I have a method that takes n and returns nth Fibonacci number. Inside the method implementation I use BigDecimal
to get the nth Fibonacci number then I use method toBigInteger()
to get the number as a BigInteger
object and that's surely because I am working with huge numbers in my application.
I keep getting correct results until I pass 1475 as an argument for my method. I get NumberFormatException: Infinite or NaN
in this case without any clear reason for me.
Could you please explain me why am I getting this exception?
Here's my method:
BigInteger getFib(int n){
double phi = (1 + Math.sqrt(5))/2;
double squareRoot = (Math.sqrt(5)) + (1/2);
BigDecimal bd = new BigDecimal(Math.floor(Math.pow(phi, n)/(squareRoot)));
return bd.toBigInteger();
}
It's not a good idea to create
BigDecimal
with float or double because its again limit to the range of them you must create a BigDecimal at first and do some operation with its functions like:This is not cause of the INF's / NaN's but it is definitely wrong. This ...
... is equivalent to this ...
... because
(1/2)
is an integer division, returning an integer value; i.e. zero.In fact, I think the most likely explanation for the INF / NaN is that "phi1475" is too large to be represented as a
double
. So thepow
method is returningINF
... which is the way that "too large" is represented as a floating number in Java.If you want to compute Fibonacci numbers this way, you need to use a representation that is capable of representing the really large numbers involved ... and represent them with sufficient accuracy. The Java
double
type cannot do this. And indeed, it is hard to do the computation usingBigDecimal
... as the comments on the accepted answer demonstrate!I'd recommend using the recurrence relation. It is going to be much simpler ... and probably more efficient as well.
Your problem is here:
the result of
Math.floor(Math.pow(phi, n)/(squareRoot))
is giving you either infinite or NaN.According to the BigDecimal javadoc that constructor (
BigDecimal(double)
) could throw aNumberFormatException
if you use a double with value infinite or NaNYour
Math.pow(phi, n)
is too big(Infinity),double is unable to store it,use BigDecimal instead.How about the flowing:
from the formula:
UPDATE: the above way is incorrect,because Math.sqrt(5) does not has enough precision as the comment said. I've tried to culculate sqrt(5) with more precision using Netown's method,and found out that
x1.pow(n).subtract(x2.pow(n)).divide(...)
is very time-consuming,it spended about 30 seconds for n = 200 in my computer.I think the recursive way with a cache is mush faster:
It spend 7 ms in my computer for n = 2000.