-
-
Notifications
You must be signed in to change notification settings - Fork 31.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
round(25, 1) should return an integer, not a float #48957
Comments
I've been playing around with the newly released Python 3.0, and I'm a Python 3.0 (r30:67503, Dec 7 2008, 04:54:04)
[GCC 4.3.2] on linux2
>>> round(25, -1)
30.0 I had expected the result to be the integer 20, because:
Is this unintended behaviour, or am I missing something? |
Looks like a bug to me. I get the expected behaviour on my machine. Python 3.0+ (release30-maint:67878, Dec 20 2008, 17:31:44)
[GCC 4.0.1 (Apple Inc. build 5490)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> round(25, -1)
20.0
>>> round(25.0, -1)
20.0 What system are you on? |
Correction: it looks like two bugs to me. I think the wrong-return-type bug is rather serious, possibly a release The incorrect rounding (returning 30.0 instead of 20.0) is less serious, |
Why do you say the return type is incorrect? It should, and does, return |
The documentation at: http://docs.python.org/dev/3.0/library/functions.html#round says, of round(x[, n]): """The return value is an integer if called with one argument, otherwise On the other hand, PEP-3141 (which I didn't check before) seems to say So maybe this is just a doc bug? I have to admit that I don't understand the motivation for round(int, n) But given that a behaviour change would be backwards incompatible, and the |
Jeffrey, any opinion on this? |
I'm using Arch Linux (32 bit) with kernel 2.6.25 and glibc 2.8 on a core As far as the rounding itself is concerned, round(x, n) seems to work as |
When PEP-3141 says something should be Real, that includes both int and The documentation is a little too strict on __round__ implementations by And, uh, oops for writing those bugs. Is your guess for round(25.0, |
The code that hands-off long.__round__ to float.__round__ is a train |
Yes, something like that. I don't think it's feasible to make round I'll work up a patch for round(int, int) -> int, so that at least we |
In that case, the doc string should be fixed: round(number[, ndigits]) -> floating point number unless "floating point number" is supposed to include type int Wrt. this issue: PEP-3141 specified that round() rounds to even If the result is to be an int, the implementation must not go py> int(round(10**20+324678,-3)) |
IMO, having long.__round__ return a float is a landmine, guaranteed to |
Here's a first attempt at a patch for round(int, int) -> int. |
Correct me if I'm wrong, but I think computing the quotient is not def round(n, i):
if i >= 0: return n
i = 10**(-i)
r = n%(2*i)
if r < i:
return n-r
return n-r+2*i |
Martin, that gives some answers like round(51, -2) --> 0 instead of 100. |
Will review the patch later this evening. Thanks for the submission. |
I see. Here is a version that fixes that. def round(n, i):
i = 10**(-i)
r = n%(2*i)
o = i/2
n -= r
if r <= o:
return n
elif r < 3*o:
return n+i
else:
return n+2*i However, I now see that it is pointless not to use divrem, since |
Updated patch: fix test_builtin. (Rest of the patch unchanged.) |
Hi Mark,
I think there's an overflow for ndigits that predates your patch:
>>> round(2, -2**31 +1)
2
>>> round(2, -2**31 +2)
nan
(it looks like these lines above make 2.6 hang :/) Now, I'm getting a segfault in 3.0 when Ctrl + C-ing during a long Python 3.1a0 (py3k:67893M, Dec 21 2008, 10:38:30)
[GCC 4.2.4 (Ubuntu 4.2.4-1ubuntu3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> round(2, -2**31 + 1)
2
>>> round(2, -2**31 + 2) # Press Ctrl + C
Segmentation fault
(backtrace below) Also, maybe "round(2, -2**31 + 2)" taking long is a bug of its own? The crash with backtrace:
Starting program: /home/ajaksu/py3k/python
[Thread debugging using libthread_db enabled]
Python 3.1a0 (py3k:67893M, Dec 21 2008, 11:08:29)
[GCC 4.2.4 (Ubuntu 4.2.4-1ubuntu3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
[New Thread 0xb7d2e8c0 (LWP 14925)]
>>> round(2, -2**31 + 1)
2
>>>
>>> round(2, -2**31 + 2) # Press Ctrl + C Program received signal SIGSEGV, Segmentation fault. I hope this helps :) |
Thanks, Daniel. It looks like I messed up the refcounting in the error- I don't think the hang itself should be considered a bug, any more |
Cause of segfault was doing Py_XDECREF on a pointer that hadn't been Here's a fixed patch. I still get the instant result: >>> round(2, -2**31+1)
2 which is a little odd. It's the correct result, but I can't see how |
Aha. The special result for round(x, 1-2**31) has nothing to do with this #define UNDEF_NDIGITS (-0x7fffffff) /* Unlikely ndigits value */ in bltinmodule.c. The same behaviour results for all types, not just |
Mark Dickinson <report@bugs.python.org> wrote:
Well, besides the fact that you can stop "10**(2**31-1)" with Ctrl+C but
Is it correct? The answer for 0 > ndigits > -2**301+1 was nan before the
That should be optimizable for ndigits > number, and perhaps
Yep, "predates your patch" as I said :) |
No. :-) It should be 0, as you say.
I think this is wrong, too. It should be 2. It's another consequence of Here's an updated version of the patch that does away with the >>> round(2, 2**31)
2
>>> round(2, 2**100)
2
>>> round(2, -2**100)
^CTraceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyboardInterrupt
>> round(2, 1-2**31)
^CTraceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyboardInterrupt
Agreed. I don't think this optimization is worth it. |
I also think that documentation should be improved for It can be confusing to anyione. Take the following example:
>>> round(26.5,1)
26.5
>>> round(26.5,-1)
30.0 |
Clearer title. |
Some minor modifications to the last patch:
|
Someone ought to ping Guido on this. He may have some strong thoughts |
Guido, do you have any thoughts on this? Basically, it's a choice between giving round() a weird signature |
I think it's fine if it returns an int iff the first arg is an int. In round(int)int |
I'd prefer round(x,positive_integer) return float. Returning int is a For non-positive integer roundings I'd like an integer return. In my opinion, we'd benefit from this definition of round: import numbers
def round(a,p=0,base=10):
'''
>>> round(147,-1,5)
145.0
>>> round(143,-1,5)
145.0
>>> round(142,-1,5)
140.0
>>> round(12.345,1,2)
12.5
>>> round(12.345,2,2)
12.25
>>> round(12.345,-2,2)
12
>>> round(12.345,-3,2)
16
'''
# consider using sign transfer for negative a
if base < 1:
raise ValueError('base too confusing')
require_integral_output = (
(p < 1) and
isinstance(base, numbers.Integral) and
isinstance(p, numbers.Integral))
b = base**p
result = int(a*b+0.5)/b
if require_integral_output:
result = int(0.5+result)
return result |
Well, that would leave a function whose return *type* depends on the I don't know why you think rounding an int to X (X>0) digits after the |
The value of one of the arguments controls how many digits there are. Certainly if you rounded $10 to the nearest cents you'd expect $10.00. I'd apply a similar argument to convince you that the return value Hark! This is python. We can take this correct and beautiful approach. |
I'm sorry, but I don't see a significant difference between $10 and |
For myself, I strongly prefer that round(int, int) return an integer in (1) Interoperability with Decimal (and, to a lesser extent, Fraction): (2) Accuracy: currently, for example, we have >>> round(10**16+1, 0)
10000000000000000.0 If the return type is changed to int, there's no need for this loss of (3) Consistency: in 3.x, round(my_decimal, n) returns a Decimal; |
marketdickinson> (2) Accuracy I see int/float like bytes/characters: it's not a good idea to mix I like round(int,int)->int (same input/output types). To get a float, |
Apologies for the poor formatting in the last comment. Bad One more reason: (4) "In the face of ambiguity, refuse the temptation to guess." I'll shut up now. |
It's settled then. Input type dictates output type. No dependency on |
Committed in r69068 (py3k), r69069 (release30-maint). The original bug with round(float, n) (loss of accuracy arising from |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: