Python 3.x 舍入行为
- 2024-11-28 08:37:00
- admin 原创
- 6
问题描述:
我刚刚重读了Python 3.0 中的新增功能,它指出:
函数
round()
舍入策略和返回类型已更改。精确半数的情况现在被舍入为最接近的偶数结果,而不是远离零。(例如,round(2.5)
现在返回 2 而不是 3。)
以及以下文档round()
:
对于支持 的内置类型
round()
,值将四舍五入为最接近的 10 的 n 次方倍数;如果两个倍数同样接近,则向偶数方向舍入
因此,在Python 2(例如 v2.7.3)中我得到了预期的结果:
round(2.5)
3.0
round(3.5)
4.0
但是,现在在Python 3下(例如 v3.2.3):
round(2.5)
2
round(3.5)
4
这似乎违反直觉,与我对舍入的理解相反(并且注定会让人困惑)。英语不是我的母语,但直到我读到这篇文章,我才知道舍入是什么意思 :-/ 我确信在 Python 3 推出时一定对此进行了一些讨论,但我在搜索中找不到一个很好的理由。
有人知道为什么要将其改为这样吗?
是否有其他主流编程语言(例如C、C++、Java、Perl等)可以进行这种(对我来说不一致的)舍入?
我在这里遗漏了什么?
更新:@Li-aungYip 关于“银行家舍入”的评论给了我正确的搜索词/关键词,然后我发现了这个 SO 问题:为什么 .NET 使用银行家舍入作为默认设置?,所以我会仔细阅读。
解决方案 1:
Python 3 的方法(称为“四舍五入为偶数”或“银行家舍入”)现在被认为是标准的舍入方法,尽管一些语言实现尚未实现。
简单的“始终将 0.5 四舍五入”技术会导致略微偏向较高的数字。对于大量计算,这可能会很严重。Python 3.0 方法消除了这个问题。
常用的舍入方法不止一种。IEEE 754(浮点数学国际标准)定义了五种不同的舍入方法(Python 3.0 使用的方法是默认方法)。还有其他方法。
这种行为并不像它应该的那样广为人知。如果我没记错的话,AppleScript 是这种舍入方法的早期采用者。AppleScriptround
中的命令提供了几个选项,但舍入为偶数是默认选项,就像 IEEE 754 中一样。显然,实现该命令的工程师round
对所有“让它像我在学校学到的那样工作”的要求感到厌烦,因此他只实现了这个:round 2.5 rounding as taught in school
是一个有效的 AppleScript 命令。:-)
解决方案 2:
您可以使用Decimal 模块控制 Py3000 中的舍入:
>>> decimal.Decimal('3.5').quantize(decimal.Decimal('1'),
rounding=decimal.ROUND_HALF_UP)
>>> Decimal('4')
>>> decimal.Decimal('2.5').quantize(decimal.Decimal('1'),
rounding=decimal.ROUND_HALF_EVEN)
>>> Decimal('2')
>>> decimal.Decimal('3.5').quantize(decimal.Decimal('1'),
rounding=decimal.ROUND_HALF_DOWN)
>>> Decimal('3')
解决方案 3:
只需在这里添加文档中的一个重要说明:
https://docs.python.org/dev/library/functions.html#round
笔记
round() 对浮点数的行为可能会令人惊讶:例如,round(2.675, 2) 给出的结果为 2.67,而不是预期的 2.68。这不是错误:这是由于大多数小数不能精确表示为浮点数所致。有关更多信息,请参阅浮点运算:问题和限制。
因此,在 Python 3.2 中得到以下结果不要感到惊讶:
>>> round(0.25,1), round(0.35,1), round(0.45,1), round(0.55,1)
(0.2, 0.3, 0.5, 0.6)
>>> round(0.025,2), round(0.035,2), round(0.045,2), round(0.055,2)
(0.03, 0.04, 0.04, 0.06)
解决方案 4:
Python 3.x 将 .5 值舍入为相邻的偶数
assert round(0.5) == 0
assert round(1.5) == 2
assert round(2.5) == 2
import decimal
assert decimal.Decimal('0.5').to_integral_value() == 0
assert decimal.Decimal('1.5').to_integral_value() == 2
assert decimal.Decimal('2.5').to_integral_value() == 2
但是,如果需要的话,可以将小数舍入“改回”为始终将 .5 向上舍入:
decimal.getcontext().rounding = decimal.ROUND_HALF_UP
assert decimal.Decimal('0.5').to_integral_value() == 1
assert decimal.Decimal('1.5').to_integral_value() == 2
assert decimal.Decimal('2.5').to_integral_value() == 3
i = int(decimal.Decimal('2.5').to_integral_value()) # to get an int
assert i == 3
assert type(i) is int
解决方案 5:
我最近也遇到了这个问题。因此,我开发了一个 Python 3 模块,它有 2 个函数trueround()
,trueround_precision()
可以解决这个问题,并提供我们在小学时习惯的相同舍入行为(不是银行家舍入)。这是模块。只需保存代码并将其复制或导入即可。
注意:trueround_precision 模块可以根据 decimal 模块中的 ROUND_CEILING、ROUND_DOWN、ROUND_FLOOR、ROUND_HALF_DOWN、ROUND_HALF_EVEN、ROUND_HALF_UP、ROUND_UP 和 ROUND_05UP 标志根据需要更改舍入行为(有关详细信息,请参阅该模块文档)。有关以下函数,请参阅文档字符串或使用help(trueround)
并help(trueround_precision)
复制到解释器中以获取更多文档。
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
def trueround(number, places=0):
'''
trueround(number, places)
example:
>>> trueround(2.55, 1) == 2.6
True
uses standard functions with no import to give "normal" behavior to
rounding so that trueround(2.5) == 3, trueround(3.5) == 4,
trueround(4.5) == 5, etc. Use with caution, however. This still has
the same problem with floating point math. The return object will
be type int if places=0 or a float if places=>1.
number is the floating point number needed rounding
places is the number of decimal places to round to with '0' as the
default which will actually return our interger. Otherwise, a
floating point will be returned to the given decimal place.
Note: Use trueround_precision() if true precision with
floats is needed
GPL 2.0
copywrite by Narnie Harshoe <signupnarnie@gmail.com>
'''
place = 10**(places)
rounded = (int(number*place + 0.5if number>=0 else -0.5))/place
if rounded == int(rounded):
rounded = int(rounded)
return rounded
def trueround_precision(number, places=0, rounding=None):
'''
trueround_precision(number, places, rounding=ROUND_HALF_UP)
Uses true precision for floating numbers using the 'decimal' module in
python and assumes the module has already been imported before calling
this function. The return object is of type Decimal.
All rounding options are available from the decimal module including
ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN,
ROUND_HALF_UP, ROUND_UP, and ROUND_05UP.
examples:
>>> trueround(2.5, 0) == Decimal('3')
True
>>> trueround(2.5, 0, ROUND_DOWN) == Decimal('2')
True
number is a floating point number or a string type containing a number on
on which to be acted.
places is the number of decimal places to round to with '0' as the default.
Note: if type float is passed as the first argument to the function, it
will first be converted to a str type for correct rounding.
GPL 2.0
copywrite by Narnie Harshoe <signupnarnie@gmail.com>
'''
from decimal import Decimal as dec
from decimal import ROUND_HALF_UP
from decimal import ROUND_CEILING
from decimal import ROUND_DOWN
from decimal import ROUND_FLOOR
from decimal import ROUND_HALF_DOWN
from decimal import ROUND_HALF_EVEN
from decimal import ROUND_UP
from decimal import ROUND_05UP
if type(number) == type(float()):
number = str(number)
if rounding == None:
rounding = ROUND_HALF_UP
place = '1.'
for i in range(places):
place = ''.join([place, '0'])
return dec(number).quantize(dec(place), rounding=rounding)
解决方案 6:
Python 3 中的 Python 2 舍入行为。
小数点后第 15 位加 1,精度达 15 位。
round2=lambda x,y=None: round(x+1e-15,y)
175.57 不对。因为数字增加时应该将其添加到小数点后 13 位。改用十进制比重新发明轮子要好。
from decimal import Decimal, ROUND_HALF_UP
def round2(x, y=2):
prec = Decimal(10) ** -y
return float(Decimal(str(round(x,3))).quantize(prec, rounding=ROUND_HALF_UP))
未使用 y
解决方案 7:
一些案例:
in: Decimal(75.29 / 2).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
in: round(75.29 / 2, 2)
out: 37.65 GOOD
in: Decimal(85.55 / 2).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
in: round(85.55 / 2, 2)
out: 42.77 BAD
修复方法:
in: round(75.29 / 2 + 0.00001, 2)
out: 37.65 GOOD
in: round(85.55 / 2 + 0.00001, 2)
out: 42.78 GOOD
如果想要更多小数,例如 4,则应添加 (+ 0.0000001)。
为我工作。
解决方案 8:
样品复制:
['{} => {}'.format(x+0.5, round(x+0.5)) for x in range(10)]
['0.5 => 0', '1.5 => 2', '2.5 => 2', '3.5 => 4', '4.5 => 4', '5.5 => 6', '6.5 => 6', '7.5 => 8', '8.5 => 8', '9.5 => 10']
API:https ://docs.python.org/3/library/functions.html#round
状态:
返回四舍五入到小数点后 ndigits 精度的数字。如果 ndigits 被省略或为 None,则返回最接近其输入的整数。
对于支持 round() 的内置类型,值会被四舍五入为最接近的 10 的次方减 ndigits 的倍数;如果两个倍数同样接近,则四舍五入为偶数(例如,round(0.5) 和 round(-0.5) 均为 0,round(1.5) 为 2)。任何整数值对于 ndigits 都有效(正数、零或负数)。如果 ndigits 被省略或为 None,则返回值为整数。否则,返回值的类型与 number 相同。
对于一般的 Python 对象数字, round 委托给number.round。
注意:round() 对浮点数的行为可能会令人惊讶:例如,round(2.675, 2) 给出的结果为 2.67,而不是预期的 2.68。这不是错误:这是由于大多数小数不能精确表示为浮点数所致。有关更多信息,请参阅浮点运算:问题和限制。
有了这种见解,你可以用一些数学来解决这个问题
import math
def my_round(i):
f = math.floor(i)
return f if i - f < 0.5 else f+1
现在您可以使用 my_round 而不是 round 来运行相同的测试。
['{} => {}'.format(x + 0.5, my_round(x+0.5)) for x in range(10)]
['0.5 => 1', '1.5 => 2', '2.5 => 3', '3.5 => 4', '4.5 => 5', '5.5 => 6', '6.5 => 7', '7.5 => 8', '8.5 => 9', '9.5 => 10']
解决方案 9:
我建议为 DataFrame 工作的自定义函数:
def dfCustomRound(df, dec):
d = 1 / 10 ** dec
df = round(df, dec + 2)
return (((df % (1 * d)) == 0.5 * d).astype(int) * 0.1 * d * np.sign(df) + df).round(dec)
解决方案 10:
没有小数,
def my_round(x: float, precision: int = 2):
tmp = round(x, precision)
if x == tmp + float('0.' + '0' * precision + '5'):
return round(x + float('0.' + '0' * precision + '1'), precision)
return tmp
解决方案 11:
# round module within numpy when decimal is X.5 will give desired (X+1)
import numpy as np
example_of_some_variable = 3.5
rounded_result_of_variable = np.round(example_of_some_variable,0)
print (rounded_result_of_variable)
解决方案 12:
试试这个代码:
def roundup(input):
demo = input if str(input)[-1] != "5" else str(input).replace("5","6")
place = len(demo.split(".")[1])-1
return(round(float(demo),place))
结果是:
>>> x = roundup(2.5)
>>> x
3.0
>>> x = roundup(2.05)
>>> x
2.1
>>> x = roundup(2.005)
>>> x
2.01
您可以在此处查看输出:
https://i.sstatic.net/QQUkS.png
解决方案 13:
您可以使用 math.ceil 模块控制舍入:
import math
print(math.ceil(2.5))
> 3
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件