Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there a rounding difference between my normal recursion and tail recursion example?

Tags:

scala

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.

like image 748
Jack Avatar asked Aug 06 '12 13:08

Jack


1 Answers

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.

like image 89
Jan Avatar answered Sep 23 '22 20:09

Jan