问题
I am looking into rounding floating point numbers in Python and the following behavior seems quite strange:
Code:
a = 203.25
print '%.2f'%(a/10.)
print '%.2f'%(round(a/10., 2))
print '%.2f'%(0.1*a)
Output:
20.32
20.32
20.33
Why does the first and especially the second case fail?
回答1:
http://en.wikipedia.org/wiki/Rounding#Round_half_to_even
Round half to even
A tie-breaking rule that is less biased is round half to even, namely:If the fraction of y is 0.5, then q is the even integer nearest to y. Thus, for example, +23.5 becomes +24, as does +24.5; while −23.5 becomes −24, as does −24.5.
This method treats positive and negative values symmetrically, and is therefore free of sign bias. More importantly, for reasonable distributions of y values, the expected (average) value of the rounded numbers is the same as that of the original numbers. However, this rule will introduce a towards-zero bias for even numbers, and a towards-infinity bias for odd ones.
This variant of the round-to-nearest method is also called unbiased rounding, convergent rounding, statistician's rounding, Dutch rounding, Gaussian rounding, odd-even rounding or bankers' rounding, and is widely used in bookkeeping.
This is the default rounding mode used in IEEE 754 computing functions and operators.
>>> "%.2f"%20.325
'20.32'
>>> "%.2f"%20.335
'20.34'
>>> "%.2f"%20.345
'20.34'
>>> "%.2f"%20.355
'20.36'
So the real question should be why does the third case fail?
203.25
can be expressed exactly in the floating point representation, however 0.1
cannot, it turns out to be a tiny bit more than 0.1
>>> 0.1*203.25
20.325000000000003
So it gets rounded up
回答2:
This probably is part of the answer:
>>> a*.1
20.325000000000003
>>> a/10
20.325
See @gnibblers explanation about how IEEE 754 rounding is implemented.
回答3:
I don't know the specific details about why those cases don't work as expected, but if you want strict accuracy with your floats, use something like the decimal module.
回答4:
There is no fail. See What Every Programmer Should Know About Floating-Point Arithmetic.
回答5:
You can use printf to see what's happening
print '%0.20f'%20.325
20.32499999999999928946
回答6:
The Python docs for round() point to the answer. Basically, floating point can't represent some numbers exactly. For instance, 0.1
ends up looking like 0.10000000000000001
. This imprecision can sometimes lead to unexpected results. It's really quite difficult to get calculations within a given range of tolerance with floating point numbers. The reason the 0.1 * a
calculation works in your case, is because it's ever so slightly biased in your desired direction of rounding.
If you really need precision, you should look at using the Decimal module. Working with decimal numbers can also be a chore, but it does make it a bit easier to get the precision you desire.
来源:https://stackoverflow.com/questions/12258729/why-does-this-happen-when-rounding-floating-numbers-in-python