Python内置函数源代码 - round()

时间:2017-09-06 15:02:54

标签: python rounding

问题

我想访问内置函数round()的源代码,以允许我创建一个非常相似的函数。我如何访问此源代码以及编辑/使用它的容易程度?

我感兴趣的原因是内置函数round()即使数字为负数也会将整数转换为浮点数。 例如:

round(1234.5678,-2)

返回

1200.0 

我想创建一个返回整数的函数。我确信还有其他方法可以实现相同的结果,但是我想看看内置函数如何实现这个任务,因为我希望它的效率相当高。

2 个答案:

答案 0 :(得分:1)

来源似乎是:https://github.com/python/cpython/blob/master/Python/pymath.c

double
round(double x)
{
    double absx, y;
    absx = fabs(x);
    y = floor(absx);
    if (absx - y >= 0.5)
        y += 1.0;
    return copysign(y, x);
}

其中copysign是:

double
copysign(double x, double y)
{
    /* use atan2 to distinguish -0. from 0. */
    if (y > 0. || (y == 0. && atan2(y, -1.) > 0.)) {
        return fabs(x);
    } else {
        return -fabs(x);
    }
}

答案 1 :(得分:1)

只需扩展Mark Dickinson的注释,并确保我自己理解,CPython round function就分布在代码库的几个部分。

round(number, ndigits)首先在对象上查找并调用__round__方法。这是由C函数builtin_round_impl in bltinmodule.c

实现的

对于float,这会调用float.__round__方法,该方法在float___round___impl in floatobject.c:1045中实现,但是floatobject.c.h中有一个存根入口点,我认为它主要由{{ 3}}工具。此标头也是其PyMethodDef被定义为FLOAT___ROUND___METHODDEF

的地方

C函数float___round___impl首先检查是否未指定ndigits(即没有传递或以None传递),在这种情况下,它将从{ C标准库(或pymath.c的版本作为后备)。

如果指定了ndigits,则它可能会调用Python's argument clinic的版本。此代码以53位精度工作,因此可以调整浮点舍入模式,并且通常是很漂亮的代码,但是基本上它将双精度数转换为具有给定精度的字符串,然后再转换回双精度数

round double_round in floatobject.c:927的另一个版本执行的功能基本上是round(x * 10**ndigits) / 10**ndigits,但是这些额外的操作会降低结果的精度

请注意,如small number of platforms所述,较高精度的版本将对double_round at floatobject.c:985中的版本和NumPy中的等效版本给出不同的答案。例如,round(0.075, 2)的内置回合结果为0.07,而numpy和R给出0.08。我发现最简单的方法是使用R模块来查看浮点数的十进制扩展:

from decimal import Decimal

print(Decimal(0.075))

给定:0.0749999999999999972…,即0.075不能由(二进制)浮点数精确表示,并且最接近的数字恰好稍小,因此将其舍入为0.07。而here给出0.08的原因是它有效地round(0.075 * 100) / 100并且中间值恰好取整,即:

print(Decimal(0.075 * 100))

精确给出7.5,将其精确舍入到8