简体   繁体   English

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

[英]Why compile-time floating point calculations might not have the same results as run-time calculations?

In constexpr: Introduction , the speaker mentioned "Compile-time floating point calculations might not have the same results as runtime calculations": constexpr:Introduction中 ,发言者提到“编译时浮点计算可能与运行时计算的结果不同”: 在此输入图像描述

And the reason is related to "cross-compiling". 原因与“交叉编译”有关。

Honestly, I can't get the idea clearly. 老实说,我无法清楚地理解这个想法。 IMHO, different platforms may also have different implementation of integers. 恕我直言,不同的平台也可能有不同的整数实现。

Why does it only affect floating points? 为什么它只影响浮点数? Or I miss something? 或者我想念什么?

You're absolutely right that, at some level, the problem of calculating floating-point values at compile time is the same as that of calculating integer values. 你是绝对正确的,在某种程度上,在编译时计算浮点值的问题与计算整数值的问题是一样的。 The difference is in the complexity of the task. 不同之处在于任务的复杂性。 It's fairly easy to emulate 24-bit integer math on a system that has 16-bit registers; 在具有16位寄存器的系统上模拟24位整数数学是相当容易的。 for serious programmers, that's a finger exercise. 对于认真的程序员来说,这是一个手指练习。 It's much harder to do floating-point math if you don't have a native implementation. 如果你没有本机实现,那么做浮点数学要困难得多。 The decision to not require floating-point constexpr is based in part on that difference: it would be really expensive to require cross-compilers to emulate floating-point math for their target platform at compile time. 不要求浮点constexpr的决定部分基于这种差异:要求交叉编译器在编译时为其目标平台模拟浮点数学将是非常昂贵的。

Another factor in this is that some details of floating-point calculations can be set at runtime. 另一个因素是可以在运行时设置浮点计算的一些细节。 Rounding is one; 舍入是一个; handling of overflows and underflows is another. 处理溢出和下溢是另一回事。 There's simply no way that a compiler can know the full context for the runtime evaluation of a floating-point calculation, so calculating the result at compile-time can't be done reliably. 编译器根本无法知道浮点计算的运行时评估的完整上下文,因此无法可靠地在编译时计算结果。

Why does it only affect floating points? 为什么它只影响浮点数?

For the standard doesn't impose restrictions on floating-point operation accuracy. 对于标准,不对浮点运算精度施加限制。

As per expr.const , emphasis mine : 根据expr.const强调我的

[ Note: Since this document imposes no restrictions on the accuracy of floating-point operations , it is unspecified whether the evaluation of a floating-point expression during translation yields the same result as the evaluation of the same expression (or the same operations on the same values) during program execution. [注意:由于本文档对浮点运算的准确性没有任何限制 ,因此未指定在转换期间对浮点表达式的求值是否与对同一表达式的求值产生相同的结果(或者对程序执行期间的相同值)。 [ Example: [例如:

 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; } 

It is unspecified whether the value of f() will be true or false . 未指定f()的值是true还是false — end example ] - 结束例子]
— end note ] - 结束说明]

Why does it only affect floating points? 为什么它只影响浮点数?

Some operations on integers are invalid and undefined: 对整数的一些操作无效且未定义:

  • divide by zero: mathematical operation not defined for the operand 除以零:没有为操作数定义的数学运算
  • overflow: mathematical value not representable for the given type 溢出:给定类型无法表示的数学值

[The compiler will detect such cases on compile time values. [编译器将在编译时值上检测此类情况。 At runtime, the behavior is not defined by the standard and can be anything, from throwing a signal, modulo operation, or "random" behavior if the compiler assumed that operations are valid.] 在运行时,行为不是由标准定义的,可以是任何东西,例如,如果编译器假定操作有效,则抛出信号,模运算或“随机”行为。

Operations on integers that are valid are completely specified mathematically . 对数组有效的整数的操作是完全以数学方式指定的

Division of integers in C/C++ (and most programming languages) is an exact operation as it's Euclidean division, not an operation trying to find a close approximation of division of rationals: 5/3 is 1, infinite decimal representation of 5/3 is 1.66... or approximately 1.66666667; C / C ++(和大多数编程语言)中的整数除法是一个精确的操作,因为它是欧几里德除法,而不是试图找到有理数除法的近似逼近: 5/35/3 3的无限十进制表示是1.66 ...或约1.66666667; closest integer is 2. 最接近的整数是2。

The aim of fp is to provide the best approximation of the mathematical operation on "real numbers" (actually rational numbers for the four operations, floats are rational by definition). fp的目的是提供关于“实数”的数学运算的最佳近似值(对于四个运算实际上是有理数,浮点数是合理的定义)。 These operations are rounded according to the curent rounding mode , set with std::fesetround . 根据使用std::fesetround设置的std::fesetround 舍入模式对这些操作进行舍 So the fp operations are state dependent, the result isn't a function of only the operands. 因此fp操作是依赖于状态的,结果不仅仅是操作数的函数。 (See std::fegetround, std::fesetround .) (参见std :: fegetround,std :: fesetround 。)

There is no such "state" at compile time, so compile time fp operations cannot be consistent with run time operations, by definition. 在编译时没有这样的“状态”,因此根据定义,编译时fp操作不能与运行时操作一致。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM