I\'ve wrote a naïve test-bed to measure the performance of three kinds of factorial implementation: loop based, non tail-recursive and tail-recursive.
Su
For loops are not actually quite loops; they're for comprehensions on a range. If you actually want a loop, you need to use while
. (Actually, I think the BigInt
multiplication here is heavyweight enough so it shouldn't matter. But you'll notice if you're multiplying Int
s.)
Also, you have confused yourself by using BigInt
. The bigger your BigInt
is, the slower your multiplication. So your non-tail loop counts up while your tail recursion loop counds down which means that the latter has more big numbers to multiply.
If you fix these two issues you will find that sanity is restored: loops and tail recursion are the same speed, with both regular recursion and for
slower. (Regular recursion may not be slower if the JVM optimization makes it equivalent)
(Also, the stack overflow fix is probably because the JVM starts inlining and may either make the call tail-recursive itself, or unrolls the loop far enough so that you don't overflow any longer.)
Finally, you're getting poor results with for and while because you're multiplying on the right rather than the left with the small number. It turns out that the Java's BigInt multiplies faster with the smaller number on the left.