Python 3 小数四舍五入 ROUND_HALF_UP 上下文
Python 3 Decimal rounding half down with ROUND_HALF_UP context
任何人都可以解释或建议解决为什么当我在 Python 3 中舍入小数时将上下文设置为四舍五入一半,它将 2.5 舍入为 2,而在 Python 2 中它正确舍入为 3:
Python 3.4.3 和 3.5.2:
>>> import decimal
>>> context = decimal.getcontext()
>>> context.rounding = decimal.ROUND_HALF_UP
>>> round(decimal.Decimal('2.5'))
2
>>> decimal.Decimal('2.5').__round__()
2
>>> decimal.Decimal('2.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_UP)
Decimal('3')
Python 2.7.6:
>>> import decimal
>>> context = decimal.getcontext()
>>> context.rounding = decimal.ROUND_HALF_UP
>>> round(decimal.Decimal('2.5'))
3.0
>>> decimal.Decimal('2.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_UP)
Decimal('3')
请注意,当您调用 round
时,您得到的是一个浮点值,而不是 Decimal
。 round
将值强制转换为浮点数,然后根据四舍五入浮点数的规则对其进行四舍五入。
如果您在调用 round()
时使用可选的 ndigits
参数,您将得到一个 Decimal 结果,在这种情况下,它将按您预期的方式取整。
Python 3.4.1 (default, Sep 24 2015, 20:41:10)
[GCC 4.9.2 20150212 (Red Hat 4.9.2-6)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import decimal
>>> context = decimal.getcontext()
>>> context.rounding = decimal.ROUND_HALF_UP
>>> round(decimal.Decimal('2.5'), 0)
Decimal('3')
我还没有找到记录 round(someDecimal)
returns 一个整数但是 round(someDecimal, ndigits)
returns 一个小数的地方,但这似乎是 Python 3.3 及更高版本。在 Python 2.7 中,当您调用 round()
时,您总是会返回一个浮点数,但是 Python 3.3 改进了 Decimal
与 Python 内置函数的集成。
如评论中所述,round()
委托给 Decimal.__round__()
,这确实显示了相同的行为:
>>> Decimal('2.5').__round__()
2
>>> Decimal('2.5').__round__(0)
Decimal('3')
我注意到 Fraction
的文档说:
__round__()
__round__(ndigits)
The first version returns the nearest int to self, rounding half to even.
The second version rounds self to the nearest multiple of Fraction(1, 10**ndigits)
(logically, if ndigits is negative), again rounding half toward even.
This method can also be accessed through the round() function.
因此,行为是一致的,因为它没有参数就改变了结果的类型并将一半四舍五入为偶数,但是似乎 Decimal
未能记录其 __round__
方法的行为.
编辑注意,正如 Barry Hurley 在评论中所说,如果在没有可选参数的情况下调用,round()
被记录为返回 int
,如果给定可选参数,则返回 "floating point value"。 https://docs.python.org/3/library/functions.html#round
扩展@Duncan 的回答,round
内置函数在 python 2 和 python 3 之间更改为四舍五入到最接近的偶数(这是统计中的标准)。
Python2 文档:
...if two multiples are equally close, rounding is done away
from 0 (so, for example, round(0.5) is 1.0 and round(-0.5) is -1.0).
Python3 文档:
...if two multiples are equally close, rounding is done toward the even
choice (so, for example, both round(0.5) and round(-0.5) are 0, and
round(1.5) is 2)
由于 round
转换为 float
如果没有为 ndigits
给出参数(归功于@Duncan 的回答),round
的行为方式与float
s.
示例(在 python3 中):
>>> round(2.5)
2
>>> round(2.500000001)
3
>>> round(3.5)
4
这是 Python 2 vs 3 中 round
的舍入模式和 Python 到 [= 的 Decimal
的重新实现之间的变化的组合16=](参见Features for 3.3 section PEP 398中的"Other final large-scale changes")。
对于 round
,舍入策略发生了变化,在为传递的对象定义的 What's New In Python 3.0 [Also see Python 3.x rounding behavior ]. Additionally, round
in Python 3
first tries to find an appropriate __round__
方法中可以看出:
>>> round('1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type str doesn't define __round__ method
虽然在 Python 2.x
它首先尝试 coerce it specifically to a float
然后舍入它:
>>> round('1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: a float is required
对于Decimal
,在Python 2
中,实现甚至缺少一个__round__
方法被调用:
>>> Decimal.__round__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'Decimal' has no attribute '__round__'
因此,在 Decimal
对象上调用 round
将其强制转换为 float
,后者得到 rounded using _Py_double_round
;这导致 float
总是被返回,而不管是否提供了 ndigits
的值。 decimal
以纯 Python 实现 2.x
和(是?)Python 3
直到 3.2
.
In Python 3.3
it got shinny new __round__
method 因为它在 C
中重新实现:
>>> Decimal.__round__
<method '__round__' of 'decimal.Decimal' objects>
现在,当调用 round(<Decimal_object>)
时,它会被 round
拾取。
这个,映射到 C
中的 PyDec_Round
,现在 returns a PyLong (an integer) using the default context (ROUND_HALF_EVEN
) if the argument ndigits
is not supplied and, if it is, calls quantize
和 returns 一个新的圆形 Decimal
对象。
任何人都可以解释或建议解决为什么当我在 Python 3 中舍入小数时将上下文设置为四舍五入一半,它将 2.5 舍入为 2,而在 Python 2 中它正确舍入为 3:
Python 3.4.3 和 3.5.2:
>>> import decimal
>>> context = decimal.getcontext()
>>> context.rounding = decimal.ROUND_HALF_UP
>>> round(decimal.Decimal('2.5'))
2
>>> decimal.Decimal('2.5').__round__()
2
>>> decimal.Decimal('2.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_UP)
Decimal('3')
Python 2.7.6:
>>> import decimal
>>> context = decimal.getcontext()
>>> context.rounding = decimal.ROUND_HALF_UP
>>> round(decimal.Decimal('2.5'))
3.0
>>> decimal.Decimal('2.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_UP)
Decimal('3')
请注意,当您调用 round
时,您得到的是一个浮点值,而不是 Decimal
。 round
将值强制转换为浮点数,然后根据四舍五入浮点数的规则对其进行四舍五入。
如果您在调用 round()
时使用可选的 ndigits
参数,您将得到一个 Decimal 结果,在这种情况下,它将按您预期的方式取整。
Python 3.4.1 (default, Sep 24 2015, 20:41:10)
[GCC 4.9.2 20150212 (Red Hat 4.9.2-6)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import decimal
>>> context = decimal.getcontext()
>>> context.rounding = decimal.ROUND_HALF_UP
>>> round(decimal.Decimal('2.5'), 0)
Decimal('3')
我还没有找到记录 round(someDecimal)
returns 一个整数但是 round(someDecimal, ndigits)
returns 一个小数的地方,但这似乎是 Python 3.3 及更高版本。在 Python 2.7 中,当您调用 round()
时,您总是会返回一个浮点数,但是 Python 3.3 改进了 Decimal
与 Python 内置函数的集成。
如评论中所述,round()
委托给 Decimal.__round__()
,这确实显示了相同的行为:
>>> Decimal('2.5').__round__()
2
>>> Decimal('2.5').__round__(0)
Decimal('3')
我注意到 Fraction
的文档说:
__round__()
__round__(ndigits)
The first version returns the nearest int to self, rounding half to even.
The second version rounds self to the nearest multiple of Fraction(1, 10**ndigits)
(logically, if ndigits is negative), again rounding half toward even.
This method can also be accessed through the round() function.
因此,行为是一致的,因为它没有参数就改变了结果的类型并将一半四舍五入为偶数,但是似乎 Decimal
未能记录其 __round__
方法的行为.
编辑注意,正如 Barry Hurley 在评论中所说,如果在没有可选参数的情况下调用,round()
被记录为返回 int
,如果给定可选参数,则返回 "floating point value"。 https://docs.python.org/3/library/functions.html#round
扩展@Duncan 的回答,round
内置函数在 python 2 和 python 3 之间更改为四舍五入到最接近的偶数(这是统计中的标准)。
Python2 文档:
...if two multiples are equally close, rounding is done away from 0 (so, for example, round(0.5) is 1.0 and round(-0.5) is -1.0).
Python3 文档:
...if two multiples are equally close, rounding is done toward the even choice (so, for example, both round(0.5) and round(-0.5) are 0, and round(1.5) is 2)
由于 round
转换为 float
如果没有为 ndigits
给出参数(归功于@Duncan 的回答),round
的行为方式与float
s.
示例(在 python3 中):
>>> round(2.5)
2
>>> round(2.500000001)
3
>>> round(3.5)
4
这是 Python 2 vs 3 中 round
的舍入模式和 Python 到 [= 的 Decimal
的重新实现之间的变化的组合16=](参见Features for 3.3 section PEP 398中的"Other final large-scale changes")。
对于 round
,舍入策略发生了变化,在为传递的对象定义的 What's New In Python 3.0 [Also see Python 3.x rounding behavior ]. Additionally, round
in Python 3
first tries to find an appropriate __round__
方法中可以看出:
>>> round('1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type str doesn't define __round__ method
虽然在 Python 2.x
它首先尝试 coerce it specifically to a float
然后舍入它:
>>> round('1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: a float is required
对于Decimal
,在Python 2
中,实现甚至缺少一个__round__
方法被调用:
>>> Decimal.__round__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'Decimal' has no attribute '__round__'
因此,在 Decimal
对象上调用 round
将其强制转换为 float
,后者得到 rounded using _Py_double_round
;这导致 float
总是被返回,而不管是否提供了 ndigits
的值。 decimal
以纯 Python 实现 2.x
和(是?)Python 3
直到 3.2
.
In Python 3.3
it got shinny new __round__
method 因为它在 C
中重新实现:
>>> Decimal.__round__
<method '__round__' of 'decimal.Decimal' objects>
现在,当调用 round(<Decimal_object>)
时,它会被 round
拾取。
这个,映射到 C
中的 PyDec_Round
,现在 returns a PyLong (an integer) using the default context (ROUND_HALF_EVEN
) if the argument ndigits
is not supplied and, if it is, calls quantize
和 returns 一个新的圆形 Decimal
对象。