Possible Duplicate:
Trouble with floats in Objective-C
It might sound to you like a basic issue, but I’m trying for 2 days to figure it out.
I searched for a solution and the only explanation I found is that float uses only 4-bytes of memory. (that’s helpful…)
I have the following loop:
double x = 0.0;
for(int i = 0; i< 100; i++)
{
x = x + 0.01;
NSLog(@"%f",x);
}
and it prints:
0.010000
0.020000
0.030000
.
.
1.000000
but when I change the double to float:
0.010000
0.020000
0.030000
.
.
0.820000
0.830000
0.839999
0.849999
.
.
0.999999
As you can see, the computer can’t calculate 0.840000 as float -_-
The problem is that I have to use float because I’m using the UIProgressView that can take a float number between 0.0 to 1.0.
If I can’t use double, what can I do?
Thanks.
What if you wrote the following code:
you wouldn’t be surprised that it doesn’t print out
3.5,7.0,10.5, right? Would you say that “int is inaccurate”? Of course not.Exactly the same thing is happening in your example. Just like
3.5isn’t representable as an integer,0.01isn’t representable as a double. The actual value you get is:Now, you accumulate not only the initial representation error from rounding
0.1to double, but you also get rounding errors because not all of the intermediate sums are representable. This second source of error does not occur in theintexample. The actual intermediate sums that are computed are:when you round these to six decimal places via the
%fformat specifier, you get yet a third source of rounding, but the errors are all small enough that the results you “expect” are printed out.Now let’s look at what happens when you use
floatinstead ofdouble; because of the C arithmetic operand promotion rules, the additions are all carried out indouble, but the result is rounded back tofloatafter each addition — yet another rounding. The sequence of intermediate values is as follows:Up to this point, the errors are small enough that they all still produce the “expected” value when rounded to six decimal digits. However, the next value computed is
Because this is just smaller than the exact halfway case for rounding to six decimal digits:
it rounds down, and the number that is printed is:
Now, what can you do about it? The reason that the errors eventually become large enough to appear when printed with six decimal digits is that you are accumulating error with each sequential addition. If you can avoid this accumulation, the error will remain small enough to not cause this trouble. There are a several easy ways to avoid this cumulative error; perhaps the easiest is:
This works because both
i + 1and100.fare exactly represented infloat. There is thus only a single rounding, which occurs in the division, so thefloatresult is as close to your desired number as possible; there is no way you can come any closer.