【问题标题】:format not printing all double digits even when precision exceeds available digits即使精度超过可用数字,格式也不打印所有两位数
【发布时间】:2017-11-08 18:12:37
【问题描述】:

我无法理解这一点。

即使给定足够的精度字段,JDK 的数字格式化例程似乎也无法打印两位数。

特别是,我不明白为什么下面程序的第二个输出行是:

b.doubleValue() => 34981.29000000000000000000000000000000000000000000000000

我认为打印的值应该是34981.29000000000087311491370201110839843750000000000000

你能帮我理解为什么会这样吗:

PrecisionLoser.java

import java.math.BigDecimal;

public class PrecisionLoser {
    public static void main(final String[] args) {
        final BigDecimal b = new BigDecimal("34981.29");
        System.out.printf("b                => %.50f%n", b);
        System.out.printf("b.doubleValue()  => %.50f%n", b.doubleValue());
        System.out.printf("b.floatValue()   => %.50f%n", b.floatValue());
        System.out.printf("Double.MIN_VALUE =>     %.50f%n", Double.MIN_VALUE);
        System.out.println("-");
        final double d = 34981.2900000000008731149137020111083984375;
        System.out.printf("d                               => %.50f%n", d);
        System.out.printf("new BigDecimal(d)               => %.50f%n", new BigDecimal(d));
        System.out.printf("new BigDecimal(b.doubleValue()) => %.50f%n", new BigDecimal(b.doubleValue()));
        System.out.printf("d == b.doubleValue()            => %b%n", d == b.doubleValue());
        final double e = 34981.29;
        System.out.printf("d == e                          => %b%n", d == e);
        System.out.println("-");
        System.out.printf("Double.doubleToLongBits(b.doubleValue()) => 0x%16x%n", Double.doubleToLongBits(b.doubleValue()));
        System.out.printf("Double.doubleToLongBits(d)               => 0x%16x%n", Double.doubleToLongBits(d));
        System.out.printf("Double.doubleToLongBits(e)               => 0x%16x%n", Double.doubleToLongBits(e));
    }
}

输出

$ javac PrecisionLoser.java
$ java PrecisionLoser
b                => 34981.29000000000000000000000000000000000000000000000000
b.doubleValue()  => 34981.29000000000000000000000000000000000000000000000000
b.floatValue()   => 34981.28906250000000000000000000000000000000000000000000
Double.MIN_VALUE =>     0.00000000000000000000000000000000000000000000000000
-
d                               => 34981.29000000000000000000000000000000000000000000000000
new BigDecimal(d)               => 34981.29000000000087311491370201110839843750000000000000
new BigDecimal(b.doubleValue()) => 34981.29000000000087311491370201110839843750000000000000
d == b.doubleValue()            => true
d == e                          => true
-
Double.doubleToLongBits(b.doubleValue()) => 0x40e114a947ae147b
Double.doubleToLongBits(d)               => 0x40e114a947ae147b
Double.doubleToLongBits(e)               => 0x40e114a947ae147b

【问题讨论】:

    标签: java double precision number-formatting bigdecimal


    【解决方案1】:

    用调试器看转换过程,我认为发生的情况是double首先转换为字符串,忽略了精度。然后,调整字符串以匹配指定的精度(最后用 0 填充,或用舍入截断 - 请参阅 sun.misc.FormattedFloatingDecimal 的 applyPrecision)。

    而且,如果重新解析,原始转换似乎使用了(最小?)十进制数字,这将产生原始双精度值。

    【讨论】:

    • 感谢您解决这个问题。你知道如何打印真实的数字吗?
    • 转换为 BigDecimal? :)
    • 更严重的是,我不清楚您为什么要这样做?在 double 的上下文中,34981.29 和 34981.2900000000008731149137020111083984375 是完全相同数字的十进制表示形式。
    • “产生原始值的最小十进制位数”称为往返格式。一些语言会这样做,包括 Java。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多