为什么编译时浮点计算的结果可能与运行时计算的结果不同?

时间:2018-06-21 01:10:23

标签: c++ floating-point language-lawyer constexpr floating-accuracy

constexpr: Introduction中,发言者提到“编译时浮点计算可能与运行时计算的结果不同”: enter image description here

原因与“交叉编译”有关。

老实说,我不清楚。恕我直言,不同的平台也可能具有不同的整数实现。

为什么它只影响浮点数?还是我想念什么?

3 个答案:

答案 0 :(得分:3)

在某种程度上,您绝对正确的是,在编译时计算浮点值的问题与计算整数值的问题相同。不同之处在于任务的复杂性。在具有16位寄存器的系统上模拟24位整数数学相当容易。对于认真的程序员来说,这是一个手指练习。如果没有本机实现,则进行浮点数学运算要困难得多。不需要浮点constexpr的决定部分是基于这种差异:要求交叉编译器在编译时为其目标平台模拟浮点数学确实非常昂贵。

另一个原因是可以在运行时设置浮点计算的某些详细信息。取整是一;处理上溢和下溢是另一回事。编译器根本无法了解浮点计算的运行时评估的完整上下文,因此无法可靠地在编译时计算结果。

答案 1 :(得分:2)

  

为什么只影响浮点数?

对于该标准,浮点运算精度没有限制。

根据expr.const强调我的

  

[注意:由于,本文档对以下内容的准确性不加任何限制:   浮点运算,是否未指定   翻译过程中的浮点表达式产生相同的结果   作为相同表达式(或相同运算符)的求值   相同的值)。 [示例:

bool f() {
    char array[1 + int(1 + 0.2 - 0.1 - 0.1)];  // Must be evaluated during translation
    int size = 1 + int(1 + 0.2 - 0.1 - 0.1);   // May be evaluated at runtime
    return sizeof(array) == size;
}
     

未指定f()的值是true还是false。   —示例]
  —尾注]

答案 2 :(得分:1)

  

为什么只影响浮点数?

一些对整数的操作无效且未定义:

  • 除以零:未为操作数定义数学运算
  • 溢出:给定类型无法表示的数学值

[编译器将在编译时间值上检测到这种情况。在运行时,行为不是标准定义的,可以是引发信号,模运算或“随机”行为的任何行为,如果编译器认为这些操作有效。]

有效整数上的运算在数学上已完全指定

C / C ++(和大多数编程语言)中的整数除法是一个精确的运算,因为它是欧几里得除法,而不是试图找到有理除法的近似值的运算:5/3是1,无穷十进制表示形式5/3的比例为1.66 ...或大约1.66666667;最接近的整数是2。

fp的目的是在“实数”(这四个操作实际上是有理数,根据定义浮点数是有理数)上提供数学运算的最佳近似。这些操作将根据当前舍入模式进行舍入,该模式使用std::fesetround进行设置。因此,fp操作是取决于状态的,结果不仅是操作数的函数。 (请参见std::fegetround, std::fesetround。)

在编译时没有这种“状态”,因此根据定义,编译时fp操作不能与运行时操作一致。

相关问题