9

In the given program why did I get different results for each of the printfs?

#include <stdio.h>
int main()
{
    float c = 4.4e10;
    printf("%f\n", c);
    printf("%f\n", 4.4e10);
    return 0;
}

And it shows the following output:

44000002048.000000
44000000000.000000
S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
user10056563
  • 105
  • 4
  • 4
    The answers so far explain that `4.4e10` is a `double` constant which is converted to `float` in the initialization of `c` but kept as a `double` when passed to `printf`. However, you might also like to know that adding an `f` suffix makes it a `float` constant: Printing `4.4e10f` will show the same value that results from initializing `c` to `4.4e10f`. Distinguishing `float` constants from `double` constants can be important to doing quality work with floating-point arithmetic. – Eric Postpischil Oct 01 '19 at 15:08
  • Is this conversion method named anything? I want to read about it. – user10056563 Oct 01 '19 at 15:11
  • Do you want to know when the conversion from `double` to `float` occurs in the C language? Or do you want to know what values result from the conversion, that is, what effects the conversion has? Or something else? – Eric Postpischil Oct 01 '19 at 15:21
  • I'm questioning ***neither*** the replies here ***nor*** the standard but, when I was young and learning `C` we used `printf("%f",x)` for a `float` and `printf("%lf",x)` for a `double`. When did things change? And how would one *explicitly* printf a (single) `float` - `printf("%hf",x)`?? – Adrian Mole Oct 01 '19 at 15:34
  • Possible duplicate of ['float' vs. 'double' precision](https://stackoverflow.com/questions/5098558/float-vs-double-precision) – S.S. Anne Oct 01 '19 at 15:37
  • 2
    @Adrian `%lf` in printf is the same thing as `%f`. A `float` in a variable argument is converted into a `double` by the compiler, just like a `short` gets converted into an `int`. – S.S. Anne Oct 01 '19 at 15:38
  • Also see https://stackoverflow.com/questions/6395726/how-does-printf-and-co-differentiate-between-float-and-double and https://stackoverflow.com/questions/28097564/why-does-printf-promote-a-float-to-a-double and maybe even https://stackoverflow.com/questions/4264127/correct-format-specifier-for-double-in-printf – S.S. Anne Oct 01 '19 at 15:46
  • See also the canonical question on these issues, [Is floating point math broken?](https://stackoverflow.com/questions/588004) – Steve Summit Oct 01 '19 at 16:46

2 Answers2

9

A float is a type that holds a 32-bit floating point number, while the constant 4.4e10 represents a double, which holds a 64-bit floating point number (i.e. a double-precision floating point number)

When you assign 4.4e10 to c, the value 4.4e10 cannot be represented precisely (a rounding error in a parameter called the mantissa), and the closest possible value (44000002048) is stored. When it is passed to printf, it is promoted back to double, including the rounding error.

In the second case, the value is a double the whole time, without narrowing and widening, and it happens to be the case that a double can represent the value exactly.

If this is undesirable behavior, you can declare c as a double for a bit more precision (but beware that you'll still hit precision limits eventually).

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
nanofarad
  • 40,330
  • 4
  • 86
  • 117
3

You're actually printing the values of two different types here.

In the first case you're assigning a value to a variable of type float. The precision of a float is roughly 6 or 7 decimal digits, so unless the value can be represented exactly you'll see the closest value that can be represented by that type.

In the second case you're passing the constant 4.4e10 which has type double. This type has around 16 decimal digits of precision, and the value is within that range, so the exact value is printed.

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
dbush
  • 205,898
  • 23
  • 218
  • 273