2

I was working on some 'determine the output' questions in C. I came across this question which looked simple on the face of it, but after running the code left me puzzled.

The output I expected was "True". However upon running, it was "False". And when I checked the value of f using printf(), it showed 0.1. Can someone please explain why f being assigned 0.1 doesn't return true for the IF statement?

There was no explanation for the answer from where I picked the question up, and I wasn't able to find an answer myself.

#include <stdio.h>

int main()
{
    float f = 0.1;
    if (f == 0.1)
        printf("True");
    else
        printf("False");
}
Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
VGupta
  • 109
  • 8
  • 4
    Read about [floating point precision](http://floating-point-gui.de/). – haccks Jul 20 '14 at 18:00
  • Going through it now @haccks, thanks. – VGupta Jul 20 '14 at 18:03
  • 2
    Note that if you changed the type of `f` to `double` or compared to `1.0f` rather than `1.0`, the condition would be true. – avakar Jul 20 '14 at 18:06
  • 3
    @avakar I'm confounded by how many people are answering this, yet *not* pointing out that the literal `0.1` isn't a `float`, its a `double`. The *loss* of precision when converting a floating point value that cannot be represented perfectly as `double` or `float` from `double` *to* `float` is causing the results seen. – WhozCraig Jul 20 '14 at 18:08
  • @WhozCraig, hopefully, Vlad's answer will `float` to the top. – avakar Jul 20 '14 at 18:15
  • The proposed dup doesn't answer _this_ question. The problem of adding floating point numbers of **the same type** in a loop, is quite different from comparing floating point numbers of **different types**. – Nisse Engström Feb 23 '16 at 10:11

4 Answers4

9

The problem is that variable f defined as having type float while float constant 0.1 has type double. Type double has more precision than type float. it has more binary digits to represent fraction. So in this statement

        float f = 0.1;

there is a truncation.

To get the expected result you should write at least

        if (f == 0.1f)

Also that to be sure that there is no rounding the code should look as

#include <stdio.h>

int main( void )
{
    float f = 0.1f;

    if ( f == 0.1f )
        printf("True\n");
    else
        printf("False\n");
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • +1 Type consistency; its whats for dinner. – WhozCraig Jul 20 '14 at 18:14
  • I see. Need to go back to the absolute basics! Thanks so much for the explanation, it all makes sense now. :) – VGupta Jul 20 '14 at 18:15
  • So, can it be deduced that the compiler takes numbers as double unless explicitly specified as float? – VGupta Jul 20 '14 at 18:17
  • 1
    @user3714817 Yes. Just like literal `5` is an `int` unless you specify otherwise (`5l` for `long int`, `5u` for `unsigned int`, etc), there has to be a default *somewhere*. For floating pointer literals the default is `double` unless you specify otherwise with the literal value itself (in this case the `f` specifier in this example). – WhozCraig Jul 20 '14 at 18:21
  • 1
    @user3714817 btw, to firm this up once in for all, just throw out everything but the `if` test and change that expression to `if (0.1f == 0.1)`. The result (False) should endure. – WhozCraig Jul 20 '14 at 18:27
  • Thanks @WhozCraig, it'll be easier to remember this now that I know the defaults better! – VGupta Jul 20 '14 at 18:28
  • "So in this statement `float f = 0.1;` there is a truncation" is _likely_ true as most floating point implementations use a binary based format, `0.1` is not exactly representation as such and `double` format often differs from `float`. C does not specify floating point must be binary base and decimal base floating point, though rare, could represent `0.1` equally both as a `float` and `double`. More common are limited systems (embedded) that use the same floating point representation for both `float` and `double`, so `0.1f == 0.1` is true. C doesn't require `double` and `float` to differ. – chux - Reinstate Monica Aug 01 '14 at 21:48
2

That is because of the precision of float value.

Check this:- What Every Computer Scientist Should Know About Floating-Point Arithmetic

You can better use double instead of float.

Also to note that(Correctly pointed by WhozCraig) that 0.1 is a double not a float. Change the float to double and you will get the expected output.

Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
  • It's quite silly how even upon printing the variable, it doesn't reflect the actual precision it used to make the comparison! – VGupta Jul 20 '14 at 18:03
  • 1
    @user3714817: Probably you didn't print with enough precision? – mafso Jul 20 '14 at 18:03
1

0.1 cannot be represented exactly in binary . 0.1 in binary would be 0.0r0011r which is recurring so internally it is rounded off which is not exact value. That is why it returns false. But if you try with number like 0.5 which is 0.1 in binary or 0.250 or 0.125 whichever can be perfectly represented it would return true. Also read http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html . Better to use double for more accurate results.

sujithvm
  • 2,351
  • 3
  • 15
  • 16
  • Thanks for the explanation and the 0.5 example! – VGupta Jul 20 '14 at 18:05
  • Sure it can't be represented exactly, but `0.1` doesn't magically change its representation. The only reason the comparison doesn't work is because `0.1` as a `double` has a different representation than the `float` it's being compared to. – chris Jul 20 '14 at 18:21
1

Well, that's a problem float type has. Check that if you change float with double type it prints true instead of false. Also try this output:

#include <stdio.h>

int main()
{
    float f;
    for(f=.0;f<10.;f+=0.1)
        printf("%f \n",f);    
}
dragosht
  • 3,237
  • 2
  • 23
  • 32
csdinos
  • 197
  • 2
  • 6
  • `double` has the same problem in general. Changing `0.1` to `0.1f` also works because the same value is compared to. If using `double`, `0.1` is a `double` and thus the same value is compared to. – chris Jul 20 '14 at 18:19
  • yes indeed, but using double you will have less problems like this. – csdinos Jul 20 '14 at 18:25
  • Less problems where you explicitly have two constants to compare. Nothing is ever that simple when you actually *use* floating-point numbers. You have no idea what the exact number being given to you to compare is and trying to compare it as if you do will not give you good results, whether you use `float` or `double`. – chris Jul 20 '14 at 18:31