While toying with a tail recursion example I noticed a small discrepancy between the results of a normal recursive call and a tail recursive call:
scala> def fact(n: Int): Double = if(n < 1) 1 else n * fact(n - 1)
fact: (n: Int)Double
scala> fact(30)
res31: Double = 2.6525285981219103E32
scala> @tailrec def fact(n: Int, acc: Double = 1): Double = if(n < 1) acc else fact(n - 1, n * acc)
fact: (n: Int, acc: Double)Double
scala> fact(30)
res32: Double = 2.652528598121911E32
Just out of curiosity, can someone please explain to me why or where the rounding is happening. My guess is that because the Scala compiler translates the tail recursive version to a loop, the acc
parameter is assigned at each iteration of the loop, and that the small rounding error slips in there.
The result is different because the two versions do the multiplications in different order, thus leading to different rounding.
The normal recursive call leads to an expression n*([n-1]*([n-2]*(...)))
, because you first compute the value of fact(n-1) and then multiply it with n, whereas the tail recursive one leads to ((n*[n-1])*[n-2])*...
because you first multiply by n and then iterate on to n-1.
Try rewriting one of the versions so that it iterates the other way and you should, theoretically, get the same answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With