[Tutor] floating point rounding inconsistency
steve at pearwood.info
Sat Sep 29 05:02:56 CEST 2012
On 29/09/12 11:30, Alan Gauld wrote:
> On 28/09/12 13:15, Mark Lawrence wrote:
>> from Calvin Spealman is typical "Also, I'd be completely in support of
>> dropping round() and agree it gets misused
>> and leads to too much confusion. We should promote the right ways, and
>> sometimes to show the right path you need to lock another door and throw
>> away the key.".
> As a matter of interest what is the "right path" that is being proposed?
> If it takes much more than 7 keypresses then I suspect it will be opposed!
>(I'm too lazy to look up the thread myself! :-)
It is already opposed because it breaks existing, working code unnecessarily.
The replacements suggested are:
- use Decimal values, and round them instead;
- use string formatting
Neither suggestion has really thought things through clearly. The first has
identified the problem correctly -- it is *binary floats*, not round, which
causes the problem, but to round a Decimal you need the round built-in (or
at least a replacement):
py> from decimal import Decimal as D
py> x = D('2.123456')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Decimal' object has no attribute 'round'
py> round(x, 3)
The second is, well, poorly thought out. Here is an example of the sort
of thing where round can give funny results. You expect that on half-way
cases, it should round to the nearest EVEN number:
# as expected
py> round(1.125, 2)
py> round(1.135, 2)
# but unexpected
py> round(2.675, 2)
Why? Because 2.675 is not actually a half-way case, it is actually a binary
float a tiny bit under the decimal 2.675:
py> print("%.17f" % 2.675)
Fair enough. So let's try the recommended solution:
py> "%.2f" % 2.675
Wait, that gives the same result as rounding. So how is this better?
More information about the Tutor