2016-12-24 62 views
1

我想用BigDecimal.pow(int i)具有很大的基数和指数,但是我得到一个ArithmeticException: Underflow错误。BigDecimal可能的解决方案下溢错误

就干脆把它的代码是:

BigDecimal base = BigDecimal.valueOf(2147483645.4141948); 
BigDecimal product = base.pow(987654321); 

System.out.println("product = " + product.toPlainString()); 

是的,这是一个项目欧拉问题。不过,我知道我的号码是正确的。这不是一个数学问题,它纯粹是我不明白为什么BigDecimal.pow(int i)给我一个ArithmeticException: Underflow

我知道BigDecimalscale is a 32-bit int,但有没有什么办法可以绕过这个并计算出如此大的值?如果有帮助,我打算在地板上铺设产品,并将其修改为100000000,因为我只需要最后8位数字。如果还有其他的方法可以用数学方法来完成,我想要一个提示。

堆栈跟踪:

Exception in thread "main" java.lang.ArithmeticException: Underflow 
    at java.math.BigDecimal.checkScale(BigDecimal.java:3841) 
    at java.math.BigDecimal.pow(BigDecimal.java:2013) 
    at test.main(test.java:10) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) 

Process finished with exit code 1 

感谢。

+3

' BigDecimal.valueOf(2147483645.4141948)' - 不!切勿从浮点文字构造BigDecimal;只要这样做,你就已经招致了舍入误差。从字符串文字构造它:'new BigDecimal(“2147483645.4141948”)'。 – user2357112

+0

@ user2357112'BigDecimal.valueOf()'把'long l'作为它的参数,而不是字符串。 – kkmonlee

+0

哎呦,修正了。你需要构造函数,而不是valueOf。 – user2357112

回答

1

答案一个十进制数字,小数位以“11234048”(最后8位小数)结尾的小数位数为6913580247。你有你的基地7个小数,和987654321 * 7等于6913580247.

我的问题是这样的数字不能在BigDecimal表示,因为它需要的6913580247规模,其溢出,BigDecimal用于其规模整数。我不知道你想用你的号码代替哪种格式。以下代码将结果打印为

Result is 1.1234048e-6913580240 

也就是说,就像科学记数法一样,只有指数超出了科学记数法的正常范围。对于模亿我使用:

public static final BigDecimal moduloBase = new BigDecimal(10).pow(8); // 8 digits 

现在我做:

long noOfDecimals = 987654321L * 7L; 

    BigDecimal bd = new BigDecimal("54141948"); // last 8 digits of base 
    bd = bd.pow(379721); 
    bd = bd.remainder(moduloBase); 
    bd = bd.pow(2601); 
    bd = bd.remainder(moduloBase); 

    double result = bd.doubleValue()/10_000_000.0; // print with 7 decimals 
    System.out.println("Result is " + result + "e" + (-(noOfDecimals - 7))); 

我使用从安东多夫任科的答案的伎俩,事实上,987654321是2601 * 379721.计算需要一些4秒,在我的电脑上,这可能会有很大的不同。

期待您的后续问题。

编辑:计算的中心部分可以用简单的代码使用BigInteger代替BigDecimal更快的完成都和:(它打印11234048,因为我们现在知道它应该)

BigInteger bi = new BigInteger("54141948"); 
    bi = bi.modPow(new BigInteger("987654321"), new BigInteger("100000000")); 
    System.out.println("As BigInteger: " + bi); 

1

计算可以在几个部分被打破,例如:

BigDecimal base = BigDecimal.valueOf(2147483645.4141948); 
base = base.setScale(20, BigDecimal.ROUND_FLOOR); 
// 109739369 = 6455257 * 17 
base = base.pow(17).setScale(20, BigDecimal.ROUND_FLOOR); 
base = base.pow(6455257); 

ArithmeticException被抛出,因为scaleValue * powValue是外[Integer.MIN_VALUE; Integer.MAX_VALUE]段。请注意,规模,重置应用pow需要后,因为BigDecimal规模重新计算每次pow被调用,等于oldScaleValue * powValue

而且,我认为,这让POW值会花很多时间

相关问题