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

Tho*_*mas 57 c++ precision double standards 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

对于任何架构,任何编译器,任何值ab?保证这是真的吗?i转换为的任何整数是否double总是表示为i.0000000000000和不表示为,例如,i.000000000001

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

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

Beg*_*ner 74

免责声明(由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
Run Code Online (Sandbox Code Playgroud)

IEEE 754双类型的原理图

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

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

由于公共int通常是32位,你可以将所有ints 表示为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;
}
Run Code Online (Sandbox Code Playgroud)

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


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

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

  • @Beginner这个比较将始终返回`false`,因为整数`test_int`将在此比较中隐式转换为`double`.因此,即使`double`不能表示`int`,`int`也将被转换为相同的不精确表示,然后比较相等. (3认同)

Pet*_*ker 15

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

  • 32位整数怎么样?对于这种情况,基数论证是不确定的. (2认同)
  • @Beginner - 更加极端,缺少反常浮点类型,每个可以表示为"int8_t"值的整数值(假设类型实际存在)可以精确地表示为double.但问题比这更广泛; 它没有限定地问,如果**所有**整数值都可以完全表示为双精度,答案是"否".隐含问题的答案是,如果您需要知道哪个整数可以在双精度中准确表示,您必须知道系统中双重表示的相当详细的详细信息.这不适合初学者. (2认同)

Cor*_*sto 11

答案是不.这仅在ints为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";
    }
}    
Run Code Online (Sandbox Code Playgroud)

将打印

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

即2397083434877565865和2397083434877565864将转换为相同double.

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

  • @Rene根据平台,`int`可能是64位整数. (6认同)
  • @Rene可能有任何数量的此类平台.你不能仅仅因为你不了解平台而假设平台不存在.这个问题被标记为"标准"而不是"恰好在大多数地方工作". (2认同)
  • @Thomas - 浮点精度不会因为 into 越大而变得更差。它保持完全相同。您的整数值似乎具有更高的精度,因为您正在写入更多的非零数字,但它们的精度也没有改变。 (2认同)