msg60129 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2008-01-19 01:04 |
The documentation for the builtin round(x, n) says:
"Values are rounded to the closest multiple of 10 to the power minus n."
This isn't always true; for example:
Python 2.6a0 (trunk:59634M, Dec 31 2007, 17:27:56)
[GCC 4.0.1 (Apple Computer, Inc. build 5370)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> round(562949953421312.5, 1)
562949953421312.62
Here 562949953421312.5 is exactly representable as an IEEE754 double, so the output from the round function should be
exactly the same as the input.
Assigning this to myself to remind me to try to fix it someday.
|
msg70000 - (view) |
Author: George Boutsioukis (gboutsioukis)  |
Date: 2008-07-19 02:35 |
The issue is that the implementation of round includes multiplying the
number by 10**ndigits, thus unnecessarily losing some precision for
large numbers within the IEEE754 double limits. This means that even
smaller numbers can produce these results for higher ndigit values, eg.
>>> round(56294995342131.5, 3) #one less digit
56294995342131.508
In the submitted patch I used modf to split the number and keep the
integral intact.
|
msg71279 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2008-08-17 15:30 |
Thanks for the patch, George!
This patch fixes the problem in some, but not all cases. I'd like to take
this a little further.
As far as I can see, getting correctly rounded results in all cases is out
of reach without either writing lots of multi-precision code (which would
make the round code unnecessarily complicated and difficult to maintain)
or using Python's arbitrary-precision integers (which would be slow).
But it would be reasonable to aim for correctly rounded results
|
msg71281 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2008-08-17 15:35 |
Hit submit too soon; sorry...
But it would be reasonable to aim for correctly rounded results when the
second argument to round is not too large (less than 22 in absolute
value, for example), so that 10**abs(n) is exactly representable as a
double. I think this should be easy when n is negative (use fmod to
compute the remainder, and subtract the remainder from the original
number to round down, or add (10**-n - remainder) to round up, and a
little bit more involved when n is positive.
Note that the 3.x version will need to be slightly different, so that it
does round-half-to-even instead of round-half-away-from-zero.
I think that while these changes could be considered bugfixes they're
not essential, so should be put off until 2.7/3.1.
|
msg71286 - (view) |
Author: George Boutsioukis (gboutsioukis)  |
Date: 2008-08-17 18:05 |
Hi Mark,
Yes, I see where you are going with this and I agree. I think the py3k
round function is a bit more accurate, any chance this can be backported
to 2.7(after modifying the half-rounding)?
Anyway, I was just playing around with the code when I wrote this patch.
Anything beyond math.h(and only the really portable functions) is
obviously out of the question, so there's little here to work with.
Despite the (rare) unpredictable results, I think this issue is probably
too minor to spend any more time on;IMO nobody really relies on round()
for accuracy anyway. Perhaps this should be just ignored.
|
msg80728 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-01-28 21:48 |
See also issue 4707.
|
msg80872 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-01-31 15:14 |
See also issue 5118.
|
msg83458 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-03-11 08:24 |
...and issue 5473
|
msg86088 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-04-17 20:13 |
Here's a patch that improves float rounding in a number of respects:
(1) (when available) it uses the recently added correctly-rounded str <-
> float conversions in Python/dtoa.c. This means that:
- round(x, n) finally does what the docs say it does: rounds x to the
closest multiple of 10**-n (and then returns the closest float to the
result).
- for n > 0, the digits of round(x, n) will always agree with those
of "%.<n>f" % x.
One *really* nice feature is that since e.g. round(x, 2) will always be
the closest float to a multiple of 0.01, thanks to the recent repr
changes it'll always be output with at most two places following the
decimal point, and so will appear to be properly rounded...
Other changes. round(x, n) now:
(2) deals correctly with large values of n
(3) deals correctly with infinities and nans for x
(4) deals correctly with overflow (e.g. round(1.5e308, -308))
(5) doesn't have the weird exception for n = -2**31+1, which was
treated as a single-parameter round.
Still needs tests. I'm working on them.
|
msg86089 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-04-17 20:15 |
Note that the correctly rounded string<->decimal code only
exists in 3.1, so it won't be possible to backport all this good
stuff to 2.7.
|
msg86093 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-04-17 21:51 |
Updated patch, with tests.
|
msg86114 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-04-18 11:51 |
Fixed in py3k in r71701.
Some of this fix can be backported to 2.7.
|
msg86115 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-04-18 12:06 |
Closing this. I think 2.7 is fine as it is.
|
msg86117 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-04-18 12:27 |
I take that back. The 2.7 round still has some problems.
Here's one example:
>>> x = 5e15 + 1 # exactly representable as an IEEE 754 double
>>> x
5000000000000001.0
>>> round(x)
5000000000000002.0
Another nit:
>>> round(-0.0, 0) # should retain the sign of zero
0.0
Reopening.
|
msg86119 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-04-18 15:06 |
The two problems mentioned above have now been fixed in r71715.
There are (at least) two remaining problems with the round function in 2.x
that I'm not going to fix, because the added complication doesn't seem
worth it.
(1) round(x, n) doesn't give correct results with large values of n;
but small values (e.g., abs(n) <= 50) should be fine unless x is
huge.
(2) round(x, n) still occasionally rounds the wrong way in borderline
cases, even for small n.
Closing (again!)
|
msg89041 - (view) |
Author: Mark Dickinson (mark.dickinson) *  |
Date: 2009-06-07 14:37 |
See also issue 6228.
|
|
Date |
User |
Action |
Args |
2022-04-11 14:56:29 | admin | set | github: 46177 |
2009-06-07 14:37:32 | mark.dickinson | set | messages:
+ msg89041 |
2009-04-18 15:06:24 | mark.dickinson | set | status: open -> closed resolution: fixed messages:
+ msg86119
|
2009-04-18 12:27:24 | mark.dickinson | set | status: closed -> open resolution: fixed -> (no value) messages:
+ msg86117
|
2009-04-18 12:06:38 | mark.dickinson | set | status: open -> closed resolution: fixed messages:
+ msg86115
|
2009-04-18 11:51:18 | mark.dickinson | set | messages:
+ msg86114 versions:
- Python 3.1 |
2009-04-17 21:52:18 | mark.dickinson | set | components:
+ Interpreter Core |
2009-04-17 21:51:57 | mark.dickinson | set | files:
+ issue1869_2.patch
messages:
+ msg86093 stage: test needed -> patch review |
2009-04-17 20:15:17 | mark.dickinson | set | messages:
+ msg86089 |
2009-04-17 20:13:54 | mark.dickinson | set | files:
+ issue1869.patch
messages:
+ msg86088 stage: test needed |
2009-03-11 08:30:12 | mark.dickinson | link | issue5473 superseder |
2009-03-11 08:24:52 | mark.dickinson | set | messages:
+ msg83458 |
2009-01-31 15:14:18 | mark.dickinson | set | messages:
+ msg80872 |
2009-01-28 21:48:08 | mark.dickinson | set | priority: low -> normal messages:
+ msg80728 |
2008-08-17 18:05:20 | gboutsioukis | set | messages:
+ msg71286 |
2008-08-17 15:35:35 | mark.dickinson | set | messages:
+ msg71281 versions:
- Python 3.0 |
2008-08-17 15:30:22 | mark.dickinson | set | messages:
+ msg71279 versions:
+ Python 3.1, Python 2.7, - Python 2.6, Python 2.5 |
2008-07-19 02:35:25 | gboutsioukis | set | files:
+ round_patch.diff keywords:
+ patch messages:
+ msg70000 nosy:
+ gboutsioukis |
2008-01-19 01:04:25 | mark.dickinson | create | |