Unexpected behavior of floating point numbers in C [duplicate] - c

This question already has answers here:
Why are floating point numbers inaccurate?
(5 answers)
Closed 8 years ago.
I have a simple C snippet as follows:
#include<stdio.h>
#include<conio.h>
int main()
{
float a=0.3,b=0.5
clrscr();
if(a==0.3)
{
printf("equal");
}
else
{
printf("unequal");
}
if(b==0.5)
{
printf("equal");
}
else
{
printf("unequal");
}
getch();
}
shows output as: unequal equal.
I understand this because computer takes 0.3 as 1/3 and as 0.333... is not equal to 0.33, it shows output unequal, while in 0.5 is precise number so it gives output as equal.
But now if I take float b=0.2 like this:
float b=0.2;
if(b==0.2)
{
printf("equal");
}
else
{
printf("unequal");
}
Then it also shows unequal as output! As 0.2 is 1/5 - precise value, it should give output equal.
Can anyone tell me if anything is wrong here?

Simplifying somewhat, floating point numbers are basically stored as a series of fractions of powers of 2. (1/2, 1/4, 1/8, 1/16, 1/32, 1/64, etc). If your number can be represented as the sum of some number of those, you are lucky -- for most numbers (1/3, 1/5, etc) you get a pretty close approximation. Comparing floating point numbers for exact equality is fraught with peril.

Related

equality of two float numbers in for loop [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 5 years ago.
What I am trying to do here is, I am taking a precision value (less than 1) and printing count of all the numbers of type 1/n (n is natural number) which are greater than or equal to the precision value (input).
#include <stdio.h>
int main(){
int i=1,terms=0;
float n;
printf("Enter precision value : ");
scanf("%f",&n);
while(i>0){
if ((1.0/i) >= n){
printf("%f\n",1.0/i);
sum = sum + (1.0/i);
terms++;
i++;
}
else
break;
}
printf("number of terms : %d\n",terms);
return 0;
}
But if I give input 0.1 than the count (output) is showing only 9. but it should show 10 (it is not including 1/10).
I was using a for loop before and I know that breaking a loop with an if-else statement is not the best thing.
That's just the way math works with limited precision. For example, say you're using six digits of decimal precision. The best you can do for one-third is 0.333333 and the best you can do for 2/3 is 0.666667, but then 2 * 1/3 will not equal 2/3. And 3 * 1/3 will not equal 1. But 1/3 + 2/3 will.
Just as 1/3 cannot be expressed exactly in decimal, 0.1 cannot be expressed exactly in binary. So testing for equivalence is not smart.

Comparison of a float with a value in C [duplicate]

This question already has answers here:
strange output in comparison of float with float literal
(8 answers)
Closed 5 years ago.
I have come across two programs in C, both comparing floating point number but with different outputs.
1)
#include<stdio.h>
int main()
{
float x = 0.1;
if (x == 0.1)
printf("IF");
else if (x == 0.1f)
printf("ELSE IF");
else
printf("ELSE");
}
Output : ELSE IF
2)
int main()
{
float x = 0.5;
if (x == 0.5)
printf("IF");
else if (x == 0.5f)
printf("ELSE IF");
else
printf("ELSE");
}
Output : IF
why 0.5 is not promoted to double whereas 0.1 is?
Since double is wider than float, x == 0.1 is interpreted as (double) x == 0.1.
This works for 0.5 because 0.5 is exactly representable in binary, so (double) 0.5f produces precisely 0.5. On the other hand, 0.1 has an infinite-digit representation in binary, and 0.1f and 0.1 end up being rounded to numbers that differ in how many initial digits of the sequence they hold.
In an analogy with decimal numbers, you can think of the above situation as trying to write down the fraction 1/3 by rounding it to a fixed number of decimal digits. Using a 5-significant-digit representation, you get 0.33333; choosing a 10-digit one results in 0.3333333333. Now, "casting" the five-digit number to ten digits results in 0.3333300000, which is a different number than 0.3333333333. In the same analogy, 0.5 in is like 1/10 in decimal, which would be represented as 0.10000 and 0.1000000000 respectively, so one could convert it to the other representation and back without changing its meaning.
If the contents of x is a marker value set from code, then simply compare it to 0.1f instead of to 0.1. If it is the result of a calculation, see Paul's answer for the correct way to compare floating-point quantities.
The proper way of comparing one floating point number with another is by using a precission value, for example
#define EPS 0.00001
#define ABS(a) ((a)<0?-(a):(a))
if (ABS(a-b)<EPS)
...
This is derived from:
if (a == b) // "equal" of fp numbers is not well defined
if (a-b == 0) // so comparing with zero is also ill defined
if (ABS(a-b) < EPS) // and so we compare with this small precission

adding numbers in a for loop [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 6 years ago.
I tried to sum some numbers in a for loop but it didn't go as I expected
float sum = 0;
int i;
printf("0.1+0.1=%f\n", 0.1 + 0.1);
for (i = 0; i<1000000; i++)
{
sum = sum + 0.1;
}
printf("the sum need to be 100000 \n");
printf("the real sum is:\n %f\n", sum);
system("PAUSE");
this program prints:
0.1+0.1=0.200000
the sum need to be 100000
the real sum is:
100958.343750
Press any key to continue . . .
can you explain please this strange result?
the international standard for floating point numbers does not have an exact representation for some decimal numbers.
http://en.wikipedia.org/wiki/IEEE_754
It is due to the way they are stored in memory, the way the mantissa and exponent are stored.
https://en.wikipedia.org/wiki/Floating_point
This is also the reason why you should never compare two float numbers even if they look "the same".
I still remember how surprised I was the fist time a simple code comparing two float numbers didn't work :) This alone would open a dedicated universe of discussions. It is very worth reading anyway:
http://floating-point-gui.de/errors/comparison/
The floating numbers are stored in memory as x*2^y where x is between 0 and 1 with some precision and y is integer and so they accurately don't represent most numbers, they represent numbers "close enough".
When you do this addition multiple times, the error is just more visible.
You can use double type for better accuracy.

In C, why is the ratio 10.0/100 different from 0.1? [duplicate]

This question already has answers here:
Why Floating point numbers cant be compared? [duplicate]
(7 answers)
Closed 7 years ago.
This is a simple question and I searched the forums, but couldn't find an answer (I found one about Log but I don't think there is a rounding error here).
I wrote a program to determine the value of a fine for a range of expired products, but when the ratio is exact, the program will return the next fine category, ignoring the = sign in the conditional.
The program must return the following fines:
0 if no product is expired.
100 if up to 10% of products are expired.
10000 if more than 10% of products and up to 30% are expired.
100000 if more than 30% of products are expired.
This is the code I wrote:
#include <stdio.h>
int calculate_fine(int ncheckedproducts, int nexpiredproducts)
{
int fine;
float ratio;
ratio=(float)nexpiredproducts/ncheckedproducts;
if(nexpiredproducts==0)
fine=0;
else
if(ratio<=0.1)
fine=100;
else
if(ratio<=0.3)
fine=10000;
else
fine=100000;
return fine;
}
int main(void)
{
int ncheckedproducts, nexpiredproducts, fine;
printf("Type number of checked and expired products\n");
scanf("%d %d", &ncheckedproducts, &nexpiredproducts);
fine=calculate_fine(ncheckedproducts, nexpiredproducts);
printf("The fine is: %d\n", fine);
return 0;
}
But for values of 100 and 10, and 100 and 30, exactly 10% and 30% of expired products respectively, the program will return the wrong fine.
The teacher failed to explain me why, and corrected me to the following function:
int calculate_fine(int ncheckedproducts, int nexpiredproducts)
{
int fine;
if(nexpiredproducts==0)
fine=0;
else
if(nexpiredproducts<=0.1*ncheckedproducts)
fine=100;
else
if(nexpiredproducts<=0.3*ncheckedproducts)
fine=10000;
else
fine=100000;
return fine;
}
However, I wish to know why the first 10% ratio is greater than 0.1, and why I cannot use this approach.
This most probably is a rounding issue, but a different than you might think: Many finite decimal fractions do not have a finite binary fraction representation. Thus, some rounding the the closest number representable as a floating point number of the given type happens.
What you're dealing with is are the fine-grained aspects of floating point numbers:
Computers save floating point numbers in a binary format. Your float is probably a IEEE-754 single precision floating point number.
In those formats, you can typically represent only numbers exactly that are only a sum of a very limited amount of powers of two; for example, 0.75 is 2-1 + 2-2 and can hence be exactly reconstructed. In your case, you try to divide 100 = 26 + 25 + 22 by 3 = 21+20 and hope you get exactly the same result as 0.3 = 2-2+ 2-5+ 2-9+ 2-10+ 2-13+ ...
That won't happen.

Equality test and accuracy of machine [duplicate]

This question already has answers here:
Floating point inaccuracy examples
(7 answers)
C++ floating point precision [duplicate]
(5 answers)
Closed 8 years ago.
I found this code snippet on Page 174, A Book on C -Al Kelley, Ira Pohl .
int main()
{
int cnt=0; double sum=0.0,x;
for( x=0.0 ;x!= 9.9 ;x+=0.1)
{
sum=sum +x;
printf("cnt = %5d\n",cnt++);
}
return 0;
}
and it became a infinite loop as the book said it would. It didnt mention the precise reason except saying that it had to do with the accuracy of the machine.
I modified the code to check if
x=9.9
would ever become true, i.e. x was attaining 9.9 by adding the following lines
diff=x-9.9;
printf("cnt =10%d \a x =%10.10lf dif=%10.10lf \n",++cnt,x,diff);
and i got the following lines among the output
cnt =1098 x =9.7000000000 dif=-0.2000000000
cnt =1099 x =9.8000000000 dif=-0.1000000000
cnt =10100 x =9.9000000000 dif=-0.0000000000
cnt =10101 x =10.0000000000 dif=0.1000000000
cnt =10102 x =10.1000000000 dif=0.2000000000
if x is attaining the value 9.9 exactly , why is it still a infinite loop?
You are simply printing the number with too poor accuracy to notice that it isn't exact. Try something like this:
#include <stdio.h>
int main()
{
double d = 9.9;
if(d == 9.9)
{
printf("Equal!");
}
else
{
printf("Not equal! %.20f", d);
}
}
Output on my machine:
Not equal! 9.90000000000000035527
The book is likely trying to teach you to never use == or != operators to compare floating point variables. Also for the same reason, never use floats as loop iterators.
The problem is that most floating point implementation are based on IEEE 754. See http://en.wikipedia.org/wiki/IEEE_floating_point
The problem with this is, that numbers are builded with base 2 (binary formats).
The number 9.9 can never be build with base 2 excatly.
The "Numerical Computation Guide" by David Goldberg gves an exact statement about it:
Several different representations of real numbers have been proposed,
but by far the most widely used is the floating-point representation.
Floating-point representations have a base b (which is always assumed to
be even) and a precision p. If b = 10 and p = 3, then the number 0.1 is
represented as 1.00 × 10^-1. If b = 2 and p = 24, then the decimal
number 0.1 cannot be represented exactly, but is approximately
1.10011001100110011001101 × 2^-4.
You can safely assume two floating point numbers are never equal 'exactly' (unless one is a copy of the other).
Computer works on binary and floating point, in other words in base 2. Just like base 10, base 2 have numbers that it cannot build. For example, try to write the fraction 10/3 in base 10. You'll end up with infinite 3s. and in Binary, you cannot even write 0.1 (decimal) in binary, you'll also get a recurring pattern 0.0001100110011... (binary).
This video will do better to explain http://www.youtube.com/watch?v=PZRI1IfStY0

Resources