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

这个问题在这里已有答案:

  • 用双精度表示整数                                     5个答案

我的问题是,是否所有整数值都保证具有完美的双精度表示形式。

考虑下面的代码示例,显示“ 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的任何值,这是否保证是正确的? 将转换为double的整数i始终表示为i.0000000000000而不是例如i.000000000001吗?

我尝试了其他一些数字,但它始终是正确的,但无法找到有关这是巧合还是设计使然的信息。

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

Thomas asked 2019-11-15T08:24:32Z
5个解决方案
71 votes

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


双精度数以int的形式表示,即某些位用于双精度数的非整数部分。

             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

Schematic of IEEE 754 double type

小数部分也可以通过使用指数来表示整数,该指数去除点后的所有数字。

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

由于常见的int通常为32位,因此您可以将所有int都表示为双精度,但是对于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建议)是,使用指数2615040909821608608960,步长必须始终为2的幂。 因此,除了最大的52(+1号)位整数之外,再也没有两个距离小于2的double值,这解决了舍入问题。

Beginner answered 2019-11-15T08:26:11Z
15 votes

否。假设您有64位整数类型和64位浮点类型(对于double是典型的)。 该整数类型有2 ^ 64个可能的值,并且该浮点类型有2 ^ 64个可能的值。 但是其中一些浮点值(实际上,大多数浮点值)不表示整数值,因此浮点类型表示的整数值比整数类型少。

Pete Becker answered 2019-11-15T08:26:41Z
11 votes

答案是不。 仅当int64_ts是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和23970834348775658658都将转换为相同的int64_t

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

Corristo answered 2019-11-15T08:27:36Z
4 votes

您有2个不同的问题:

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

这已经被其他人回答(TL; DR:这取决于intint的精度)。

考虑以下打印“ Same”的代码示例:[...]是否保证对任何体系结构,任何编译器,a和b的任何值都是正确的?

您的代码将两个ints相加,然后将结果转换为两倍。 ints的总和将溢出某些值,但是两个单独转换的doubles的总和将不会(通常)。 对于这些值,结果将有所不同。

Pablo H answered 2019-11-15T08:28:31Z
2 votes

简短的答案是“可能”。 可移植的答案是“并非无处不在”。

这确实取决于您的平台,尤其是取决于

  • std::numeric_limits的大小和表示
  • std::numeric_limits的范围

对于使用IEEE-754 double的平台,如果std::numeric_limits为53位或更小,则可能为true。 对于std::nextafterdouble大的平台,这显然是错误的。

您可能希望能够使用std::numeric_limitsstd::nextafter调查运行时主机上的属性。

Toby Speight answered 2019-11-15T08:29:34Z
translate from https://stackoverflow.com:/questions/43655668/are-all-integer-values-perfectly-represented-as-doubles