Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
1124e713
Commit
1124e713
authored
Jan 28, 2009
by
Mark Dickinson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #4707: round(x, n) now returns an integer when x is an integer.
Previously it returned a float.
parent
9de29afa
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
217 additions
and
33 deletions
+217
-33
Lib/test/test_builtin.py
Lib/test/test_builtin.py
+3
-3
Lib/test/test_long.py
Lib/test/test_long.py
+75
-0
Misc/NEWS
Misc/NEWS
+3
-0
Objects/longobject.c
Objects/longobject.c
+128
-20
Python/bltinmodule.c
Python/bltinmodule.c
+8
-10
No files found.
Lib/test/test_builtin.py
View file @
1124e713
...
...
@@ -1068,9 +1068,9 @@ class BuiltinTest(unittest.TestCase):
self
.
assertEqual
(
round
(
8
),
8
)
self
.
assertEqual
(
round
(
-
8
),
-
8
)
self
.
assertEqual
(
type
(
round
(
0
)),
int
)
self
.
assertEqual
(
type
(
round
(
-
8
,
-
1
)),
floa
t
)
self
.
assertEqual
(
type
(
round
(
-
8
,
0
)),
floa
t
)
self
.
assertEqual
(
type
(
round
(
-
8
,
1
)),
floa
t
)
self
.
assertEqual
(
type
(
round
(
-
8
,
-
1
)),
in
t
)
self
.
assertEqual
(
type
(
round
(
-
8
,
0
)),
in
t
)
self
.
assertEqual
(
type
(
round
(
-
8
,
1
)),
in
t
)
# test new kwargs
self
.
assertEqual
(
round
(
number
=-
8.0
,
ndigits
=-
1
),
-
10.0
)
...
...
Lib/test/test_long.py
View file @
1124e713
...
...
@@ -896,6 +896,81 @@ class LongTest(unittest.TestCase):
self
.
assertEqual
((
a
+
1
).
bit_length
(),
i
+
1
)
self
.
assertEqual
((
-
a
-
1
).
bit_length
(),
i
+
1
)
def
test_round
(
self
):
# check round-half-even algorithm. For round to nearest ten;
# rounding map is invariant under adding multiples of 20
test_dict
=
{
0
:
0
,
1
:
0
,
2
:
0
,
3
:
0
,
4
:
0
,
5
:
0
,
6
:
10
,
7
:
10
,
8
:
10
,
9
:
10
,
10
:
10
,
11
:
10
,
12
:
10
,
13
:
10
,
14
:
10
,
15
:
20
,
16
:
20
,
17
:
20
,
18
:
20
,
19
:
20
}
for
offset
in
range
(
-
520
,
520
,
20
):
for
k
,
v
in
test_dict
.
items
():
got
=
round
(
k
+
offset
,
-
1
)
expected
=
v
+
offset
self
.
assertEqual
(
got
,
expected
)
self
.
assert_
(
type
(
got
)
is
int
)
# larger second argument
self
.
assertEqual
(
round
(
-
150
,
-
2
),
-
200
)
self
.
assertEqual
(
round
(
-
149
,
-
2
),
-
100
)
self
.
assertEqual
(
round
(
-
51
,
-
2
),
-
100
)
self
.
assertEqual
(
round
(
-
50
,
-
2
),
0
)
self
.
assertEqual
(
round
(
-
49
,
-
2
),
0
)
self
.
assertEqual
(
round
(
-
1
,
-
2
),
0
)
self
.
assertEqual
(
round
(
0
,
-
2
),
0
)
self
.
assertEqual
(
round
(
1
,
-
2
),
0
)
self
.
assertEqual
(
round
(
49
,
-
2
),
0
)
self
.
assertEqual
(
round
(
50
,
-
2
),
0
)
self
.
assertEqual
(
round
(
51
,
-
2
),
100
)
self
.
assertEqual
(
round
(
149
,
-
2
),
100
)
self
.
assertEqual
(
round
(
150
,
-
2
),
200
)
self
.
assertEqual
(
round
(
250
,
-
2
),
200
)
self
.
assertEqual
(
round
(
251
,
-
2
),
300
)
self
.
assertEqual
(
round
(
172500
,
-
3
),
172000
)
self
.
assertEqual
(
round
(
173500
,
-
3
),
174000
)
self
.
assertEqual
(
round
(
31415926535
,
-
1
),
31415926540
)
self
.
assertEqual
(
round
(
31415926535
,
-
2
),
31415926500
)
self
.
assertEqual
(
round
(
31415926535
,
-
3
),
31415927000
)
self
.
assertEqual
(
round
(
31415926535
,
-
4
),
31415930000
)
self
.
assertEqual
(
round
(
31415926535
,
-
5
),
31415900000
)
self
.
assertEqual
(
round
(
31415926535
,
-
6
),
31416000000
)
self
.
assertEqual
(
round
(
31415926535
,
-
7
),
31420000000
)
self
.
assertEqual
(
round
(
31415926535
,
-
8
),
31400000000
)
self
.
assertEqual
(
round
(
31415926535
,
-
9
),
31000000000
)
self
.
assertEqual
(
round
(
31415926535
,
-
10
),
30000000000
)
self
.
assertEqual
(
round
(
31415926535
,
-
11
),
0
)
self
.
assertEqual
(
round
(
31415926535
,
-
12
),
0
)
self
.
assertEqual
(
round
(
31415926535
,
-
999
),
0
)
# should get correct results even for huge inputs
for
k
in
range
(
10
,
100
):
got
=
round
(
10
**
k
+
324678
,
-
3
)
expect
=
10
**
k
+
325000
self
.
assertEqual
(
got
,
expect
)
self
.
assert_
(
type
(
got
)
is
int
)
# nonnegative second argument: round(x, n) should just return x
for
n
in
range
(
5
):
for
i
in
range
(
100
):
x
=
random
.
randrange
(
-
10000
,
10000
)
got
=
round
(
x
,
n
)
self
.
assertEqual
(
got
,
x
)
self
.
assert_
(
type
(
got
)
is
int
)
for
huge_n
in
2
**
31
-
1
,
2
**
31
,
2
**
63
-
1
,
2
**
63
,
2
**
100
,
10
**
100
:
self
.
assertEqual
(
round
(
8979323
,
huge_n
),
8979323
)
# omitted second argument
for
i
in
range
(
100
):
x
=
random
.
randrange
(
-
10000
,
10000
)
got
=
round
(
x
)
self
.
assertEqual
(
got
,
x
)
self
.
assert_
(
type
(
got
)
is
int
)
# bad second argument
bad_exponents
=
(
'brian'
,
2.0
,
0j
,
None
)
for
e
in
bad_exponents
:
self
.
assertRaises
(
TypeError
,
round
,
3
,
e
)
def
test_main
():
support
.
run_unittest
(
LongTest
)
...
...
Misc/NEWS
View file @
1124e713
...
...
@@ -12,6 +12,9 @@ What's New in Python 3.1 alpha 0
Core and Builtins
-----------------
- Issue #4707: round(x, n) now returns an integer if x is an integer.
Previously it returned a float.
- Issue #4753: By enabling a configure option named '--with-computed-gotos'
on compilers that support it (notably: gcc, SunPro, icc), the bytecode
evaluation loop is compiled with a new dispatch mechanism which gives
...
...
Objects/longobject.c
View file @
1124e713
...
...
@@ -3643,32 +3643,140 @@ long__format__(PyObject *self, PyObject *args)
PyUnicode_GET_SIZE
(
format_spec
));
}
static
PyObject
*
long_round
(
PyObject
*
self
,
PyObject
*
args
)
{
#define UNDEF_NDIGITS (-0x7fffffff)
/* Unlikely ndigits value */
int
ndigits
=
UNDEF_NDIGITS
;
double
x
;
PyObject
*
res
;
if
(
!
PyArg_ParseTuple
(
args
,
"|i"
,
&
ndigits
))
return
NULL
;
PyObject
*
o_ndigits
=
NULL
,
*
temp
;
PyLongObject
*
pow
=
NULL
,
*
q
=
NULL
,
*
r
=
NULL
,
*
ndigits
=
NULL
,
*
one
;
int
errcode
;
digit
q_mod_4
;
/* Notes on the algorithm: to round to the nearest 10**n (n positive),
the straightforward method is:
(1) divide by 10**n
(2) round to nearest integer (round to even in case of tie)
(3) multiply result by 10**n.
But the rounding step involves examining the fractional part of the
quotient to see whether it's greater than 0.5 or not. Since we
want to do the whole calculation in integer arithmetic, it's
simpler to do:
(1) divide by (10**n)/2
(2) round to nearest multiple of 2 (multiple of 4 in case of tie)
(3) multiply result by (10**n)/2.
Then all we need to know about the fractional part of the quotient
arising in step (2) is whether it's zero or not.
Doing both a multiplication and division is wasteful, and is easily
avoided if we just figure out how much to adjust the original input
by to do the rounding.
Here's the whole algorithm expressed in Python.
def round(self, ndigits = None):
"""round(int, int) -> int"""
if ndigits is None or ndigits >= 0:
return self
pow = 10**-ndigits >> 1
q, r = divmod(self, pow)
self -= r
if (q & 1 != 0):
if (q & 2 == r == 0):
self -= pow
else:
self += pow
return self
if
(
ndigits
==
UNDEF_NDIGITS
)
*/
if
(
!
PyArg_ParseTuple
(
args
,
"|O"
,
&
o_ndigits
))
return
NULL
;
if
(
o_ndigits
==
NULL
)
return
long_long
(
self
);
/* If called with two args, defer to float.__round__(). */
x
=
PyLong_AsDouble
(
self
);
if
(
x
==
-
1
.
0
&&
PyErr_Occurred
())
ndigits
=
(
PyLongObject
*
)
PyNumber_Index
(
o_ndigits
);
if
(
ndigits
==
NULL
)
return
NULL
;
self
=
PyFloat_FromDouble
(
x
);
if
(
self
==
NULL
)
return
NULL
;
res
=
PyObject_CallMethod
(
self
,
"__round__"
,
"i"
,
ndigits
);
if
(
Py_SIZE
(
ndigits
)
>=
0
)
{
Py_DECREF
(
ndigits
);
return
long_long
(
self
);
}
Py_INCREF
(
self
);
/* to keep refcounting simple */
/* we now own references to self, ndigits */
/* pow = 10 ** -ndigits >> 1 */
pow
=
(
PyLongObject
*
)
PyLong_FromLong
(
10L
);
if
(
pow
==
NULL
)
goto
error
;
temp
=
long_neg
(
ndigits
);
Py_DECREF
(
ndigits
);
ndigits
=
(
PyLongObject
*
)
temp
;
if
(
ndigits
==
NULL
)
goto
error
;
temp
=
long_pow
((
PyObject
*
)
pow
,
(
PyObject
*
)
ndigits
,
Py_None
);
Py_DECREF
(
pow
);
pow
=
(
PyLongObject
*
)
temp
;
if
(
pow
==
NULL
)
goto
error
;
assert
(
PyLong_Check
(
pow
));
/* check long_pow returned a long */
one
=
(
PyLongObject
*
)
PyLong_FromLong
(
1L
);
if
(
one
==
NULL
)
goto
error
;
temp
=
long_rshift
(
pow
,
one
);
Py_DECREF
(
one
);
Py_DECREF
(
pow
);
pow
=
(
PyLongObject
*
)
temp
;
if
(
pow
==
NULL
)
goto
error
;
/* q, r = divmod(self, pow) */
errcode
=
l_divmod
((
PyLongObject
*
)
self
,
pow
,
&
q
,
&
r
);
if
(
errcode
==
-
1
)
goto
error
;
/* self -= r */
temp
=
long_sub
((
PyLongObject
*
)
self
,
r
);
Py_DECREF
(
self
);
return
res
;
#undef UNDEF_NDIGITS
self
=
temp
;
if
(
self
==
NULL
)
goto
error
;
/* get value of quotient modulo 4 */
if
(
Py_SIZE
(
q
)
==
0
)
q_mod_4
=
0
;
else
if
(
Py_SIZE
(
q
)
>
0
)
q_mod_4
=
q
->
ob_digit
[
0
]
&
3
;
else
q_mod_4
=
(
PyLong_BASE
-
q
->
ob_digit
[
0
])
&
3
;
if
((
q_mod_4
&
1
)
==
1
)
{
/* q is odd; round self up or down by adding or subtracting pow */
if
(
q_mod_4
==
1
&&
Py_SIZE
(
r
)
==
0
)
temp
=
(
PyObject
*
)
long_sub
((
PyLongObject
*
)
self
,
pow
);
else
temp
=
(
PyObject
*
)
long_add
((
PyLongObject
*
)
self
,
pow
);
Py_DECREF
(
self
);
self
=
temp
;
if
(
self
==
NULL
)
goto
error
;
}
Py_DECREF
(
q
);
Py_DECREF
(
r
);
Py_DECREF
(
pow
);
Py_DECREF
(
ndigits
);
return
self
;
error:
Py_XDECREF
(
q
);
Py_XDECREF
(
r
);
Py_XDECREF
(
pow
);
Py_XDECREF
(
self
);
Py_XDECREF
(
ndigits
);
return
NULL
;
}
static
PyObject
*
...
...
@@ -3773,8 +3881,8 @@ static PyMethodDef long_methods[] = {
{
"__ceil__"
,
(
PyCFunction
)
long_long
,
METH_NOARGS
,
"Ceiling of an Integral returns itself."
},
{
"__round__"
,
(
PyCFunction
)
long_round
,
METH_VARARGS
,
"Rounding an Integral returns itself.
\n
"
"Rounding with an ndigits argument
s defers to float.__round__
."
},
"Rounding an Integral returns itself.
\n
"
"Rounding with an ndigits argument
also returns an integer
."
},
{
"__getnewargs__"
,
(
PyCFunction
)
long_getnewargs
,
METH_NOARGS
},
{
"__format__"
,
(
PyCFunction
)
long__format__
,
METH_VARARGS
},
{
"__sizeof__"
,
(
PyCFunction
)
long_sizeof
,
METH_NOARGS
,
...
...
Python/bltinmodule.c
View file @
1124e713
...
...
@@ -1717,15 +1717,14 @@ For most object types, eval(repr(object)) == object.");
static
PyObject
*
builtin_round
(
PyObject
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
{
#define UNDEF_NDIGITS (-0x7fffffff)
/* Unlikely ndigits value */
static
PyObject
*
round_str
=
NULL
;
int
ndigits
=
UNDEF_NDIGITS
;
PyObject
*
ndigits
=
NULL
;
static
char
*
kwlist
[]
=
{
"number"
,
"ndigits"
,
0
};
PyObject
*
number
,
*
round
;
if
(
!
PyArg_ParseTupleAndKeywords
(
args
,
kwds
,
"O|
i
:round"
,
kwlist
,
&
number
,
&
ndigits
))
return
NULL
;
if
(
!
PyArg_ParseTupleAndKeywords
(
args
,
kwds
,
"O|
O
:round"
,
kwlist
,
&
number
,
&
ndigits
))
return
NULL
;
if
(
Py_TYPE
(
number
)
->
tp_dict
==
NULL
)
{
if
(
PyType_Ready
(
Py_TYPE
(
number
))
<
0
)
...
...
@@ -1746,15 +1745,14 @@ builtin_round(PyObject *self, PyObject *args, PyObject *kwds)
return
NULL
;
}
if
(
ndigits
==
UNDEF_NDIGITS
)
return
PyObject_CallFunction
(
round
,
"O"
,
number
);
if
(
ndigits
==
NULL
)
return
PyObject_CallFunction
(
round
,
"O"
,
number
);
else
return
PyObject_CallFunction
(
round
,
"Oi"
,
number
,
ndigits
);
#undef UNDEF_NDIGITS
return
PyObject_CallFunction
(
round
,
"OO"
,
number
,
ndigits
);
}
PyDoc_STRVAR
(
round_doc
,
"round(number[, ndigits]) ->
floating point
number
\n
\
"round(number[, ndigits]) -> number
\n
\
\n
\
Round a number to a given precision in decimal digits (default 0 digits).
\n
\
This returns an int when called with one argument, otherwise the
\n
\
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment