简体   繁体   中英

Round with floor problem in Objective-C

I am calculating g with e and s, which are all doubles. After that I want to cut off all digits after the second and save the result in x, for example:

g = 2.123 => x = 2.12

g = 5.34995 => x = 5.34

and so on. I Use...

g = 0.5*e + 0.5*s;
x = floor(g*100)/100;

...and it works fine most of the time. But sometimes I get strange results. For example:

e = 3.0 s = 1.6 g = 2.30 but x = 2.29!!!

So I tried to track down the error:

g = 0.5*e + 0.5*s;
NSLog(@"%f",g);

gives me g = 2.30

g = g * 100;
NSLog(@"%f",g);

gives me g = 230.0

x = floor(g);
NSLog(@"%f",x);

results in x = 229.0 !!!

I don't get it! Help please! :-)

This will be due to floating point calculations.

Your calculation

g * 100

already brings back

229.99999999999997

From where your issue stems.

Have a look at INFO: Precision and Accuracy in Floating-Point Calculations

Also have a look at Floating point

Accuracy problems

The fact that floating-point numbers cannot precisely represent all real numbers, and that floating-point operations cannot precisely represent true arithmetic operations, leads to many surprising situations. This is related to the finite precision with which computers generally represent numbers.

As others have already mentioned, this is due to the limited precision of floating point numbers in computers. These imprecisions show up everywhere a hard yes/no decision about a floating point number is made. In order to resolve the problem, you can add/subtract a small number to find an answer that is correct up to a certain accuracy.

You may find functions like these useful:

#define ACC 1e-7

double floorAcc( double x ) { return floor(x + ACC);}
double ceilAcc( double x ) { return ceil(x - ACC); }
bool isLessThanAcc( double x, double y ) { return (x + ACC) < y; }
bool isEqualAcc( double x, double y ) { return (x + ACC) > y && (x - ACC) < y; }

Of course, these work only in a limited number range. When working with very small or very large numbers, you need to pick another value for ACC.

Note that the value of 'ACC' is in general dependent on the accuracy of the numbers in your application, not on the value of x. For example, comparing two numbers a and b for equality can be done in two ways: isEqualAcc(a, b) and isEqualAcc(ab, 0) . You would want the same result from both ways, even though in the second way the number x is likely much smaller.

Here is a possible approach using intermediate integer results:

double e = 3.0;
double s = 1.6;

NSInteger e1 = e * .5 * 100.0; // 150
NSInteger s1 = s * .5 * 100.0; // 80

double x = (e1 + s1)/100.0; // 2.3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM