【问题标题】:Addition of very small Double values (Java) [duplicate]添加非常小的 Double 值(Java)[重复]
【发布时间】:2017-09-18 10:02:09
【问题描述】:

我想知道,为什么我简单地添加一些双精度值会在 Java 中导致以下结果:

double a = 1 + 1E-10; // 1.0000000001 (as expected)
double b = 1 + 1E-15; // 1.000000000000001 (as expected)
double c = 1 + 1E-20; // 1.0 (why?)

我认为我至少可以添加一个 Double.MIN_VALUE 的值,它似乎是 4.9E-324。

我在这里做错了什么?

【问题讨论】:

  • “我在这里做错了什么?” - 你忘记了任何浮点数表示的精度问题。
  • 技术性更强一点:在IEEE 754 中,一个有 11 位指数和 53 位尾数。指数定义了数字的大小顺序,而尾数定义了数值。例如,在2.63 x 10^3 中,2.63 是数值,而3 是幅度。如果您添加两个幅度明显不同的值,您可能会遇到问题。精度,这是你观察到的。一般来说,floats 和 doubles 工作得很好,当(大多数)组件的数量级大致相同时。
  • 谢谢@Turing85,但我还是不明白,为什么我可以用Double.MIN_VALUE描述一个很小的值,却不能按预期使用。 :P 仅仅是因为另一个值(在这种情况下为 1)的大小有很大不同吗?
  • @Thomas 是的。 Double.MIN_VALUE2^-1074,而 12^0
  • @Thomas 如果您知道如何将基数为 10 的表示形式转换为二进制,那么请尝试将 0.3 写入二进制。你会注意到这个表示有一个句点(就像以 10 为底的 1/3),因此你会有一个精度错误。二进制中的0.1 也是如此。在计算0.3 + 0.1 时,舍入误差会被抵消,您会得到预期的结果。在计算0.3 - 0.1 时,错误不会被抵消,您会得到意想不到的结果。然而,这个结果在给定的算术中是正确的。

标签: java double min addition


【解决方案1】:

正如@Turing85 指出的那样,double 有 11 位指数和 53 位尾数。

我们在这里计算的是 1.0 + 1E-20。为了表示这个数字(比 1.0 更精确),我们需要至少 21 个十进制数字的精度或 71 位。这比 double 在尾数中提供的精度更高。

因此,与 1.0 + 1E-20 最接近的可表示 double 数是 .... 1.0。这就是你得到的结果。

欢迎来到浮点运算的神秘世界。

【讨论】:

    【解决方案2】:

    你在这里没有做错任何事。小数精度的概念就在眼前。浮点数总是有可能出错。 而常见的错误值表示为:

    - 1/2E-n <= error <=  1/2E-n
    

    其中 n 是您定义的小数位数。

    更多关于浮点错误的信息可以在here找到。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 2020-08-21
      • 2011-11-16
      • 2019-08-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多