The type of a floating point literal with exponent

By default, all floating point literals, with or without an exponent part, have type double. You can add the f suffix to make the type float or L to make the type long double.

In the case of float f = 123456e-3;, you're initializing a float with a double constant, so there is the possibility of loss of precision, however this particular constant only has 6 decimal digits of precision so it should be OK.


What is the type of a floating-point literal?

Floating constants

C defines these as floating constants, not literals. Default type is double.
An f or F suffix makes it a float.
An l or L suffix makes it a long double.

[edit] FLT_EVAL_METHOD

C has FLT_EVAL_METHOD which allows constants to be interpreted as a wider type.

Example FLT_EVAL_METHOD == 2

evaluate all operations and constants to the range and precision of the long double type.

In this case, I'd expect v1 and v2 to have the same value when FLT_EVAL_METHOD == 2, but different values when FLT_EVAL_METHOD == 0.

long double v1 = 0.1;
long double v2 = 0.1L;

When used as a float initializer in float f = 123456e-3; does it need to have a f suffix?

For best conversion of the text to float, yes use an f.

float f = 123456e-3 incurs double rounding. 2 rounding occurs: text->double and double to float.

With select values, g may get a different value with float g = x.xxx vs g = x.xxxf;. See following.

double rounding example

Notice f2 and f4 have the same constant except the the f suffix. Compiler warns with f4:

warning: conversion from 'double' to 'float' changes value from '9.9999997019767761e-1' to '1.0e+0f' [-Wfloat-conversion]

#include <stdlib.h>
int main(void) {
  // float has 24 bit significand, double has 53
  float f1 = 0x0.FFFFFFp0f;         // code with 24 bit significand, exact as a float
  printf("%-20a %.17e\n", f1, f1);
  float f2 = 0x0.FFFFFF7FFFFFFCp0f; // code with 54 bit significand, rounds down to nearest float
  printf("%-20a %.17e\n", f2, f2);
  float f3 = 0x0.FFFFFF80000000p0f; // code with 25 bit significand, rounds up to nearest float
  printf("%-20a %.17e\n", f3, f3);
  puts("");
  double d1 = 0x0.FFFFFF7FFFFFF8p0; // code constant with 53 bit significand, exact as a double
  printf("%-20a %.17e\n", d1, d1);
  double d2 = 0x0.FFFFFF7FFFFFFCp0; // code constant with 54 bit significand, rounds up to nearest double
  printf("%-20a %.17e\n", d2, d2);
  float f4 = 0x0.FFFFFF7FFFFFFCp0;  // code constant with 54 bit significand, rounds up to nearest double
                                    // then rounds up again when double converted to float
  printf("%-20a %.17e\n", f4, f4);
  return 0;
}

Output

0x1.fffffep-1        9.99999940395355225e-01
0x1.fffffep-1        9.99999940395355225e-01  f2
0x1p+0               1.00000000000000000e+00

0x1.fffffefffffffp-1 9.99999970197677501e-01
0x1.ffffffp-1        9.99999970197677612e-01
0x1p+0               1.00000000000000000e+00  f4 Double Rounding!

For best conversion of the text to long double, definitely use an L else the constant is only a double with less precision.

long double ld1 = 0x1.00000000000001p1;
printf("%.20Le\n", ld1, ld1);
long double ld2 = 0x1.00000000000001p1L; // "Same" constant as above with an 'L'
printf("%.20Le\n", ld2, ld2);

Output

2.00000000000000000000e+00
2.00000000000000002776e+00

For floating point literal, if no suffix is defined, it will be automatically considered as double.

You can follow this chart for suffix:

(no suffix) - double

f/F - float

l/L - long double

So, for float, it needs to have f or F suffix.