【问题标题】:Double value change during assignment赋值过程中的双倍值变化
【发布时间】:2016-08-26 04:40:22
【问题描述】:

我知道double 存在一些精度问题,它可以在转换为integer 期间截断值。

在我的例子中,我分配了一个double 690000000000123455,它在分配期间更改为 690000000000123392

为什么数字变化如此之大?毕竟没有分配它的小数部分。这似乎不是精度问题,因为值不会改变 1 而是 63。

【问题讨论】:

  • 嗨。您应该在此处发布您的代码,因为它可以帮助其他人诊断问题。

标签: c++


【解决方案1】:

大概您将 690000000000123455 存储为 64 位整数并将其分配给双精度数。

double d = 690000000000123455;

可以在此处检查最接近 690000000000123455 的可表示双精度值:http://pages.cs.wisc.edu/~rkennedy/exact-float?number=690000000000123455 并且可以看到是 690000000000123392。

换句话说,一切都在意料之中。您的数字不能完全表示为双精度值,因此选择最接近的可表示值。

有关浮点数据类型的更多讨论,请参阅:Is floating point math broken?

【讨论】:

    【解决方案2】:

    IEEE-754 双精度浮点数大约有 53 bits of precision,相当于大约 16 个十进制数字(给或取)。您会注意到这就是您的两个数字开始分歧的地方。

    【讨论】:

      【解决方案3】:

      double 存储大小为 8 字节。取值范围从 2.3E-308 到 1.7E+308。它的精度高达小数点后 15 位。但是您的号码包含 18 位数字。就是这个原因。

      您可以使用long double,因为它的精度高达小数点后 19 位。

      【讨论】:

      • @DavidHeffernan 好吧,在 MSVC 和一些 Windows 编译器中是的......还有其他的吗?
      • @M.M 平台比编译器更重要。 x87 具有 80 位扩展类型,通常映射为 long double。 x64 为浮点提供 sse 单元,没有大于 64 位的类型。我相信ARM也是一样的。在这些平台上,long double 通常与 double 相同。
      • @DavidHeffernan sizeof(1.0L) 在 x86_64 gcc for windows 中给出 16
      • @M.M 这可能是编译器决定在 x87 单元上使用 80 位类型。 stackoverflow.com/questions/15176290/… 预计性能会有些蹩脚。并且明白 16 个字节中有 6 个是填充。所以我猜编译器也很重要!
      【解决方案4】:

      其他答案已经很完整了,但是我想推荐一个我觉得对理解浮点数如何工作很有帮助的网站:IEEE 754 Converter(这里只有 32 位浮点数,但交互性仍然很好)。

      我们可以看到,690000000000123455 介于2^592^60 之间,对于双精度,尾数的最高精度是2^-52,这意味着给定数字的精度步长是2^7=128。您提供的错误 63,实际上在范围内。

      作为一个附带建议,最好使用long 来存储大整数,因为它将保持精度并且不会溢出(在您的情况下)。

      【讨论】:

      • uint64_t 在这种特殊情况下会更好。 long 可能是 32 位
      猜你喜欢
      • 2013-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-14
      • 1970-01-01
      • 2023-02-01
      相关资源
      最近更新 更多