Python是否记录了舍入到指定小数位数的行为?

Python是否记录了舍入到指定小数位数的行为?,python,python-2.7,Python,Python 2.7,该算法是否用于将Python中的float四舍五入到任何Python文档中指定的位数?零小数位数(round)的语义很容易理解,但我不清楚如何实现位数非零的情况 我所能想到的函数最直接的实现(考虑到小数位数为零的舍入)是: def round_impl(x, ndigits): return (10 ** -ndigits) * round(x * (10 ** ndigits)) 我试图编写一些C++代码,它模仿Python的代码>代码(Road)/代码>函数,用于所有代码< C++

该算法是否用于将Python中的
float
四舍五入到任何Python文档中指定的位数?零小数位数(
round
)的语义很容易理解,但我不清楚如何实现位数非零的情况

我所能想到的函数最直接的实现(考虑到小数位数为零的
舍入
)是:

def round_impl(x, ndigits):
    return (10 ** -ndigits) * round(x * (10 ** ndigits))

我试图编写一些C++代码,它模仿Python的代码>代码(Road)/代码>函数,用于所有代码< C++ >代码>的值,并且在翻译成等价的C++调用时,上述大部分与Python相一致。但是,在某些情况下会有所不同,例如:

>>> round(0.493125, 5)
0.49312
>>> round_impl(0.493125, 5)
0.49313
当要舍入的值位于或非常接近两个潜在输出值之间的精确中点时,显然会出现差异。因此,如果我想得到类似的结果,那么尝试使用相同的技术似乎很重要


Python是否指定了执行舍入的具体方法?我在测试中使用的是CPython 2.7.15,但我的目标是v2.7+。

Python文档用于并指定了以下行为:

值四舍五入到最接近幂减的10倍 NDIGIT;如果两个倍数相等,则舍入将被消除 从0开始

用于:

对于支持round()的内置类型,值舍入为 幂减去ndigit的最接近10的倍数;如果两个倍数 同样接近,舍入是朝着均匀的选择进行的

更新:

函数
float\uuuuuu round\uuuuu impl
中的(cpython)实现,如果
ndigits
未给出,则调用
round
,如果给出,则调用
double\u round

double\u round
有两种实现。 一种是将double转换为字符串(也称为decimal),然后再转换回double。 另一个执行一些浮点计算,调用
pow
,并在其核心调用
round
。它似乎有更多潜在的溢出问题,因为它实际上将输入乘以
10**-ndigit


要了解精确的算法,请查看链接的源文件。

Python文档中指定了以下行为:

值四舍五入到最接近幂减的10倍 NDIGIT;如果两个倍数相等,则舍入将被消除 从0开始

用于:

对于支持round()的内置类型,值舍入为 幂减去ndigit的最接近10的倍数;如果两个倍数 同样接近,舍入是朝着均匀的选择进行的

更新:

函数
float\uuuuuu round\uuuuu impl
中的(cpython)实现,如果
ndigits
未给出,则调用
round
,如果给出,则调用
double\u round

double\u round
有两种实现。 一种是将double转换为字符串(也称为decimal),然后再转换回double。 另一个执行一些浮点计算,调用
pow
,并在其核心调用
round
。它似乎有更多潜在的溢出问题,因为它实际上将输入乘以
10**-ndigit

有关精确的算法,请查看链接的源文件。

另请参阅,其中有更详细的解释,说明了为什么会发生这种情况

这真是一团糟。首先,就浮动而言,没有0.493125这样的数字,当你写0.493125时,你实际得到的是:

0.49312499999999800815985556747182272374746279974629974365234375

所以这个数字并不完全在两个小数之间,它实际上更接近于0.49312,而不是0.49313,所以它肯定应该四舍五入到0.49312,这一点很清楚

问题是当你乘以105时,你得到的是确切的数字49312.5。所以这里发生的是乘法给了你一个不精确的结果,恰好抵消了原始数字的舍入误差。两个舍入错误互相抵消了,耶!但问题是,当你这样做时,舍入实际上是不正确的。。。至少如果您想在中点取整,但是Python 3和Python 2的行为不同。Python2从0开始循环,Python3从最低有效数字开始循环

如果两个倍数相等接近,则舍入距离为0

…如果两个倍数相等,则向偶数方向取整

总结 在Python 2中

>>> round(49312.5)
49313.0
>>> round(0.493125, 5)
0.49312
在Python 3中

>>> round(49312.5)
49312
>>> round(0.493125, 5)
0.49312
在这两种情况下,0.493125实际上只是书写0.493124999999980015985556747182272374747462799629974365234375的一个简短方式

那么,它是如何工作的呢? 我认为有两种可行的方法可以让
round()
真正发挥作用

  • 选择具有指定位数的最接近的十进制数,然后将该十进制数四舍五入为
    浮点
    精度。这是很难实现的,因为它需要比您从
    float
    得到的精度更高的计算

  • 取两个具有指定位数的最接近的十进制数,将它们四舍五入到
    float
    精度,然后返回两者中较接近的一个。这将给出不正确的结果,因为它将数字舍入两次

  • Python选择了。。。选项1!该版本完全正确,但更难实现。提到它使用以下过程:

  • 使用请求的精度将浮点数写入十进制格式的字符串

  • 将字符串重新解析为
    浮点数

  • 这使用基于的代码。如果您希望C++代码获得像Python那样的实际正确结果,这是一个好的开始。幸运的是你可以