我有一个方法,需要n并返回第n个斐波那契数。在方法实现内部,我使用BigDecimal
来获取第n个斐波那契数,然后使用toBigInteger()
方法来将数字作为BigInteger
对象来获取,这肯定是因为我正在应用程序中处理大量数字。
在我将 1475 作为参数传递给我之前,我一直得到正确的结果。在这种情况下,我得到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)
太大(无穷大),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(...)
非常耗时,在我的计算机上花费了30秒,n = 200。我认为使用缓存的递归方法速度更快:
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<Integer, BigInteger> cache = new HashMap<Integer, BigInteger>();
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。
关于java - NumberFormatException:无限或NaN,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18028454/