如何在 Java 中对 BigDecimal 进行小数幂运算?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3579779/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to do a fractional power on BigDecimal in Java?
提问by Eugene Marin
In my little project, I need to do something like Math.pow(7777.66, 5555.44)
only with VERY big numbers. I came across a few solutions:
在我的小项目中,我只需要Math.pow(7777.66, 5555.44)
处理非常大的数字。我遇到了几个解决方案:
- Use
double
- but the numbers are too big - Use
BigDecimal.pow
but no support for fractional - Use the
X^(A+B)=X^A*X^B
formula (B
is the remainder of the second num), but again no support for bigX
or bigA
because I still convert to double - Use some kind of Taylor series algorithm or something like that - I'm not very good at math so this one is my last option if I don't find any solutions (some libraries or formula for
(A+B)^(C+D)
).
- 使用
double
- 但数字太大 - 使用
BigDecimal.pow
但不支持小数 - 使用
X^(A+B)=X^A*X^B
公式(B
是第二个 num 的余数),但同样不支持 bigX
或 bigA
因为我仍然转换为 double - 使用某种泰勒级数算法或类似的东西 - 我不太擅长数学,所以如果我找不到任何解决方案(一些库或公式
(A+B)^(C+D)
),这是我最后的选择。
Does anyone know of a library or an easy solution? I figured that many people deal with the same problem...
有谁知道图书馆或简单的解决方案?我想很多人都在处理同样的问题......
p.s.
I found some library called ApFloat that claims to do it approximately, but the results I got were so approximate that even 8^2
gave me 60
...
ps 我发现了一些名为 ApFloat 的库,它声称可以大致做到这一点,但我得到的结果是如此近似,甚至8^2
给了我60
......
采纳答案by Eugene Marin
The solution for arguments under 1.7976931348623157E308 (Double.MAX_VALUE) but supporting results with MILLIONS of digits:
1.7976931348623157E308(Double.MAX_VALUE)下参数的解决方案,但支持数百万位数的结果:
Since double supports numbers up to MAX_VALUE (for example, 100! in double looks like this: 9.332621544394415E157), there is no problem to use BigDecimal.doubleValue(). But you shouldn't just do Math.pow(double, double) because if the result is bigger than MAX_VALUE you will just get infinity. SO: use the formula X^(A+B)=X^A*X^B to separate the calculation to TWO powers, the big, using BigDecimal.pow, and the small (remainder of the 2nd argument), using Math.pow, then multiply. X will be copied to DOUBLE - make sure it's not bigger than MAX_VALUE, A will be INT (maximum 2147483647 but the BigDecimal.pow doesn't support integers more than a billion anyway), and B will be double, always less than 1. This way you can do the following (ignore my private constants etc):
由于 double 支持最大为 MAX_VALUE 的数字(例如,double 中的 100! 看起来像这样:9.332621544394415E157),因此使用 BigDecimal.doubleValue() 没有问题。但是你不应该只做 Math.pow(double, double) 因为如果结果大于 MAX_VALUE 你只会得到无穷大。SO:使用公式 X^(A+B)=X^A*X^B 将计算分为两个幂,大的,使用 BigDecimal.pow,小(第二个参数的余数),使用 Math。 pow,然后乘以。X 将被复制到 DOUBLE - 确保它不大于 MAX_VALUE,A 将是 INT(最大值为 2147483647,但 BigDecimal.pow 无论如何不支持超过 10 亿的整数),并且 B 将是双倍,始终小于 1。通过这种方式,您可以执行以下操作(忽略我的私有常量等):
int signOf2 = n2.signum();
try {
// Perform X^(A+B)=X^A*X^B (B = remainder)
double dn1 = n1.doubleValue();
// Compare the same row of digits according to context
if (!CalculatorUtils.isEqual(n1, dn1))
throw new Exception(); // Cannot convert n1 to double
n2 = n2.multiply(new BigDecimal(signOf2)); // n2 is now positive
BigDecimal remainderOf2 = n2.remainder(BigDecimal.ONE);
BigDecimal n2IntPart = n2.subtract(remainderOf2);
// Calculate big part of the power using context -
// bigger range and performance but lower accuracy
BigDecimal intPow = n1.pow(n2IntPart.intValueExact(),
CalculatorConstants.DEFAULT_CONTEXT);
BigDecimal doublePow =
new BigDecimal(Math.pow(dn1, remainderOf2.doubleValue()));
result = intPow.multiply(doublePow);
} catch (Exception e) {
if (e instanceof CalculatorException)
throw (CalculatorException) e;
throw new CalculatorException(
CalculatorConstants.Errors.UNSUPPORTED_NUMBER_ +
"power!");
}
// Fix negative power
if (signOf2 == -1)
result = BigDecimal.ONE.divide(result, CalculatorConstants.BIG_SCALE,
RoundingMode.HALF_UP);
Results examples:
结果示例:
50!^10! = 12.50911317862076252364259*10^233996181
50!^0.06 = 7395.788659356498101260513
回答by Matthew Flynn
回答by Ben Holland
The big-mathlibrary released under MIT license has a simple static helper BigDecimalMath.log(BigDecimal, MathContext)
for log and many other functions not included with BigDecimal. Very simple to use and has lots of benchmarking data to compare performance.
在 MIT 许可下发布的big-math库有一个简单的静态帮助器,BigDecimalMath.log(BigDecimal, MathContext)
用于日志和 BigDecimal 未包含的许多其他功能。使用起来非常简单,并有大量的基准数据来比较性能。