【问题标题】:What happens behind the scene of floor division in Python?Python 中地板除法的幕后发生了什么?
【发布时间】:2021-01-12 14:59:24
【问题描述】:

DocumentationDocumentation 关于 Python 中的楼层划分说,

/(除法)和 //(下除法)运算符产生其参数的商。数字参数首先转换为通用类型。整数除法产生一个浮点数,而整数的下除法产生一个整数;结果是对结果应用“floor”函数的数学除法。

我专注于最后一行,也就是说,

结果是数学除法,结果应用了“floor”函数

我收到了float

>>> 10//2.0
5.0

但是integer 在:

>>> import math
>>> math.floor(10/2.0)
5

所以显然不是 Python 楼层划分使用的math.floor 函数。我想知道 Python 计算两个参数的底除法的确切过程。

因为在取complex 数字的地板除法时,Python 说,

>>> (2+3j)//(4+5j)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't take floor of complex number.

这意味着 Python 会先进行除法运算,然后再应用某种底函数。它到底是什么?

【问题讨论】:

  • 这并不能回答你关于它是如何工作的问题(这可能取决于实现,我不确定),但请参阅this question about whether the behaviour is expected
  • @ThierryLathuille “内置floor”是什么意思。
  • @Chris 是的,行为符合预期。我之前读过一个类似的问题。我只是想知道幕后发生了什么。
  • 正如我之前所说,我怀疑这取决于实现。 “Python”不止一种,还有很多:CPython、Jython、PyPy、IronPython、MicroPython、Brython……
  • 这确实是其他评论中提到的特定实现。对于 PyPy,它是一个基于 rpython 的实现:foss.heptapod.net/pypy/pypy/-/blob/branch/default/pypy/objspace/…,寻找 descr_floordiv 函数,这是作为分子的浮点数。试一试,它的可读性很好。

标签: python floor-division


【解决方案1】:

比较(都来自该页面):

“地板”功能

函数math.fmod()

如果他们的意思是 math.floor,他们会像 fmod 那样设置它的样式,即作为代码并带有 math. 前缀和括号和链接。他们的意思只是数学上的floor function。不是 Python 函数。

深入研究CPython是如何实现的,我们先反汇编一下:

>>> import dis
>>> dis.dis('x // y')
  1           0 LOAD_NAME                0 (x)
              2 LOAD_NAME                1 (y)
              4 BINARY_FLOOR_DIVIDE
              6 RETURN_VALUE

抬头BINARY_FLOOR_DIVIDE

        case TARGET(BINARY_FLOOR_DIVIDE): {
            PyObject *divisor = POP();
            PyObject *dividend = TOP();
            PyObject *quotient = PyNumber_FloorDivide(dividend, divisor);
            Py_DECREF(dividend);
            Py_DECREF(divisor);
            SET_TOP(quotient);
            if (quotient == NULL)
                goto error;
            DISPATCH();
        }

抬头PyNumber_FloorDivide

PyObject *
PyNumber_FloorDivide(PyObject *v, PyObject *w)
{
    return binary_op(v, w, NB_SLOT(nb_floor_divide), "//");
}

抬头nb_floor_divide

+-----------------+------------+-----------------+
| Slot            | Type       | special methods |
+-----------------+------------+-----------------+
| ...             | ...        | ...             |
| nb_floor_divide | binaryfunc | __floordiv__    |
| ...             | ...        | ...             |
+-----------------+------------+-----------------+

现在intfloor 都有自己的:

>>> int.__floordiv__
<slot wrapper '__floordiv__' of 'int' objects>
>>> float.__floordiv__
<slot wrapper '__floordiv__' of 'float' objects>

查找the float one的函数:

static PyNumberMethods float_as_number = {
    ...
    float_floor_div,    /* nb_floor_divide */
    ...
};

抬头float_floor_div

static PyObject *
float_floor_div(PyObject *v, PyObject *w)
{
    double vx, wx;
    double mod, floordiv;
    CONVERT_TO_DOUBLE(v, vx);
    CONVERT_TO_DOUBLE(w, wx);
    if (wx == 0.0) {
        PyErr_SetString(PyExc_ZeroDivisionError, "float floor division by zero");
        return NULL;
    }
    _float_div_mod(vx, wx, &floordiv, &mod);
    return PyFloat_FromDouble(floordiv);
}

抬头_float_div_mod

static void
_float_div_mod(double vx, double wx, double *floordiv, double *mod)
{
    ...
    /* snap quotient to nearest integral value */
    if (div) {
        *floordiv = floor(div);
        if (div - *floordiv > 0.5) {
            *floordiv += 1.0;
        }
    }
    ...
}

我认为floor 来自 C,因此取决于用于编译 CPython 的 C 编译器。

【讨论】:

  • 这表明它不是math.floor,我已经弄清楚了。但幕后究竟发生了什么? Python 是如何计算它的?
  • 取决于 Python 实现和操作数的类型。就像,至少在 CPython 中,3 // 2 使用 int.__floordiv__3.0 // 2 使用 float.__floordiv__。然后您可以根据需要仔细查看他们的源代码。
  • @Fahim 添加了更多细节。
猜你喜欢
  • 2011-10-19
  • 1970-01-01
  • 2011-07-12
  • 1970-01-01
  • 2018-03-29
  • 2019-06-05
  • 1970-01-01
  • 2016-06-06
  • 1970-01-01
相关资源
最近更新 更多