NumberFormatException:无限或NaN

我有一个方法,取n并返回第n个斐波纳契数。 在方法实现中我使用BigDecimal来获取第n个Fibonacci数,然后我使用方法toBigInteger()来获取作为BigInteger对象的数字,这肯定是因为我在我的应用程序中处理大量数字。

我一直得到正确的结果,直到我通过1475作为我的方法的参数。 我得到NumberFormatException: Infinite or NaN在这种情况下NumberFormatException: Infinite or NaN没有任何明确的理由。

你能解释一下我为什么会得到这个例外吗?

这是我的方法:

 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(); } 

你的Math.pow(phi, n)太大(Infinity),double无法存储它,而是使用BigDecimal。

流动怎么样:

 static BigInteger getFib(int n) { BigDecimal x1 = new BigDecimal((1 + Math.sqrt(5)) / 2); BigDecimal x2 = new BigDecimal((1 - Math.sqrt(5)) / 2); return x1.pow(n).subtract(x2.pow(n)) .divide(new BigDecimal(Math.sqrt(5))).toBigInteger(); } 

从公式: 在此处输入图像描述

更新:上面的方法是不正确的,因为Math.sqrt(5)没有足够的精度,如评论所说。 我试图使用Netown的方法更精确地计算sqrt(5),并发现x1.pow(n).subtract(x2.pow(n)).divide(...)非常耗时,我的电脑在n = 200时大约30秒。

我认为缓存的递归方式更快:

  public static void main(String[] args) { long start = System.nanoTime(); System.out.println(fib(2000)); long end = System.nanoTime(); System.out.println("elapsed:"+ (TimeUnit.NANOSECONDS.toMillis(end - start)) + " ms"); } private static Map cache = new HashMap(); public static BigInteger fib(int n) { BigInteger bi = cache.get(n); if (bi != null) { return bi; } if (n <= 1) { return BigInteger.valueOf(n); } else { bi = fib(n - 1).add(fib(n - 2)); cache.put(n, bi); return bi; } } 

它在我的计算机上花费7毫秒,n = 2000。

你的问题在这里:

 BigDecimal bd = new BigDecimal(Math.floor(Math.pow(phi, n)/(squareRoot))); 

Math.floor(Math.pow(phi, n)/(squareRoot))是给你无限或NaN。

根据BigDecimal javadoc ,如果使用值为infinite或NaN的double,则构造函数( BigDecimal(double) )可能抛出NumberFormatException

这不是INF / NaN的原因,但绝对是错误的。 这个 …

 double squareRoot = (Math.sqrt(5)) + (1/2); 

……相当于……

 double squareRoot = Math.sqrt(5)); 

…因为(1/2)是整数除法,返回整数值; 即零。


事实上,我认为INF / NaN最可能的解释是“phi 1475 ”太大而不能表示为double 。 所以pow方法返回INF …这就是“太大”在Java中表示为浮点数的方式。


如果要以这种方式计算斐波那契数,则需要使用能够表示所涉及的真正大数的表示…并以足够的精度表示它们。 Java double类型不能这样做。 事实上,使用BigDecimal很难进行计算……因为对接受的答案的评论表明了!

我建议使用递归关系。 它会变得更简单……也可能更有效率。

使用float或double创建BigDecimal不是一个好主意,因为它再次限制它们的范围你必须首先创建一个BigDecimal并使用它的函数执行一些操作:

 BigDecimal a; BigDecimal b; x1.pow(b);