【问题标题】:BigDecimal.movePointRight() hangs with very large numbersBigDecimal.movePointRight() 挂起非常大的数字
【发布时间】:2012-02-13 11:38:36
【问题描述】:

以下程序冻结,我不知道为什么。

import java.math.*;

public class BigDec {
  public static BigDecimal exp(double z) {
       // Find e^z = e^intPart * e^fracPart.
       return new BigDecimal(Math.E).pow((int)z, MathContext.DECIMAL128).
           multiply(new BigDecimal(Math.exp(z-(int)z)), MathContext.DECIMAL128);
   }

   public static void main(String[] args) {
       // This works OK:
       BigDecimal x = new BigDecimal(3E200);
       System.out.println("x=" + x);
       System.out.println("x.movePointRight(1)=" + x.movePointRight(1));

       // This does not:
       x = exp(123456789);
       System.out.println("x=" + x);
       System.out.println("x.movePointRight(1)=" + x.movePointRight(1)); //hangs
   }
}

对于目前的目的,第一种方法只是创建一个非常大的 BigDecimal。 (详细信息:它找到 e 的 z 次方,即使它太大而不能成为双精度数。我很确定这种方法是正确的,尽管 MathContexts 可能不在最佳位置。)

我知道 e^123456789 非常大,但我真的很想使用这样的数字。任何答案都将非常感激。

【问题讨论】:

    标签: java bigdecimal


    【解决方案1】:

    实际上它并没有冻结,但是在 Oracle 的 VM 中实现movePointRight 可能效率极低。与使用 movePointRightmovePointLeft 方法相比,使用 10 的幂进行乘法或除法通常要快得多。在您的情况下,使用 x.multiply(BigDecimal.TEN) 可能会更好。

    【讨论】:

    • 谢谢。这听起来很有说服力,x.multiply(BigDecimal.TEN) 工作正常。我在周末(偶然)离开了我的程序,周一早上还没有完成,所以movePointRight 不仅效率极低,而且效率低得令人难以置信。它所要做的就是将 BigDecimal 的“比例”改变 1,所以这很令人费解。
    • 我还没有检查整个实现,但在某些时候,movePointXYZ 创建了一个中间 BigInteger 实例,其顺序为 10 次方(BigDecimal 中的位数)。它创建一个带有前导“1”的字符串(实际上是一个 char[]),后跟大约 5300 万个“0”字符,并将其传递给 BigInteger 构造函数。然后 BigInteger 实现尝试将这个数字二进制编码打包成内部 int 数组中的 32 位块,这才是真正的罪魁祸首。
    猜你喜欢
    • 1970-01-01
    • 2019-12-14
    • 1970-01-01
    • 2012-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-21
    相关资源
    最近更新 更多