C++ 当一个被加到一个大数字上时,浮点运算是如何工作的?

C++ 当一个被加到一个大数字上时,浮点运算是如何工作的?,c++,floating-point,C++,Floating Point,如果我们运行此代码: #include <iostream> int main () { using namespace std; float a = 2.34E+22f; float b = a+1.0f; cout<<"a="<<a<<endl; cout<<"b-a"<<b-a<<endl; return 0; } #包括 int

如果我们运行此代码:

 #include <iostream>
 int main ()
 { 
     using namespace std;
     float a = 2.34E+22f;
     float b = a+1.0f;  
     cout<<"a="<<a<<endl;
     cout<<"b-a"<<b-a<<endl;
     return 0;
 }
#包括
int main()
{ 
使用名称空间std;
浮子a=2.34E+22f;
浮球b=a+1.0f;

cout基本原理是两个数字对齐,以便小数点位于同一位置。我使用10位数字使其更易于阅读:

 a = 1.234E+10f;
 b = a+1.0f;
计算+1.0f时,需要对齐小数点:

 1.234E+10f becomes 1234000000.0
 1.0f       becomes          1.0
            + 
            =       1234000001.0
但由于它是浮动的,右侧的1超出了有效范围,因此存储的数字将是
1.234000E+10
-超出该范围的任何数字都将丢失,因为没有足够的数字

[请注意,如果您在优化编译器上执行此操作,它可能仍然会显示1.0作为差异,因为浮点单元使用64位或80位内部表示,因此如果计算是在不将中间结果存储到变量中的情况下进行的(一个体面的编译器肯定可以在这里实现这一点)对于2.34E+22f,保证不适合64位浮点,也可能不适合80位浮点。

逐步:

IEEE-754 32位二进制浮点格式:

sign 1 bit significand 23 bits exponent 8 bits 但有效位只能存储点后的23位。因此我们必须四舍五入:

1.01011100101011111110101 010000000002 • 234 ≈ 1.010111001010111111101012 • 234 1.01011100101011111110101 000000000012 • 234 ≈ 1.010111001010111111101012 • 234 但是,有效位只能在点后存储23位二进制数字。因此,我们必须四舍五入:

1.01011100101011111110101 010000000002 • 234 ≈ 1.010111001010111111101012 • 234 1.01011100101011111110101 000000000012 • 234 ≈ 1.010111001010111111101012 • 234
b
等于23399991808

三)
float c=b-a;

101011100101011111110101000000000002 - 101011100101011111110101000000000002 = 0
c
等于0。

当添加两个FP数时,它们首先转换为相同的指数。十进制:
2.34000E+22+1.00000E0=2.34000E22+0.000000 E+22
。在这一步中,1.0会因舍入而丢失


二进制浮点的工作原理基本相同,只是E+22被2^77所取代。

。程序没有“意识到”事情——它们只是没有足够的位。它是否以当前形式编译(无分号)?“但尾数只能在点后存储23位。所以我们必须截断并取整:”中间值1.0101110010101111111010100000000001*2^34存储在哪里?这是特定于硬件的问题。程序员看不到。可能这是一些内部临时寄存器。可能这只是动态处理的电信号。从实际角度看,你可以认为浮点处理器的工作原理与我描述的一样ibed。现实可能与我的描述大不相同。但结果将是相同的。通常,真实硬件使用尾随位的摘要信息。为了进行IEEE 754四舍五入,第一位的实际值足以超出可存储的值,加上一位指示是否有任何较低符号一点不重要。没有理由进行“优化”编译器将结果显示为
1.0
。这种编译器将被称为蹩脚编译器,用于在编译时任意选取常量表达式,并使用不同于运行时语义的语义对其进行求值,所有这些都是程序员无法控制的。非蹩脚编译器根据o他们的意图,并坚持隐含的语义。@PascalCuoq:好的,所以我也许应该说“编译器可能会生成代码,给出这个计算的结果1.0,因为它不存储中间结果,在这种情况下,64位浮点将导致实际的1.0值被添加”。 101011100101011111110101000000000002 - 101011100101011111110101000000000002 = 0
float c = b - a;