当前位置: 首页 > 知识库问答 >
问题:

为什么java.math.BigDecimal.value的(双)使用新的BigDecimal(字符串),而不是新的BigDecimal(双)

阎安邦
2023-03-14

这是代码:

    public static void main(String[] args) {
    final double d1 = 811.440000;
    final double d2 = 425.530000;
    final double d3 = 384.270000;

    for (double d : Arrays.asList(d1, d2, d3)) {
        final String dstr = String.format("%f", d);
        BigDecimal bg1 =  BigDecimal.valueOf(d).setScale(2, BigDecimal.ROUND_DOWN);
        BigDecimal bg2 = (new BigDecimal(dstr)).setScale(2, BigDecimal.ROUND_DOWN);
        BigDecimal bg3 =    (new BigDecimal(d)).setScale(2, BigDecimal.ROUND_DOWN);
        System.out.printf("[%s : %f] {%f, %f} %f\n", dstr, d,     bg1, bg2,   bg3);
    }
}

以下是输出:

[811.440000 : 811.440000] {811.440000, 811.440000} 811.440000
[425.530000 : 425.530000] {425.530000, 425.530000} 425.520000
[384.270000 : 384.270000] {384.270000, 384.270000} 384.260000

为什么我们不更改valueOf(double)方法或BigDecimal类的BigDecimal(double)构造函数,以获得一致的结果?

共有2个答案

宇文德明
2023-03-14

稍微更改代码:

    public static void main(String[] args) {
    final double d1 = (new Double("811.44")).doubleValue();
    final double d2 = (new Double("425.53")).doubleValue();
    final double d3 = (new Double("384.27")).doubleValue();
    final double DD = (new Double("999999999999999.95")).doubleValue();  // 15 9s before decimal point

    for (double d : Arrays.asList(d1, d2, d3)) {
        final String dstr = String.valueOf(d);
        BigDecimal bg1 =  BigDecimal.valueOf(d);
        BigDecimal bg2 = (new BigDecimal(dstr));
        BigDecimal bg3 =    (new BigDecimal(d));
        System.out.printf("* [%s : %s : %.15f] {%.15f, %.15f, %.15f}\n", dstr, d, d, bg1, bg2, bg3);
        System.out.printf("  [%s : %s : %.15f] {%.15f, %.15f, %.15f}\n", dstr, d, d, bg1.doubleValue(), bg2.doubleValue(), bg3.doubleValue());
    }
}

这就是结果:

1000000000000000.000000000000000
x [811.44 : 811.44 : 811.440000000000000] {811.440000000000000, 811.440000000000000, 811.440000000000055}
  [811.44 : 811.44 : 811.440000000000000] {811.440000000000000, 811.440000000000000, 811.440000000000000}
x [425.53 : 425.53 : 425.530000000000000] {425.530000000000000, 425.530000000000000, 425.529999999999973}
  [425.53 : 425.53 : 425.530000000000000] {425.530000000000000, 425.530000000000000, 425.530000000000000}
x [384.27 : 384.27 : 384.270000000000000] {384.270000000000000, 384.270000000000000, 384.269999999999982}
  [384.27 : 384.27 : 384.270000000000000] {384.270000000000000, 384.270000000000000, 384.270000000000000}

从输出来看,精度损失似乎是由BigDecimal(double)构造函数引起的。

步博艺
2023-03-14

这里的问题不是新的BigDecimal(double)或新的BigDecimal(String)工作错误。

这里的问题是,double不精确。它们以一种不能代表所有数字的方式存储位。

以下是有关该主题的一些链接:

  • 这个简单的“双精度”计算有什么错
  • https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems
  • 在Java中使用double保持精度
 类似资料:
  • 问题内容: 我有一个BigDecimal对象,我想将其转换为字符串。问题是我的值得到了分数,我得到了一个很大的数字(长度),例如,我只需要字符串中的原始数字即可: 输出为: 我需要把输出准确地放在字符串中 问题答案: 要获得准确的结果,您需要使用String构造函数或(它基于double的规范表示构造一个BigDecimal): 问题在于参数是a ,并且恰巧双精度不能正确表示。因此,“转换”为最接

  • 我可以理解,在大小数中,2.0并不等于2.00,因为2.00实际上使用了更高精度的数字。我很难理解为什么不被认为等于,因为这两个数字实际上使用相同数量的精确数字。依我看,它们只是完全相同数字的不同表示。 我知道,我可以使用和而不是,我只是对这背后的推理感兴趣。有人能帮我理解吗?

  • 据我所知,例如,整数缓存了值为-128到127的实例。这是JLS的要求。JLS 5.1.7: 如果要装箱的值p是对布尔、字节、字符、短、int或长类型的常量表达式(§15.29)求值的结果,且结果为true、false、包含“\u0000”到“\u007f”范围内的字符,或包含-128到127范围内的整数,则a和b是p的任意两个装箱转换的结果。a==b的情况总是这样。 所以我能理解使用整数的意义。

  • 问题内容: 我正在尝试从字符串中读取一些BigDecimal值。假设我有以下字符串:“ 1,000,000,000.999999999999999”,我想从中获取BigDecimal。怎么做呢? 首先,我不喜欢使用字符串替换(替换逗号等)的解决方案。我认为应该有一些精巧的格式化程序为我完成这项工作。 我发现了DecimalFormatter类,但是它通过两次操作-损失了大量精度。 那么,我该怎么办

  • 问题内容: 在.NET Framework 的参考中,使用type 声明请求类型。 在RFC 2616 中,声明了所有HTTP请求方法(例如POST,GET,PUT,DELETE …)。 .NET 和类中也存在类似的行为。 Java在方法上有类似的方法。 这些语言设计者为什么不考虑为这些HTTP方法实现枚举? 你有好主意吗? 问题答案: RFC 2616 链接的第一句话(添加了重点): HTTP

  • 问题内容: 我有这个字符串:10,692,467,440,017.120(是一个数字)。 我想将其解析为BigDecimal。问题是我没有尝试过DecimalFormat和NumbeFormat。有什么帮助吗? 问题答案: 试试这个 如果要构建具有I18N支持的应用程序,则应使用 还请记住,它可能会引发a,因此您需要处理它(使用try / catch)或引发它,然后让程序的另一部分处理它