3
#include<stdio.h>
int main()
{
   float f = 0.1;
   double d = 0.1;
   printf("%lu %lu %lu %lu\n", sizeof(f), sizeof(0.1f), sizeof(0.1), sizeof(d));
   return 0;
}

Output

$ ./a.out 
4 4 8 8

As per above code, we can see sizeof(0.1) and sizeof(0.1f) are not same. sizeof(0.1) is 8 bytes, while sizeof(0.1f) is 4 bytes. but while assigning the value to float variable f, it automatically truncates its size to 4 bytes.

While in below code, while comparing it with float x it is not truncating and 4 bytes of float are compared with 8 bytes of 0.1, value of float x matches with 0.1f as both are of 4 bytes.

#include<stdio.h>
int main()
{
    float x = 0.1;
    if (x == 0.1)
        printf("IF");
    else if (x == 0.1f)
        printf("ELSE IF");
    else
        printf("ELSE");
}

Output

$ ./a.out 
ELSE IF

why and how it is truncating while assigning and not while comparing?

Nitin Tripathi
  • 1,224
  • 7
  • 17
  • 2
    The `float` type is a [*single precision* floating point type](https://en.wikipedia.org/wiki/Single-precision_floating-point_format), while `double` is a *double precision* floating point type. I also recommend you read ["Is floating-point math broken?"](http://stackoverflow.com/questions/588004/is-floating-point-math-broken), it will help you understand why `0.1f != 0.1`. – Some programmer dude Sep 19 '15 at 13:56
  • Is there any way to tackle rounding off issue? – Nitin Tripathi Sep 19 '15 at 14:17
  • 1
    @NitinTripathi Never compare floating point numbers for equality and expect them to always be off by a small amount. You can also avoid this by not using the `float` type unless absolutely necessary. – fuz Sep 19 '15 at 16:24
  • **not using the float** will force us to use **double** which will be add **another overhead of 4 bytes** which is again not good programming practice :( – Nitin Tripathi Sep 20 '15 at 03:32

5 Answers5

7

A floating point literal without a suffix is of type double. Suffixing it with an f makes a literal of type float.

When assigning to a variable, the right operand to = is converted to the type of the left operand, thus you observe truncation.

When comparing, the operands to == are converted to the larger of the two operands, so x == 0.1 is like (double)x == 0.1, which is false since (double)(float)0.1 is not equal to 0.1 due to rounding issues. In x == 0.1f, both operands have type float, which results in equality on your machine.

Floating point math is tricky, read the standard for more details.

fuz
  • 88,405
  • 25
  • 200
  • 352
  • Thanks @FUZxxl, that was really helpful. whatever you said in third para, i actually tried to implement it and found below: `printf("%lu %lu %lu %lu\n", sizeof((double)f), sizeof((double)0.1f), sizeof((double)0.1), sizeof((double)d)); printf("%15.15f %15.15f %15.15f %15.15f\n", (double)f, (double)0.1f, (double)0.1, (double)d);` **Output:** `$ ./a.out 4 4 8 8 8 8 8 8 0.100000001490116 0.100000001490116 0.100000000000000 0.100000000000000` If we see, all four are converted to 8 bytes by typecasting, but rounding issue occurs while typecasting from float to double. – Nitin Tripathi Sep 19 '15 at 14:07
  • 1
    @NitinTripathi something's wrong with your comment, `sizeof((double)x)` will always output `8` no matter what `x` is – M.M Sep 19 '15 at 14:33
  • Thanks @M.M for pointing out. correction as below `printf("%lu %lu %lu %lu\n", sizeof((double)f), sizeof((double)0.1f), sizeof((double)0.1), sizeof((double)d)); printf("%15.15f %15.15f %15.15f %15.15f\n", (double)f, (double)0.1f, (double)0.1, (double)d);` Output: `$ ./a.out 8 8 8 8 0.100000001490116 0.100000001490116 0.100000000000000 0.100000000000000` If we see, all four are converted to 8 bytes by typecasting, but rounding issue occurs while typecasting from float to double. – Nitin Tripathi Sep 19 '15 at 14:38
2

a floating point constant like 0.1 is a double unless specified as a float like 0.1f. The line

float f = 0.1;

means create a double with value 0.1 and cast it to float and lose precision in the process. The lines

float x = 0.1;
if (x == 0.1)

will cause x to be implicitly converted to double but it will have a slightly different value than for e.g. double x = 0.1;

Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82
1

0.1f (the "f" after the number) is for the computer as float , that how your compailer know that he need to store it as float and not as double. so float 0.1 not equal to 0.1 , its equal to 0.1f

Ori Yampolsky
  • 125
  • 13
1

when you write 0.1 , it is considered by default as double. suffix f explicitly make it float.

In second question float are stored as ieee standard so it it's going in else if because equivalent conversion of 0.1f to double is not same.

https://en.wikipedia.org/wiki/Floating_point

Nishant Kumar
  • 2,199
  • 2
  • 22
  • 43
1

0.1 is a double value whereas 0.1f is a float value. The reason we can write float x=0.1 as well as double x=0.1 is due to implicit conversions .

But by using suffix f you make it a float type .

In this -

if(x == 0.1)

is flase because 0.1 is not exactly 0.1 at some places after decimal .There is also conversion in this to higher type i.e double.

Converting to float and then to double , there is loss of information as also double as higher precession than float so it differs .

ameyCU
  • 16,489
  • 2
  • 26
  • 41