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 ?

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. Commented Jun 2, 2014 at 19:48
  • 3
    en.wikipedia.org/wiki/Floating_point#Accuracy_problems Commented Jun 2, 2014 at 19:48
  • Please just search for the paper What Every Computer Scientist Should Know About Floating-Point Arithmetic and read it. Commented Jun 3, 2014 at 3:51

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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 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.
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, stackoverflow.com/a/7662210/991920
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)

4 Comments

i tried but the same output is coming
c# is the right result, not c, its more important that this fix is made to the 0.9 case
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.
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.
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.

4 Comments

is there any difference b/w less than and equivalence comparison ?
@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.
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.
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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.