c++floating-pointlanguage-lawyerfma

Is floating point expression contraction allowed in C++?


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?


Solution

  • 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