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

时间:2017-04-27 10:51:29

标签: c++ double standards precision ieee-754

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

考虑以下代码示例打印"相同":

// 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

我尝试了其他一些数字并且它总是如此,但无法找到关于这是巧合还是设计的任何内容。

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

5 个答案:

答案 0 :(得分:70)

免责声明(由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

Schematic of IEEE 754 double type

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

E.g。 2,9979·10 ^ 4 = 29979.

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

回答:32位整数是,64位整数都没有。

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

正如Malcom McLean所说:

实用答案:对于几乎所有可能在现实生活中计算事物的整数,64位双精度数是一个足够的整数类型。

对于经验倾向,请尝试this

#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

<强> Subquestion : 关于分数差异的问题。是否有可能有一个整数转换为一个double,它正好偏离正确的值一小部分,但由于四舍五入而转换回相同的整数?

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

答案 1 :(得分:15)

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

答案 2 :(得分:11)

答案是否定的。这只适用于int为32位的情况,虽然在大多数平台上都是正确的,但标准并不保证。

两个整数可以共享相同的双重表示。

例如,this

#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

答案 3 :(得分:4)

您有两个不同的问题:

  

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

其他人已经回答了这个问题(TL; DR:这取决于intdouble的精确度。)

  

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

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

答案 4 :(得分:2)

简短的回答是&#34;可能&#34;。便携式答案是&#34;并非无处不在&#34;。

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

  • double
  • 的大小和代表
  • int
  • 的范围

对于使用IEEE-754双打的平台,如果int为53位或更小,则可能为真。对于int大于double的平台,它显然是错误的。

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