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