cfloating-pointfloating-point-conversion

Meaning of "A C compiler by default saves a floating point constant as double"


I was just beginning out with C (K.N king's C Programming) when I came across the following passage:

By default, floating constants are stored as double-precision numbers. In other words, when a C compiler finds the constant 57.0 in a program, it arranges for the number to be stored in memory in the same format as a double variable. This rule generally causes no problems, since double values are converted automatically to float when necessary.

Suppose I have the following statements:

 float x = 5.0;     // 1

 float y = 5.0f;    // 2

What does the passage mean in this example? What is the difference between statement 1 and 2 with regard to storage of values in bits?

In the first statement, is 5.0 first saved as a double and then allocated as a float to x?


Solution

  • The author’s assertion that “By default, floating constants are stored as double-precision numbers” likely arises from this paragraph in the C standard, C 2018 6.4.4.2 4:

    An unsuffixed floating constant has type double. If suffixed by the letter f or F, it has type float. If suffixed by the letter l or L, it has type long double.

    That paragraph makes it clear that a floating-point constant in source code is by default (meaning it does not have a suffix) interpreted as a double. But the author’s assertion that the value is “stored” is imprecise. The C standard tells us how to interpret source code, but it does not require that constants be stored. Even in the abstract machine model the C standard uses to specify C semantics, before optimization is considered, it is only specified that the values of variables are stored in the memory of the variables, not that the values of constants are stored.

    Thus, I would expect the compiler to do its best job of converting an unsuffixed constant to double,1 but I would not necessarily expect it to store it anywhere other than in its own memory while working with it and generating the program. It might end up storing it in the program’s data if needed, but it could generate it in instructions or fold it into other parts of an expression.

    This rule generally causes no problems, since double values are converted automatically to float when necessary.

    I would phrase it as saying problems caused by this automatic conversion are rare. Stating that it “generally” causes no problems might cause a student to take that as a general rule, rather than being cautious of when problems can occur. In situations where floating-point constants are carefully engineered for a particular task, suffixes should be used to ensure the constant has exactly the desired value.

    In your example with five, float x = 5.0; and float y = 5.0f; will produce the same value in x because five is representable in both float and double. However, consider this code:

    #include <stdio.h>
    
    
    int main(void)
    {
        float x = 0x9.876548000000000000001p0;
        float y = 0x9.876548000000000000001p0f;
        printf("%a\n", x);
        printf("%a\n", y);
    }
    

    In my C implementation, x and y get different values, and this prints:

    0x1.30eca8p+3
    0x1.30ecaap+3
    

    The reason is this:

    Footnote

    1 The C standard is lax about how floating-point constants are converted to floating-point values. C 2018 6.4.4.2 7 says translation-time conversion “should” match the conversion done by library functions such as strtod, and 7.22.1.3 9 says strtod “should” be correctly rounded if it does not have too many digits (at most DECIMAL_DIG digits) or, if it does, should equal the result of converting one of the two decimal numbers with DECIMAL_DIG digits that immediately bound the value. This is a legacy due to the fact that converting values with exponents such as +300 or -300 from scratch nominally requires computing with hundreds of digits, considered too much of a burden for early compilers and computers. Modern algorithms have been devised for this, so the standard could require correct rounding in all cases.