-6

I was working with C and tried this :-

#include<stdio.h>
int main()
{
     float b=0.8,a=0.6;
     if(a&&b>=0.8)
     printf("\nclass")  ;
     else
     printf("\nb");
     return 0;
}

And the output came :-

class

But when I changed the value of b to 0.9 and expression in if to a&&b>=0.9 :-

#include<stdio.h>
int main()
{
     float b=0.9,a=0.6;
     if(a&&b>=0.9)
     printf("\nclass")  ;
     else
     printf("\nb");
     return 0;
}

then output was:-

b

Can anyone explain why >= operator started to act as > operator when the value of b was 0.9 ?

Thanks in advance.

Something to add as some guys think I am wasting their time :- I also tried to debug it as :-

    #include<stdio.h>
int main()
{
float b=0.9,a=0.6;
printf(" int a   -   %d\n", (int)a);
printf("int b -    %d\n", (int)b);
printf("a&&b  -   %d\n", a&&b);
printf("b>=0.9  -  %d\n", b>=0.9);
if(a&&b>=0.9)
printf("\nclass");
else
printf("\nb");
return 0;   
}

Now the O/p was :-

int a   -   0
int b -    0
a&&b  -   1
b>=0.9  -  0

Now please that "Precedence Guy" tell me what order of precedence would be followed in a single >= operator.

dknight
  • 267
  • 2
  • 9
  • 8
    what do you think `&&` does in your program? – n. m. could be an AI Sep 20 '15 at 17:23
  • 1
    On your machine `(float) 0.9f` is not as great as `(double) 0.9`. Both are approximations of 0.9, but since being binary representations, fail to be exact. The `double 0.9` is closer to mathematical 0.9 and different than `(float) 0.9f`. It is a coin flip in that `double 0.9` is greater than `(float) 0.9f`. – chux - Reinstate Monica Sep 20 '15 at 17:35
  • 1
    The nearest to 0.9 in double precision is 0.90000000000000002220446049250313080847263336181640625 but 0.89999997615814208984375 in single precision. Truncating the double value to float results in a value not closest to 0.9f. And `a&&b>=0.9` doesn't mean that "both a and b are larger or equal to 0.9" – phuclv Sep 20 '15 at 17:54

3 Answers3

2

Your code is equivalent to:

double x1 = 0.9;
float xf = (float)x1; // discard some precision
double x2 = (double)xf;

if (x2 >= x1) {
    // ...
}

The problem is that, after you discarded some precision from x1 by converting it to float, it can never be recovered; casting it back to double doesn't regain that precision. So x2 is still not the same as 0.9, and due to the rounding direction, it happens to be a bit less. (Note: if you try the same thing with other values, you will sometimes find that it's a bit more.)

ruakh
  • 175,680
  • 26
  • 273
  • 307
0

0.9 can't be exactly represented in binary .

And also importantly 0.9(being double) is first implicitly converted to float(less precesion) and then converted back to double(higher precession than float) does no remain excalty 0.9.

Therefore, the value of b is apporximately close to 0.9 not equal to 0.9. Therefore ,you get b.

ameyCU
  • 16,489
  • 2
  • 26
  • 41
  • I.e. equality might not work when you're using floating point numbers. – che Sep 20 '15 at 17:28
  • @che Yes , that's correct . – ameyCU Sep 20 '15 at 17:28
  • 1
    -1, sorry. It's true that `0.9` can't be exactly represented in binary, but the important point here is the conversion to `float` and back. Had the OP used `double` instead, (s)he would have seen the behavior (s)he expected. – ruakh Sep 20 '15 at 17:29
  • @ruakh Implicit conversion . Ahh , I overlooked it . Thanks for correcting me . I shall correct it . – ameyCU Sep 20 '15 at 17:32
  • @che why? it is working for all numbers except 0.9....whats so special in 0.9? – dknight Sep 20 '15 at 17:36
  • @ruakh But why does implicit conversion not affect the result in any other number except 0.9? – dknight Sep 20 '15 at 17:36
  • 1
    @dknight "it is working for all numbers except 0.9"? How many of the 18 quintillion `double` did you try? – chux - Reinstate Monica Sep 20 '15 at 17:38
  • @dknight: I'm sure you haven't tried all numbers. There are most probably more that don't work, you just haven't stumbled onto them. It's a matter of how they're stored in binary. – che Sep 20 '15 at 17:38
  • @chux yeah I didn't try all the numbers but still why are there such exceptions? – dknight Sep 20 '15 at 17:39
  • @che please convert 0.8 into binary...it is also a never ending binary number like 0.9 but >= works correctly there? Why is it so? 0.9= 0.111001100110... 0.8= 0.110011001100... – dknight Sep 20 '15 at 17:43
  • 1
    @dknight: If you change the `>=` to `==` (so as to detect roundoff error in *either* direction), you'll observe this behavior for 0.8 as well. – ruakh Sep 20 '15 at 17:45
  • 2
    @dknight it's not exception. It happens every time. Read http://floating-point-gui.de/ and [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html). And there's no way for you to test for all possible double values in this universe's time. – phuclv Sep 20 '15 at 17:45
  • thanks all...That solved it . – dknight Sep 20 '15 at 17:48
  • @dknight: Uh, ok. 0.8 is "\x9a\x99\x99\x99\x99\x99\xe9\x3f", 0.9 is "\xcd\xcc\xcc\xcc\xcc\xcc\xed\x3f". 0.8 converted to float and back to double is "\x00\x00\x00\xa0\x99\x99\e9\x3f". – che Sep 20 '15 at 17:50
0

Computers only know binary representation. It is able to represent decimal numbers in binary without a problem(and that changes with extremely large numbers too), but when it comes to fractional numbers it is not able to fully represent the number.

In binary each number is multiplied with 2 instead of 10 in decimal.

For example look at number 13

1*10^1 + 3*10^0

to represent the same number in binary system we need

1*2^3 + 1*2^2 + 0*2^1 + 1*2^0 = (1101)

But things get complicated at fractional parts. Again with an example:

13.26 = 13 + 2/10^1 + 6/10^2

but in binary

(1101) + 0/2^1 + 1/2^2 + 0/2^3 + 0/2^4 + 0/2^5 + 0/2^6 + 1/2^7 + 0/2^8 + 1/2^9 + ... = (1101.010000101....)

I hope this shows that it's not that easy to represent a fractional number with limited space.

Now, as soon as you declare your variables as floats, there's a limited space allocated for them and computer barely gets close to that fractional number. In the if condition you don't specify a type and compiler automatically chooses double over float which has more space and can represent the fractional number more accurately. In one case float represents the number bigger and in the other one it represents the number as smaller.

To fix that you can convert the literal to a float

float b = 0.9, a = 0.6;
if (a&&b >= (float)0.9)
    printf("\nclass");
else
    printf("\nb");
cin.get();
return 0;

which will output

\nclass

Mert Can Ergün
  • 399
  • 5
  • 14