问题
I am having issue with rounding a float in iPhone application.
float f=4.845;
float s= roundf(f * 100.0)/100;
NSLog(@"Output-1: %.2f",s);
s= roundf(484.5)/100;
NSLog(@"Output-2: %.2f",s);
Output-1: 4.84
Output-2: 4.85
Let me know whats problem in this and how to solve this.
回答1:
The problem is that you don't yet realise one of the inherent problems with floating point: the fact that most numbers cannot be represented exactly (a).
This means that 4.845
is likely to be, in reality, something like 4.8449999999999
which, when you round it, gives you 4.84
rather than what you expect, 4.85
.
And what value you end up with also depends on how you calculate it, which is why you're getting a different result.
And, of course, no floating point "inaccuracy" answer would be complete on SO without the authoritative What Every Computer Scientist Should Know About Floating-Point Arithmetic.
(a) Only sums of exact powers of two, within a certain similar range, can be exactly rendered in IEEE754. So, for example, 484.5
is
256 + 128 + 64 + 32 + 4 + 0.5
(28 + 27 + 26 + 25 + 22 + 2-1
).
See this answer for a more detailed look into the IEEE754 format.
As to solving it, you have a few choices. One is to use double
instead of float
. That gives you more precision and greater range of numbers but only moves the problem further away rather than really solving it. Since 0.1
is a repeating fraction in IEEE754, no amount of bits (short of infinity) can exactly represent it.
Another choice is to use a custom library like a big decimal type, which can represent decimals of arbitrary precision (that's not infinite precision as some people are wont to suggest, since it's limited by memory). This will reduce the errors caused by the binary/decimal mismatch.
You may also want to look into NSDecimalNumber
- this doesn't give you arbitrary precision but it does give a large range with accurate decimal representation.
There'll still be numbers you can't represent, like PI or the square root of 2 or any other irrational number, but it should cover most cases. If you really need to handle those other values, you need to switch to symbolic numeric representations.
回答2:
Unlike 484.5
which can be represented exactly as a float* , 4.845
is represented as 4.8449998
(see this calculator if you wish to try other numbers). Multiplying by one hundred keeps the number at 484.49998
, which correctly rounds to 484
.
* An exact representation is possible because its fractional part
0.5
is a power of two (i.e. 2^-1
).
来源:https://stackoverflow.com/questions/15446902/ios-rounding-a-float-with-roundf-is-not-working-properly