0
float a = 0.7;
if(a<0.7)
  printf("true");
else
  printf("false");

OUTPUT : true

Now , if I change the value of a to say 1.7 ,then

float a = 1.7;
if(a<1.7)
  printf("true");
else
  printf("false");

OUTPUT : false

Since 0.7 is treated as a double (HIGH PRECISION) and a is a float (LESS PRECISION) , therefore a < 0.7 , and in second case it should be the same again , so it should also print true. Why the difference in output here ?

PS : I have already seen this link.

Community
  • 1
  • 1
h4ck3d
  • 6,134
  • 15
  • 51
  • 74

4 Answers4

5

Since you saw my answer to the question you linked, let's work through it and make the necessary changes to examine your second scenario:


In binary, 1.7 is:

b1.1011001100110011001100110011001100110011001100110011001100110...

However, 1.7 is a double-precision literal, whose value is 1.7 rounded to the closest representable double-precision value, which is:

b1.1011001100110011001100110011001100110011001100110011

In decimal, that's exactly:

 1.6999999999999999555910790149937383830547332763671875

When you write float a = 1.7, that double value is rounded again to single-precision, and a gets the binary value:

b1.10110011001100110011010

which is exactly

 1.7000000476837158

in decimal (note that it rounded up!)

When you do the comparison (a < 1.7), you are comparing this single-precision value (converted to double, which does not round, because all single-precision values are representable in double precision) to the original double-precision value. Because

 1.7000000476837158 > 1.6999999999999999555910790149937383830547332763671875

the comparison correctly returns false, and your program prints "false".


OK, so why are the results different with 0.7 and 1.7? It's all in the rounding. Single-precision numbers have 24 bits. When we write down 0.7 in binary, it looks like this:

b.101100110011001100110011 00110011...

(there is space after the 24th bit to show where it is). Because the next digit after the 24th bit is a zero, when we round to 24 bits, we round down.

Now look at 1.7:

b1.10110011001100110011001 10011001...

because we have the leading 1., the position of the 24th bit shifts, and now the next digit after the 24th bit is a one, and we round up instead.

Community
  • 1
  • 1
Stephen Canon
  • 103,815
  • 19
  • 183
  • 269
  • I did read it , but i didn't do the base conversion on paper , so I was under a notion that the binary value would always be greater. Anyway , thanks for the explanation. – h4ck3d Aug 19 '12 at 14:55
4

If float and double are IEEE-754 32 bit and 64 bit floating point formats respectively, then the closest float to exactly 1.7 is ~1.7000000477, and the closest double is ~1.6999999999999999556. In this case the closest float just happens to be numerically greater than the closest double.

caf
  • 233,326
  • 40
  • 323
  • 462
3

0.7 and 1.7 aren't represented the same way in base-2 - so the one might be slightly more and the other slightly fewer than the actual (exact) value.

  • So , can we say this is undefined behavior? Or compiler dependent? – h4ck3d Aug 19 '12 at 13:39
  • @sTEAK. it's not UB - if it was, it could crash. It's implementation dependent. –  Aug 19 '12 at 13:41
  • But 1.7 in base 2 with less precision (float) has to be lesser than 1.7 (double precision) . How can it be `slightly more` ? – h4ck3d Aug 19 '12 at 13:43
  • 3
    @sTEAK: Converting to a narrower precision does not merely truncate bits. It rounds. So if a value is 101.00011010 in binary, and we want to narrow to the fourth digit after the radix point, then we are removing the 1010 at the end. That 1010 is more than half the value of the previous bit, so we round up. That is, we take the remaining bits, 101.0001, and add 1 to the last bit (so we add .0001), producing 101.0010. Similarly, when rounding 1.7 to double to float, the removed bits are more than half the last remaining bit, so it is rounded up. – Eric Postpischil Aug 19 '12 at 14:58
  • Technically, the behavior is implementation dependent with respect to the C standard. However, most common C implementations use IEEE 754 floating-point, at least for normal situations of basic operations. Given this, the behavior is defined; it will be the same on different platforms that use C with IEEE 754. – Eric Postpischil Aug 19 '12 at 15:02
  • @Eric yes, that's what I'm saying - it's not UB. –  Aug 19 '12 at 15:15
1

It all has to do with base 2 representation of floating-point. Here is a good reference about the subject: What Every Computer Scientist Should Know About Floating-Point Arithmetic.

awm
  • 1,130
  • 3
  • 17
  • 37
  • -1 Linking to this document does not constitute an answer, despite it being a canonical reference. At best it's a comment. – Stephen Canon Aug 19 '12 at 15:03