Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
float f(float x) {
  return x * 0.1f;
}

float g(float x) {
  return x * 0.1;
}

Function f is allowed to return a value wider than float, but function g (which uses the wider constant) is not.

...

Footnote 142 says a cast may be used to remove extra range and precision from the return expression. This means a predictable program must have casts on all floating-point function calls (except where the function directly feeds an operator like assignment that implies the conversion). With type-generic math (tgmath), the programmer has to reason through the tgmath resolution rules to determine which casts to apply. These are significant obstacles to writing predictable code.

NOTE: WG14 has voted to include the following text in C1X. This only impacts implementations that implement the optional Annex F "IEC 60559 floating-point arithmetic.".

Require return expressions to be converted as if by assignment to the type of the function, but only in Annex F. This is a compromise that addresses the problems for Annex F implementations while not impacting non-Annex F implementations that exercise the license for wide returns.

Insert the following new subclause after F.5 (and increment subsequent subclause numbers):

F.6 The return statement

If the return expression is evaluated in a floating-point format different from the return type, then the expression is converted to the return type of the function and the resulting value is returned to the caller.

...

The following example code has been constructed to illustrate an example that does not conform to this recommendation.   The code is non-conforming nonconforming because it does not cast the result of the expression in the return statement and thereby guarantee the range or precision is no wider than expected.   The uncertainty in this example is introduced by the constant 0.1f.   This constant may be stored with a range or precision that is greater than that of float.   Consequently, the result of x * 0.1f may also have a range or precision greater than that of float.   As described above, this range or precision may not be reduced to that of a float and, thus, the caller of calcPercentage() may receive a value that is more precise than expected.   This may lead to inconsistent program execution across different platforms.

...

The following code example remedies the above noncompliant code by casting the value of the expression in the return statement.   This forces the return value to have the expected range and precision as described in Section 5.2.4.2.2 8 of the C Standard.

...

Unfortunately, not all compilers may honor casts.   In this case, the range and precision must be forced by assignment to a variable of the correct type.   The following code example illustrates this approach.

...

Compliant Code Example (Outside the function 1)

Forcing the range and precision inside the calcPercentage() function is a good way to fix the problem once without having to apply fixes in multiple locations (every time calcPercentage() is called).   However, access to the called function may not always be available.   This example shows one way to force the correct range and precision in a situation in which the source of the called function can not be modified.   This is accomplished by casting the return value of the calcPercentage() function to float.

Code Block
bgColor#ccccff
void floatRoutine(void) {
  float value = 99.0f;
  long double percentage;

  percentage = (float)calcPercentage(value);
}

...

This example shows another way to force the correct range and precision.   In this case, a temporary variable is used as the forcing mechanism.

...