Is floating point expression contraction allowed in C++?

老子叫甜甜 提交于 2019-12-07 03:46:31

问题


Floating point expressions can sometimes be contracted on the processing hardware, e.g. using fused multiply-and-add as a single hardware operation.

Apparently, using these this isn't merely an implementation detail but governed by programming language specification. Specifically, the C89 standard does not allow such contractions, while in C99 they are allowed provided that some macro is defined. See details in this SO answer.

But what about C++? Are floating-point contractions not allowed? Allowed in some standards? Allowed universally?


回答1:


Summary

Contractions are permitted, but a facility is provided for the user to disable them. Unclear language in the standard clouds the issue of whether disabling them will provide desired results.

I investigated this in the official C++ 2003 standard and the 2017 n4659 draft. C++ citations are from 2003 unless otherwise indicated.

Extra Precision and Range

The text “contract” does not appear in either document. However, clause 5 Expressions [expr] paragraph 10 (same text in 2017’s 8 [expr] 13) says:

The values of the floating operands and the results of floating expressions may be represented in greater precision and range than that required by the type; the types are not changed thereby.

I would prefer this statement explicitly stated whether this extra precision and range could be used freely (the implementation may use it in some expressions, including subexpressions, while not using it in others) or had to be used uniformly (if the implementation uses extra precision, it must use it in every floating-point expression) or according to some other rules (such as it may use one precision for float, another for double).

If we interpret it permissively, it means that, in a*b+c, a*b could be evaluated with infinite precision and range, and then the addition could be evaluated with whatever precision and range is normal for the implementation. This is mathematically equivalent to contraction, as it has the same result as evaluating a*b+c with a fused multiply-add instruction.

Hence, with this interpretation, implementations may contract expressions.

Contractions Inherited From C

17.4.1.2 [lib.headers] 3 (similar text in 2017’s 20.5.1.2 [headers] 3) says:

The facilities of the Standard C Library are provided in 18 additional headers, as shown in Table 12…

Table 12 includes <cmath>, and paragraph 4 indicates this corresponds to math.h. Technically, the C++ 2003 standard refers to the C 1990 standard, but I do not have it in electronic form and do not know where my paper copy is, so I will use the C 2011 standard (but unofficial draft N1570), which the C++ 2017 draft refers to.

The C standard defines, in <math.h>, a pragma FP_CONTRACT:

#pragma STDC FP_CONTRACT on-off-switch

where on-off-switch is on to allow contraction of expressions or off to disallow them. It also says the default state for the pragma is implementation-defined.

The C++ standard does not define “facility” or “facilities.” A dictionary definition of “facility” is “a place, amenity, or piece of equipment provided for a particular purpose” (New Oxford American Dictionary, Apple Dictionary application version 2.2.2 (203)). An amenity is “a desirable or useful feature or facility of a building or place.” A pragma is a useful feature provided for a particular purpose, so it seems to be a facility, so it is included in <cmath>.

Hence, using this pragma should permit or disallow contractions.

Conclusions

  • Contractions are permitted when FP_CONTRACT is on, and it may be on by default.

  • The text of 8 [expr] 13 can be interpreted to effectively allow contractions even if FP_CONTRACT is off but is insufficiently clear for definitive interpretation.




回答2:


Yes, it is allowed.

For example in Visual Studio Compiler, by default, fp_contract is on. This tells the compiler to use floating-point contraction instructions where possible. Set fp_contract to off to preserve individual floating-point instructions.

// pragma_directive_fp_contract.cpp
// on x86 and x64 compile with: /O2 /fp:fast /arch:AVX2
// other platforms compile with: /O2

#include <stdio.h>

// remove the following line to enable FP contractions
#pragma fp_contract (off)

int main() {
   double z, b, t;

   for (int i = 0; i < 10; i++) {
      b = i * 5.5;
      t = i * 56.025;

      z = t * i + b;
      printf("out = %.15e\n", z);
   }
}

Detailed information about Specify Floating-Point Behavior.

Using the GNU Compiler Collection (GCC):

The default state for the FP_CONTRACT pragma (C99 and C11 7.12.2). This pragma is not implemented. Expressions are currently only contracted if -ffp-contract=fast, -funsafe-math-optimizations or -ffast-math are used.



来源:https://stackoverflow.com/questions/49278125/is-floating-point-expression-contraction-allowed-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!