5

case 1

float a = 0.6;

if (a < 0.6)
{
    printf("c");
}
else
{
    printf("c#");
}

output c#

case 2

float a = 0.9;

if (a < 0.9)
{
    printf("c");
}
else
{
    printf("c#");
}

output c

now question is why ?

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
Dios
  • 63
  • 1
  • 1
  • 3
  • 1
    That code won't even compile. It's `if` not `If` Also it's not formatted well for us to see what's going on. – Almo Jun 02 '14 at 19:48
  • 3
    http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems – Andrew Jun 02 '14 at 19:48
  • Please just search for the paper *What Every Computer Scientist Should Know About Floating-Point Arithmetic* and read it. – Kaz Jun 03 '14 at 03:51

3 Answers3

8

I'm assuming float is IEEE 754 32-bit binary, and double is IEEE 754 64-bit binary.

The closest double to 0.6, the actual value of the literal, is 0.59999999999999997779553950749686919152736663818359375. The result of converting it to float is 0.60000002384185791015625, slightly bigger.

The closest double to 0.9 is 0.90000000000000002220446049250313080847263336181640625. The result of converting it to float is 0.89999997615814208984375, slightly smaller.

In each case, a decimal fraction that cannot be represented exactly is rounded to the nearest double to represent the literal. It is rounded to a float for assignment to a, which under round-to-nearest rules may be slightly smaller or slightly greater than the double, or even could be exactly the same if the double's binary representation had a lot of trailing zeros.

Patricia Shanahan
  • 25,849
  • 4
  • 38
  • 75
  • Then shouldn't the 0.9 on the RHS of the relational operator also be the equal to 0.89999997615814208984375 as well? If so then shouldn't they be equal? – Ganz7 Feb 12 '16 at 07:14
  • @Ganz7 The 0.9 is a double, not a float, so its exact value is 0.90000000000000002220446049250313080847263336181640625. The float < double comparison is done by converting the float to double, which does not change its value, not by converting the double to float. – Patricia Shanahan Feb 12 '16 at 07:30
  • That makes sense now. I tried running it on an online IDE, and it made no difference when I used a float literal (0.9f) or a double (0.9). Turns out some hardware may convert it into double anyway as stated in this answer, http://stackoverflow.com/a/7662210/991920 – Ganz7 Feb 12 '16 at 07:33
0

The short answer: floating point numbers can't be represented exactly with a binary notation, even if they have a terminating definition in decimal. That means that comparing a float to another, supposedly equal float, isn't guaranteed to go either way, everything depends on the architecture and the representation of floats on that architecture.

  • is there any difference b/w less than and equivalence comparison ? – Dios Jun 02 '14 at 20:03
  • @Dios Not as far as comparing two floats go, in being sure that they work as you expect. Both depend on the binary representation, so both are subject to the same problems. But with floats in this range of precision in the example an less than comparison between two different floats, of different value, will work as you expect, while a equal comparison probably won't. – David Högberg Jun 02 '14 at 20:08
  • 1
    The correct answer to the question is not “floating-point are inexact, don't compare them”. There are no floating-point computations in the question and for a given C99 compiler, it is perfectly predictable what the program's result will be. – Pascal Cuoq Jun 02 '14 at 21:55
  • The correct answer was to explain, how precision was lost double (float(0.6)) != double (0.6). The point about inexact representation in binary of common decimal fractions like in examples, was most of way there. – Rob11311 Jun 02 '14 at 22:42
0

Change the whole thing to only use single literals, and it should always work

float a = 0.6f;

if (a < 0.6f)
{
    printf("c");
}
else
{
    printf("c#");
}

The error actually has nothing to do with accuracy problems, and everything to do with type promotion. This is sorta equivalent to shoving 300 into a char, and then comparing the result with the real integer 300. When you first shoved it in, the value got truncated to fit in the smaller type, and during the comparison it got promoted back to the bigger type.

Edit

The accuracy problems that everyone is talking about here, are a different phenomenon. You can see it manifest with the boolean expression (4.0*3.0 == 2.0*6.0) clearly both terms are 12.0 but the different truncation of 3.0 and 6.0 can make these two arithmetic expressions differ. If however you wrote the expression (3.0*5.0 == 3.0*5.0) this is always guaranteed to be true for any conforming processor.(N.B. for many processors including intel, you can manipulate the configurations so they don't conform to the IEEE floating-point standard)

Steve Cox
  • 1,947
  • 13
  • 13
  • i tried but the same output is coming – Dios Jun 02 '14 at 20:07
  • c# is the right result, not c, its more important that this fix is made to the 0.9 case – Steve Cox Jun 02 '14 at 20:11
  • 1
    Loss of precision, is the reason why! The incorrect program is far more educational than the coerced "right" result version. A float is less accurate than a double, so if a fraction is not representable exactly in binary then is converted to double, may mean it's a little bit smaller or bigger than it ought to be. Avoid conversions with loss of precision and consider rounding errors when making floating point comparisions. – Rob11311 Jun 02 '14 at 22:34
  • A better analogy is folding, 'A'..'Z' to random letter between 'k'..'o' and 'a'..'z' to 'o'..'k', then comparing the result to 'm'. The results tell you the original input was between A..Z & a..z but not exactly what you started with. – Rob11311 Jun 02 '14 at 22:55