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.