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