IEEE 754 添加两个 32 位浮点数(-1 和 2^(-50) )

IEEE 754 Addition of two 32-bit floating point numbers (-1 and 2^(-50) )

考虑以下 C++ 代码:

#include <iostream>
#include <cmath>

using namespace std;

int main()
{
    cout.precision(1000000000);
    
    float a,b,c;
    
    a = 1;
    b = -1;
    c = pow(2, -50);
    
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    cout << "c = " << c << endl;
    
    float ab = a + b;
    float bc = b + c;
    float abc = ab + c;
    float bca = bc + a;
    
    cout << "a + b = " << ab << endl;
    cout << "b + c = " << bc << endl;
    cout << "(a + b) + c = " << abc << endl;
    cout << "(b + c) + a = " << bca << endl;

    return 0;
}

产生输出:

a = 1
b = -1
c = 8.8817841970012523233890533447265625e-16
a + b = 0
b + c = -1
(a + b) + c = 8.8817841970012523233890533447265625e-16
(b + c) + a = 0

为什么 b + c = -1?

我不明白 IEEE 754 标准的这种影响。

据我了解,指数的范围是 -126 到 127。(偏置指数为 8 位,偏置为 127。)

所以 2^(-50) 可以毫无问题地表示为 1 或 -1。如果我正确理解标准,它们都不是次正规(非正规化)数字。

但为什么-1 + 2^(-50)的加法结果是-1,从而忽略了较小的数字?

在此先感谢您的帮助!

您正在使用 float,它(至少)是单精度的。请改用 double

并且 -1+9e-16-1 的单精度舍入范围内。

IEEE 754 标准指定 1 个符号位、7 个指数位和 24 个尾数位。执行加法时,每个数字的尾数都会被归一化,因此 2^-50 是 1 相对于 1 右移 50 位。这导致它落在用于结果的 24 位尾数之外。你应该尝试用 2^-25 重复你的实验来证明这一点。