NumberFormatException:无限或NaN

时间:2013-08-03 01:47:19

标签: java fibonacci numberformatexception

我有一个方法,它取n并返回第n个Fibonacci数。在方法实现中,我使用BigDecimal来获取第n个Fibonacci数,然后我使用方法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();
}

4 个答案:

答案 0 :(得分:5)

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

来自公式:enter image description here

<强>更新 上面的方法是不正确的,因为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<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。

答案 1 :(得分:1)

你的问题在这里:

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

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

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

答案 2 :(得分:1)

这不是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很难进行计算......因为对已接受答案的评论显示了!

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

答案 3 :(得分:0)

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

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