簡體   English   中英

python中整數除法的潛在含義是什么?

[英]What's the underlying implimentation of integer division in python?

我正在運行 python 3.7.3

關於整數除法運算符:“//”(雙除法、雙正斜杠、雙除法運算符?我不確定確切的名稱。)

它似乎沒有給出一致的結果,而且我發現的許多解釋並沒有完全解釋它的結果。

這里[ 在Python中有'//'的原因是什么? (和其他地方)據說“//”運算符給出沒有余數的商。 好像a // bfloor(a / b) (如果a / b為負,則向上舍入)。

然而,有時它並沒有給出那個答案。 例如, 1 // 0.2計算結果為 4。但是1 / 0.2返回 5,並且math.floor(1 / 2)也返回 5。它給出的數字比整數除法應該小一。 如果將 10 除以 2,則//運算符返回 5,但 1 除以 0.2 無法正常工作。

這個問題出現在我使用//運算符來划分浮點數的其他時候。 5 // 0.2100 // 0.2 我不知道這是否是浮點運算的一些怪癖,但是如果您輸入math.floor(5 / 0.2) (或任何其他給出問題的數字集math.floor(5 / 0.2) ,這些問題似乎就會消失。 除非你除以負數,在這種情況下你必須使用math.ceil()而不是math.floor()

我目前的解決方案是這樣的:

import math
def integerDivision(a,b):
    tmp = a / b 
    if tmp > 1:
        return(math.floor(tmp))
    else:
        return(math.ceil(tmp))

//運算符的實現是什么使它在某些浮點情況下不能給出正確的結果? 除了上面的代碼之外,還有沒有更好的方法來解決//運算符的這個問題?

這與實施無關。 這與操作符的語義有關。 無論實現如何, //運算符都需要為您提供應用於浮點數時看到的結果,並且這些結果確實是正確的(對於浮點數)。 如果你不想要這些結果,浮動可能是你正在做的事情的錯誤工具。

1 // 0.2給出表示其參數商的確切值的下限的浮點數。 但是,右側參數並不完全具有您鍵入的值。右側參數的值是 64 位 IEEE 二進制浮點中可表示的最接近 0.2 的值,該值略高於 0.2:

>>> import decimal
>>> decimal.Decimal(0.2)
Decimal('0.200000000000000011102230246251565404236316680908203125')

因此,商的確切值略小於 5,因此1 // 0.2為您提供4.0

1 / 0.2為您提供5.0因為商的確切值不能表示為浮點數。 結果需要四舍五入,並四舍五入為5.0 //不執行此舍入; 它計算精確值的下限,而不是圓形浮點數的下限。 //的結果可能需要四舍五入,但這是不同的四舍五入。)

盡管如此,實現需要比floor(x / y)更復雜,因為這會產生錯誤的結果。 CPython 的//浮點數實現基於fmod 您可以在 CPython 源代碼庫中的Objects/floatobject.c中查看實現。

static PyObject *
float_divmod(PyObject *v, PyObject *w)
{
    double vx, wx;
    double div, mod, floordiv;
    CONVERT_TO_DOUBLE(v, vx);
    CONVERT_TO_DOUBLE(w, wx);
    if (wx == 0.0) {
        PyErr_SetString(PyExc_ZeroDivisionError, "float divmod()");
        return NULL;
    }
    PyFPE_START_PROTECT("divmod", return 0)
    mod = fmod(vx, wx);
    /* fmod is typically exact, so vx-mod is *mathematically* an
       exact multiple of wx.  But this is fp arithmetic, and fp
       vx - mod is an approximation; the result is that div may
       not be an exact integral value after the division, although
       it will always be very close to one.
    */
    div = (vx - mod) / wx;
    if (mod) {
        /* ensure the remainder has the same sign as the denominator */
        if ((wx < 0) != (mod < 0)) {
            mod += wx;
            div -= 1.0;
        }
    }
    else {
        /* the remainder is zero, and in the presence of signed zeroes
           fmod returns different results across platforms; ensure
           it has the same sign as the denominator. */
        mod = copysign(0.0, wx);
    }
    /* snap quotient to nearest integral value */
    if (div) {
        floordiv = floor(div);
        if (div - floordiv > 0.5)
            floordiv += 1.0;
    }
    else {
        /* div is zero - get the same sign as the true quotient */
        floordiv = copysign(0.0, vx / wx); /* zero w/ sign of vx/wx */
    }
    PyFPE_END_PROTECT(floordiv)
    return Py_BuildValue("(dd)", floordiv, mod);
}

static PyObject *
float_floor_div(PyObject *v, PyObject *w)
{
    PyObject *t, *r;

    t = float_divmod(v, w);
    if (t == NULL || t == Py_NotImplemented)
        return t;
    assert(PyTuple_CheckExact(t));
    r = PyTuple_GET_ITEM(t, 0);
    Py_INCREF(r);
    Py_DECREF(t);
    return r;
}

其他參數類型將使用其他實現,具體取決於類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM