retagged by
5,554 views
8 votes
8 votes

Program 1:

#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");
}

The output of above program is “ELSE IF”.

Program 2:

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

Output:

IF

Why these above two program showing different behavior ?

Here is what the standard C99 standards say:

There are three floating point types: floatdouble, and long double. The type doubleprovides at least as much precision as float, and the type long double provides at least as much precision as double. The set of values of the type float is a subset of the set of values of the type double; the set of values of the type double is a subset of the set of values of the type long double.

The C++ standard adds:

The value representation of floating-point types is implementation-defined. 

So  floating point comparison results in undefined behavior?

Please tell me why I am getting these weird output and is there any way to predict these outputs on the same processor. Also how comparison is done of two variables in C ?

retagged by

1 Answer

Best answer
10 votes
10 votes

Program 1 :-

#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");
}

Some Important Points :

  • $0.1$ on the RHS has by default double data type (Double precision floating point format - $64$ bits).
  • Assigning it to float $x$, cuts off the precision to single precision floating point format - $32$ bits .
0.1 in single precision floating point format (IEEE 754) : 00111101 | 11001100 | 11001100 | 11001101 
0.1 in double precision floating point format (IEEE 754) :
00111111 10111001 10011001 10011001
10011001 10011001 10011001 10011010
  • Now, in the IF block $0.1$ in float is promoted to double by padding some zeroes .
  • Now, compare both their MANTISSA's in the above precisions given . They are not equal .
  • ELSE-IF block compares float with 0.1f which is also a explicitly promoted float value . Hence, both the values are equal and this block executes and output ELSE IF is shown .


Program 2 :-

#include<stdio.h>
int main()
{
    float x = 0.5;
    if (x == 0.5)
        printf("IF");
    else if (x == 0.5f)
        printf("ELSE IF");
    else
        printf("ELSE");
}
  • $0.5$ is by default double data type .
  • Assigning it to float $x$, again cuts off the precision to float value (32 bits) .
0.5 in single precision floating point format (IEEE 754): 00111111 | 00000000 | 00000000 | 00000000 
0.5 in single precision floating point format (IEEE 754) :
00111111 11100000 00000000 00000000
00000000 00000000 00000000 00000000
  • Compare their MANTISSA bits and they are equal .
  • Hence, block IF is successfully executed  and output is IF .


Some Similar programs :- 

  • #include <stdio.h>
    int main()
    {
        float a = 0.25;
        if(a == 0.25)
            printf("Hello");
        else printf(" World");
    }
  • #include <stdio.h>
    int main()
    {
        float a = 0.98;
        if(a == 0.98)
            printf("Hello");
        else printf(" World");
    }
    


Moreover, I think you are confusing implementation defined and undefined behaviour ?

  • Implementation defined :- It implements the behaviour such that something is perfectly documented or it is pretty sure that it is going to happen or to guarantee that this will definitely happen .So, this is something that the vendor can document the behaviour ..

Ex :- sizeof(long) ; sizeof(short) ; adding zeroes when right shift occurs ; unsigned range moving from $0$ to UINT_MAX is surely going to wrap and start from $0$ again once UINT_MAX is counted .

  • Undefined Behaviour :- It is like something is undefined, not sure whether it will throw compiler error or core dump or garbage values or perfectly execute it. Like modify a string literal throws compiler error on some platforms but that is not so for some other platforms and sometimes output is changed . But this is something that cannot be mandated what is going to happen and this is what undefined behaviour . 

Ex :- Changing string literals ; x++ * x++ ; a[i]=i++ ; dereferencing the null pointer or freed memory , accessing out of scope objects, etc .

$C99$ also says that 

int a;
printf("%u", a);

throws UB as printf format specifier and argument should be of same type otherwise behaviour is undefined but still it works on some platforms .

selected by

Related questions

0 votes
0 votes
0 answers
1
sh!va asked Sep 30, 2017
339 views
In C++, size of float and double data types are 4 bytes and 8 bytes respectively. Calculate range ( minimum and maximum values) of float and double:
1 votes
1 votes
2 answers
4
Abhisek Saha asked Aug 31, 2018
585 views
#include<stdio.h int main() { int x, y = 7; x = ++y + ++y + y ; printf("%d\n", x); return 0; }What is the output of this code snippet ?A. 27B. 26C. 25D. Compilation error...