11

What is the type of a floating-point literal having an exponent part, such as the 123456e-3 in C(99+)? Is it of type float or double? When used as a float initializer in float f = 123456e-3; does it need to have a f suffix?

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
Ron
  • 14,674
  • 4
  • 34
  • 47
  • It is `double`: https://en.cppreference.com/w/c/language/floating_constant – isrnick Jun 26 '20 at 15:04
  • The floating-point literal has type `double` unless it has a suffix. The value of the initializer will be converted to `float` in the same way as for a simple assignment. – Ian Abbott Jun 26 '20 at 15:06

3 Answers3

10

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.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • 2
    Here, both `float f = 123456e-3;` and `float f = 123456e-3f;` result in `0x1.edd2f2p+6` being stored. However it is a best practice to initialize `float` variables with `float` literal constants, to avoid potential issues with double rounding. – njuffa Jun 27 '20 at 18:10
7

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.

UkFLSUI
  • 5,509
  • 6
  • 32
  • 47
7

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
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256