cfloating-pointroundingc11subnormal-numbers

HAS_SUBNORM is 0: "subnormal results" are determined before rounding or after rounding?


C11, 5.2.4.2.2 Characteristics of floating types <float.h>, 10, footnote 26:

Characterization as absent is intended if no floating-point operations produce subnormal results from non-subnormal inputs, even if the type format includes representations of subnormal numbers.

Here "subnormal results" are determined before rounding or after rounding?

Test shows that some implementations do it before rounding, some implementations do it after rounding.

Here is the test:

#if FLT_HAS_SUBNORM == 0
int subnorm_determ_method( void )
{
    volatile float f1 = FLT_MIN; /* 1.17549435e-38f */
    volatile float f2 = 1.0000001f;
    volatile float f3;
    int r;

    r = fesetround(FE_UPWARD);
    if ( r != 0 )        return -1; /* error: fesetround(FE_UPWARD) failed */
    f3 = f1 / f2;
    if ( f3 == FLT_MIN ) return 0; /* "subnormal results" are determined after rounding */
    if ( f3 == 0.0f )    return 1; /* "subnormal results" are determined before rounding */
    return -2; /* error: unexpected result */
}
#endif

UPD (after more research / experiments is / are done).

  1. The exact place of execution of FTZ logic is irrelevant to this question: no matter if FTZ logic is executed before rounding or after rounding, the rounded (delivered) result is not a subnormal.
  2. If an implementation does not support subnormal numbers, then such implementation does not conform to IEEE 754. Hence, such implementation is free to chose at which step the FTZ logic is executed. Experiments confirm that: different implementations configured with FTZ=1 (or with permanent FTZ=1) may execute FTZ logic at different steps, hence, producing different results: ±0.0 or ±<TYPE_PREFIX>_MIN.
  3. Extra: raising of floating-point exceptions in case of FTZ=1: the same story as in 2.: IEEE 754 nonconforming implementations are free to do what they want.

Solution

  • No standard governs whether an implementation that chooses to flush subnormal values to zero does so based on whether mathematical result before rounding is subnormal or the result of rounding is subnormal.

    Whichever choice an implementation makes in that regard, the quoted text concerns the delivered results. If no floating-point operation produces a subnormal result, then characterization as absent is intended.

    Note that whether an implementation chooses to flush subnormal values to zero before or after rounding is irrelevant to this: In either case, an implementation will not deliver subnormal results. One that flushes subnormals after rounding will flush to zero all the results and only the results that would have been subnormal. One that flushes before rounding will flush to zero all the results that would have been subnormal and some that would have been normal. Both never deliver subnormal results.