0

Please explain the output for different cases

#include<stdio.h>
int main()
{
    float a=5.9; //a=0.9
    if (a==5.9)
        printf("Equal");
    else if (a<5.9)
        printf("Less than");
    else
        printf("Greater than");
    return 0;
} 

When a is 5.9 the output is "Greater than", when a is 0.9 the output is "Less than". Why?

Sebastian
  • 7,670
  • 5
  • 38
  • 50
Utkarsh Srivastav
  • 3,105
  • 7
  • 34
  • 53
  • 3
    It's all in here : http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html – Steve Fallows Mar 05 '13 at 01:03
  • do you know how to write 5.9 in base 2? – perreal Mar 05 '13 at 01:03
  • 1
    http://ideone.com/GAZxtv – Rapptz Mar 05 '13 at 01:07
  • avoid using equals with floats as a general rule. Unless otherwise specified when you hardcode a value (the 5.9 in the comparisons) like this the C language uses double as a default so a has to be converted from single to double which changes its value. The single is less precise when converted originally or converted runtime rounding applies and depending on the rounding mode a can be less than 5.9 or greater than 5.9. Like comparing whole numbers to numbers that can hold one decimal point the lesser precise number would hold the rounded up 6 and more precise 5.9 thus the results you found – old_timer Mar 05 '13 at 01:47
  • The computer based floating point numbers use binary, base 2, your text uses base 10 there is a conversion. And there are only so many digits allowed per format. For example say you had the number 5/11 stored in decimal but you only have so many digits. say a 3 digit format you could hold .454 but you round up (due to the next number being a 5) to be more accurate to .455, the 6 digit is .454545 and you dont round up (next number is a 4), to do a comparison you get .455000 compared to .454545 and the .455000 is larger – old_timer Mar 05 '13 at 01:58
  • .454545 is more precise than .455000 as well. This is also why the equals fails. If you were to change all the 5.9s to 5.9F and re-compile you will likely get the result you were expecting. In the above it would be like comparing .455 to .455 in each case, apples to apples, same rounding applied to all. adding the F to the end of the hardcoded number is like using a typecast on variables, it tells the compiler to use single precision. – old_timer Mar 05 '13 at 02:02

6 Answers6

3

In C, the literal “5.9” has type double and is converted by common compilers to 5.9000000000000003552713678800500929355621337890625, because they use binary IEEE-754 floating point, and that number is the value representable as a double that is closest to 5.9. Your code initializes a float with that value. That requires converting a double to a float, and the result is 5.900000095367431640625, because that is the float value that is closest to the double value. Obviously, the latter is greater than the former, which is why your output is “Greater than”.

With .9, the literal “.9” is converted to the double 0.90000000000000002220446049250313080847263336181640625. Then that double is converted to the float 0.89999997615814208984375, which is obviously less than the double.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • you are assuming a rounding mode. IEEE supports three modes, round down and round to zero would have made the number 5.8something the equal would still fail but the less than would have passed. True that we commonly use round up causing an add of 1 to the lsbit of the mantissa during the original conversion making in one or both cases the stored number to be slightly larger than 5.9. – old_timer Mar 05 '13 at 01:51
  • 2
    @dwelch: IEEE 754 specifies four modes (round-to-nearest, round-toward-zero, round-toward-infinity, round-toward-negative-infinity). Round-to-nearest is the common mode, and it is deducible from the behavior reported in the question that round-to-nearest is in use, since the double near 5.9 rounded up (when converted to float) and the double near .9 rounded down. None of the other rounding modes would produce that behavior. Neither rounding up nor adding 1 to the LSB of the significand (not mantissa) is a common default mode. – Eric Postpischil Mar 05 '13 at 01:54
1

Your variable is a float but the constant is a double. Since that value can't be stored precisely ti will be stored differently as a float and as a double. If you use the same data types you'll get the desired results

http://codepad.org/1q5mwFGd

http://codepad.org/Q4lOQnG8

Musa
  • 96,336
  • 17
  • 118
  • 137
0

Floating point numbers are inherently imprecise. For a quick introduction, you can read up a bit here. http://floating-point-gui.de/errors/comparison/

For some suggestions on effective comparison strategies, see this post. What is the most effective way for float and double comparison?

Community
  • 1
  • 1
Eric Johnson
  • 696
  • 4
  • 23
  • This does not answer the question, since it does not explain the results. It advocates giving up on doing either accurate or controlled arithmetic with floating point and promotes a blanket comparison technique that is not suitable for all applications. – Eric Postpischil Mar 05 '13 at 01:08
0

This is because internally, the floating point numbers are stored in binary form and 5.9 can't be represented exactly as 5.9. Have a look at the following similar question and answer: Why does a C floating-point type modify the actual input of 125.1 to 125.099998 on output?

Community
  • 1
  • 1
Engineer3003
  • 411
  • 4
  • 3
0

When comparing floating-point numbers it is best to avoid '=='.

This because some values cannot be correctly stored without some loss of precision.

So it is better to say:

if( fabs(a-5.9) < .0001 ) {
    // 'EQUAL' or at least near enough!
}

I know this takes more to compute, but it will behave the way you expect.

Dave Lowerre
  • 128
  • 14
  • While your advice is generally helpful, there is no conversion back and forth between float and double and thus no information is truly lost. Since these are literal values it's not comparing them properly because there is a difference in the types, i.e. comparing doubles against floats. – Rapptz Mar 05 '13 at 01:12
  • 2
    This does not answer the question, since it does not explain the results. It advocates giving up on doing either accurate or controlled arithmetic with floating point and promotes a blanket comparison technique that is not suitable for all applications. – Eric Postpischil Mar 05 '13 at 01:14
  • Never using equal for floating point is suitable for almost all applications, the prime exceptions are those are cases where you are testing floating point units (Hauser, etc). How you get equal like code of course varies based on the application and range of the numbers, etc. The OP starts off by breaking this rule, +1 for this answer for that reason, then the OP uses a float to double conversion perhaps not knowing that C uses doubles for floating point unless otherwise specified (changing to 5.9F for the hardcodings likely would have changed the outcome). – old_timer Mar 05 '13 at 01:21
  • @dwelch: Unfortunately, this answer does not merely advocate “never using equal”. It advocates comparing using a lax value for absolute error. This fails to establish a basis for the error bound, fails to adapt to situations in which relative error or other criteria are more suitable, and fails to consider the consequences of falsely accepting as equal results that are not equal. Generally, when we want to test for equality, we also want to know about inequality, and you cannot just change one into the other without consequences. – Eric Postpischil Mar 05 '13 at 01:25
  • yep, I understand all of that, your answer is interesting but fails to point out the posters other major problem. nor did you point out why C converts to double, not a common thing but a spec thing. nor did you point out how to get around the problem. So you technically answered the letter of the question, the why, but really are not helping the person asking the question as far as writing good or at least working floating point code. Dave here is at least trying to give some advice (while, true, not answering the why with enough detail) – old_timer Mar 05 '13 at 01:40
  • @dwelch: What problem? The questioner did not state a problem other than this specific comparison. You are assuming they want to do things they did not state. Instead of assuming, I explained what they asked, which shows a bit of how floating point works. That is a starting point; they can ask additional questions as needed. The advice is this answer is **bad**; it causes bugs by making applications falsely accept as equal values that are not equal and that would not be equal even if calculated exactly. – Eric Postpischil Mar 05 '13 at 01:51
  • Eric your answer is certainly more 'correct' than mine. Mine, however, has served me well for over thirty years. For Example: when looking for a change in an input, say a measurement of latitude from an inertial navigator, it is best to establish some delta and test for at least that much change. This is a very practical approach. In this case 'delta' could be determined by the resolution of the input but more likely would reflect how much change I want to see before I update my position. – Dave Lowerre Mar 06 '13 at 19:30
0

Due to decimal binary conversion, 0.9 represented as a summation of powers of 2^-1:

0.9 - (0.5 + 0.25 + 0.125) = 0.025

But 0.025 is not an exact power of 2^-1. So you need to represent both numbers in the comparison with the same precision. Since float and double have different precision they compare not equal.

perreal
  • 94,503
  • 21
  • 155
  • 181