所有整数值都完美地表示为双精度数吗?

新手上路,请多包涵

我的问题是是否所有整数值都保证具有完美的双重表示。

考虑以下打印“Same”的代码示例:

 // Example program
#include <iostream>
#include <string>

int main()
{
  int a = 3;
  int b = 4;
  double d_a(a);
  double d_b(b);

  double int_sum = a + b;
  double d_sum = d_a + d_b;

  if (double(int_sum) == d_sum)
  {
      std::cout << "Same" << std::endl;
  }
}

这对于任何架构、任何编译器、任何 ab 的值是否都保证是正确的?是否将任何整数 i 转换为 double ,总是表示为 i.0000000000000 而不是例如 i.000000000001

我尝试了其他一些数字,它总是正确的,但无法找到任何关于这是巧合还是设计的信息。

注意:这与 这个问题 不同(除了语言),因为我将两个整数相加。

原文由 Thomas 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 388
2 个回答

免责声明(由 Toby Speight 建议):尽管 IEEE 754 表示非常普遍,但允许实现使用满足语言要求的任何其他表示。


双精度数以 mantissa * 2^exponent 的形式表示,即某些位用于双精度数的非整数部分。

              bits        range                       precision
  float        32        1.5E-45   .. 3.4E38          7- 8 digits
  double       64        5.0E-324  .. 1.7E308        15-16 digits
  long double  80        1.9E-4951 .. 1.1E4932       19-20 digits

IEEE 754 双型示意图

分数中的部分也可以通过使用删除点后所有数字的指数来表示整数。

例如 2,9979 · 10^4 = 29979。

由于常见的 int 通常是 32 位,因此您可以将所有 int s 表示为 double,但对于 64 位整数,这当然不再适用。更准确地说(正如 LThode 在评论中指出的那样):IEEE 754 双精度可以保证最多 53 位(52 位有效位 + 隐式前导 1 位)。

:32 位整数是可以的,64 位整数不行。

(这对于服务器/桌面通用 CPU 环境是正确的,但其他架构的行为可能会有所不同。)

正如 Malcom McLean 所说的那样, 实际答案 是:64 位双精度数对于几乎所有可能在现实生活中计算事物的整数来说是一种足够的整数类型。


对于有经验的人,试试 这个

 #include <iostream>
#include <limits>
using namespace std;

int main() {
    double test;
    volatile int test_int;
    for(int i=0; i< std::numeric_limits<int>::max(); i++) {
        test = i;
        test_int = test;

        // compare int with int:
        if (test_int != i)
            std::cout<<"found integer i="<<i<<", test="<<test<<std::endl;
    }
    return 0;
}

成功时间:0.85 内存:15240 信号:0


问题:关于分数差异的问题。是否有可能有一个整数转换为与正确值相差一个分数的双精度数,但由于四舍五入而转换回相同的整数?

答案是否定的,因为任何来回转换为相同值的整数实际上都以双精度表示相同的整数值。对我来说,最简单的解释(ilkkachu 建议)是使用指数 2^exponent 步长必须始终是 2 的幂。因此,在最大的 52(+1 符号)位整数之外,永远不会有两个距离小于 2 的 double 值,从而解决了舍入问题。

原文由 Beginner 发布,翻译遵循 CC BY-SA 3.0 许可协议

答案是不。这只适用 int s 是 32 位的,虽然在大多数平台上都是如此,但标准不能保证。

这两个整数可以共享相同的双精度表示。

例如, 这个

#include <iostream>
int main() {
    int64_t n = 2397083434877565865;
    if (static_cast<double>(n) == static_cast<double>(n - 1)) {
        std::cout << "n and (n-1) share the same double representation\n";
    }
}

将打印

n 和 (n-1) 共享相同的双重表示

即 2397083434877565865 和 2397083434877565864 都将转换为相同的 double

请注意,我在这里使用了 int64_t 来保证 64 位整数,这取决于您的平台 - 也可能是 int 是什么。

原文由 Corristo 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题