Java NumberFormatException:无限或NaN

Java NumberFormatException:无限或NaN,java,fibonacci,numberformatexception,Java,Fibonacci,Numberformatexception,我有一个方法,它取n并返回n个斐波那契数。在方法实现中,我使用BigDecimal获取第n个斐波那契数,然后使用toBigInteger()方法获取作为biginger对象的数字,这肯定是因为我在应用程序中使用的是巨大的数字 我一直得到正确的结果,直到我通过1475,作为我方法的参数。在这种情况下,我得到NumberFormatException:Infinite或NaN,没有任何明确的原因 您能解释一下为什么我会遇到这个异常吗? 以下是我的方法: BigInteger getFib(int n

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

我一直得到正确的结果,直到我通过1475,作为我方法的参数。在这种情况下,我得到
NumberFormatException:Infinite或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();
}
你的问题是:

BigDecimal bd = new BigDecimal(Math.floor(Math.pow(phi, n)/(squareRoot)));
Math.floor(Math.pow(phi,n)/(平方根))
的结果给出了无限或NaN


根据该构造函数(
BigDecimal(double)
)可以抛出
NumberFormatException
,如果使用值为无穷大或NaN的double,这不是导致INF/NaN的原因,但肯定是错误的。这个

double squareRoot = (Math.sqrt(5)) + (1/2);
。。。相当于这个

double squareRoot = Math.sqrt(5));
。。。因为
(1/2)
是一个整数除法,返回一个整数值;i、 e.零


事实上,我认为INF/NaN最有可能的解释是“phi1475”太大,无法表示为
double
。因此,
pow
方法返回
INF
。。。这就是Java中“太大”表示为浮点数的方式


如果你想用这种方法计算斐波那契数,你需要使用一种能够表示所涉及的非常大的数的表示法。。。并以足够的准确度表示它们。Java
double
类型无法执行此操作。实际上,使用
BigDecimal
进行计算是很困难的。。。正如对已接受答案的评论所表明的那样

我建议使用递归关系。这会简单得多。。。而且可能效率更高。

您的
数学。pow(φ,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(…)
非常耗时,在我的计算机中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;
    }
}
publicstaticvoidmain(字符串[]args){
长启动=System.nanoTime();
系统输出打印(fib(2000));
long end=System.nanoTime();
System.out.println(“已用时间:”+(时间单位.纳秒.toMillis(结束-开始))+“毫秒”);
}
私有静态映射缓存=新HashMap();
公共静态大整数fib(int n){
biginger bi=cache.get(n);
如果(bi!=null){
返回bi;
}

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

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

没错,就是“phi1475”给出无穷大。我实际上可以使用BigDecimal来代替它,但仍然存在一个问题。在这种情况下,BigDecimal与Math.floor的等效性是什么?尝试使用
floor
的舍入模式进行
舍入。但我认为使用递归关系可能更快、更可靠。80776376321566249506594310369598056472970340482296717528846843403451897402974064859772924316558310641200045712627734657615023748095728890842338729730058516953255187002299003343831984757057534431524942603898204091615259579526447088790366544327936444170883726483094220676247626262526548956869653以上的斐波那契数我不确定是否正确71,由于
Math.sqrt(5)的精度有限
。根据OEIS,第1475个斐波那契号码是80776376321562253452154706580907152216005883906114489495670984412334684348968491428447379890769208411123289605402905517826761242700284198062517976109316019280176024641137642233750220559475818021710376170155984070653028847748504878787878697976464253377497168581568704088625.是的……从这个公式中获得一个精确的值是非常困难的。1)大的十进制数在小数点的右边有固定的精度。2)不能使用
Math.sqrt(5)
…不够精确。令人印象深刻。我尝试了循环,但它太复杂了,然后我给了递归一个简短的例子,随着数字的增加,它现在变慢了,回到这一点,一切都很好。缓存改进了speedBigDecimal,没有接受另一个BigDecimal的pow方法。事实上,它只支持整数幂(
int
)价值观