我正在尝试使用具有很大的基础和指数的BigDecimal.pow(int i)
,但是我遇到了ArithmeticException: Underflow
错误。
简单地说,代码为:
BigDecimal base = BigDecimal.valueOf(2147483645.4141948);
BigDecimal product = base.pow(987654321);
System.out.println("product = " + product.toPlainString());
是的,这是一个项目欧拉问题。但是我知道我的数字是正确的。这不是数学问题,纯粹是我不明白为什么BigDecimal.pow(int i)
给我一个ArithmeticException: Underflow
。
我知道BigDecimal
的scale
是32位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
谢谢。
答案是十进制数字,其中6913580247小数为" 11234048"(最后8个小数)。您的基地中有7个小数,而987654321 * 7等于6913580247。
我的问题是该数字无法在BigDecimal
中表示,因为它需要6913580247的比例,这溢出了BigDecimal
用于其比例的整数。我不知道您想要哪种格式。以下代码将结果打印为
Result is 1.1234048e-6913580240
即,就像科学符号一样,只有一个指数超出了科学符号的正常范围。对于Modulo 100000000,我正在使用:
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)));
我正在使用Anton Dovzhenko的答案中的技巧,而987654321是2601 *379721。计算在我的计算机上需要大约4秒钟,这可能会有很大的不同。
期待您的后续问题。
编辑:计算的中心部分可以使用更简单的代码和使用BigInteger
而不是BigDecimal
:
BigInteger bi = new BigInteger("54141948");
bi = bi.modPow(new BigInteger("987654321"), new BigInteger("100000000"));
System.out.println("As BigInteger: " + bi);
(我们现在知道它应该打印11234048
。)
计算可以分为多个部分,例如:
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
后的比例重置是必要的,因为每次调用pow
时BigDecimal
比例都会重新计算,并且等于oldScaleValue * powValue
我认为,获得POW值将花费大量时间