【问题标题】:why is the Double.parseDouble making 9999999999999999 to 10000000000000000? [duplicate]为什么 Double.parseDouble 将 9999999999999999 变为 10000000000000000? [复制]
【发布时间】:2012-01-18 09:15:31
【问题描述】:

为什么 Double.parseDouble 将 9999999999999999 变为 10000000000000000 ? 例如:

Double d =Double.parseDouble("9999999999999999");
String b= new DecimalFormat("#.##").format(d);
System.out.println(b);

正在打印

10000000000000000

它必须显示99999999999999999999999999999999.00

非常感谢任何形式的帮助。

【问题讨论】:

  • 浮点运算 --- 自 1985 年以来计算机科学的最大谜团

标签: java double


【解决方案1】:

数字9999999999999999 刚好高于双精度浮点的精度限制。也就是说,53位的尾数是无法容纳9999999999999999的。

所以结果是它被四舍五入到最接近的双精度值——即10000000000000000

 9999999999999999 = 0x2386f26fc0ffff  // 54 significant bits needed
10000000000000000 = 0x2386f26fc10000  // 38 significant bits needed

【讨论】:

  • +1:正是这个。它需要 54 位来表示无符号的 9999999999999999,并且完全适合标准双精度的最大值是 9007199254740991。
  • @DonalFellows 不会是偶数吧?如果 9007199254740991 可以表示 9007199254740992 也必须表示。
  • @Peter:0x1fffffffffffff 是一个奇数,需要至少 53 位来表示。较大的数字需要 54 位(或指数)。猜猜这个十进制值是多少? :-)
  • 从技术上讲,您可以表示任何不超过 53 个有效位(并且不会溢出)的大整数。所以2^128 是一个整数,可以表示为double。但90071992547409919007199254740992 是最后一个连续 整数,可以用双精度表示。
  • @DonalFellows, 9007199254740991 + 1 是偶数,所以它只需要 53 位,因为可以暗示最后一位(为零)。 9007199254740991 + 2 是奇数,需要 54 位。
【解决方案2】:

double 只有 15/16 位的准确度,当您给它一个无法表示的数字时(大多数情况下,即使 0.1 也不准确),它会采用最接近的可表示数字。

如果要精确表示9999999999999999,则需要使用BigDecimal。

BigDecimal bd = new BigDecimal("9999999999999999");
System.out.println(new DecimalFormat("#.##").format(bd));

打印

9999999999999999

很少有现实世界的问题需要这种准确性,因为无论如何您都无法如此准确地测量任何东西。即每 quintillion 1 份的误差。


你可以找到最大的可表示整数

// search all the powers of 2 until  (x + 1) - x != 1
for (long l = 1; l > 0; l <<= 1) {
    double d0 = l;
    double d1 = l + 1;
    if (d1 - d0 != 1) {
        System.out.println("Cannot represent " + (l + 1) + " was " + d1);
        break;
    }
}

打印

Cannot represent 9007199254740993 was 9.007199254740992E15

最大的可表示整数是 9007199254740992,因为它需要少一位(作为偶数)

【讨论】:

  • 在考虑正常的 IEEE 双精度时,使用二进制算术比使用某种十进制近似值要有用得多。
  • 9007199254740992 = 20000000000000(十六进制)= 1000000000000000000000000000000000000000000000000000000(bin)
  • @DonalFellows 没错,这就是为什么我只考虑 2 的幂。
【解决方案3】:

9999999999999999 需要 54 位尾数才能准确表示,而 double 只有 52。因此,该数字四舍五入到最接近的数字,可以使用 52- 表示位尾数。这个号码恰好是10000000000000000

10000000000000000 需要更少位的原因是它的二进制表示以很多零结尾,而这些零可以通过增加(二进制)指数来表示。

类似问题的详细解释见Why is (long)9223372036854665200d giving me 9223372036854665216?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-06
    • 1970-01-01
    • 2013-12-17
    • 1970-01-01
    • 1970-01-01
    • 2015-11-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多