[英]What's the underlying implimentation of integer division in python?
I am running python 3.7.3我正在运行 python 3.7.3
Regarding the integer division operator: "//" (double divide, double forward slash, double division operator? I'm not sure the exact name.)关于整数除法运算符:“//”(双除法、双正斜杠、双除法运算符?我不确定确切的名称。)
It does not seem to give consistent results, and many of the explanations I've found don't fully explain its results.它似乎没有给出一致的结果,而且我发现的许多解释并没有完全解释它的结果。
Here[ What is the reason for having '//' in Python?这里[ 在Python中有'//'的原因是什么? (and other places) it's said that the "//" operator gives the quotient without the remainder. (和其他地方)据说“//”运算符给出没有余数的商。 As if a // b
is the same as floor(a / b)
(or rounding up if a / b
is negative).好像a // b
与floor(a / b)
(如果a / b
为负,则向上舍入)。
However, sometimes it does not give that answer.然而,有时它并没有给出那个答案。 For example, 1 // 0.2
evaluates to 4. However 1 / 0.2
returns 5, and math.floor(1 / 2)
also returns 5. It's giving a number one less than what integer division should.例如, 1 // 0.2
计算结果为 4。但是1 / 0.2
返回 5,并且math.floor(1 / 2)
也返回 5。它给出的数字比整数除法应该小一。 The //
operator returns a 5 if you divide 10 by 2, but 1 divided 0.2 does not work correctly.如果将 10 除以 2,则//
运算符返回 5,但 1 除以 0.2 无法正常工作。
This problem comes up other times I use the //
operator to divide floating point numbers.这个问题出现在我使用//
运算符来划分浮点数的其他时候。 Like 5 // 0.2
or 100 // 0.2
.像5 // 0.2
或100 // 0.2
。 I don't know if this is some quirk of floating point arithmetic, but these problems seem to go away if you type math.floor(5 / 0.2)
(or any other set of numbers giving issues).我不知道这是否是浮点运算的一些怪癖,但是如果您输入math.floor(5 / 0.2)
(或任何其他给出问题的数字集math.floor(5 / 0.2)
,这些问题似乎就会消失。 Except when you divide negative numbers, in which case you have to use math.ceil()
instead of math.floor()
除非你除以负数,在这种情况下你必须使用math.ceil()
而不是math.floor()
My current solution is this:我目前的解决方案是这样的:
import math
def integerDivision(a,b):
tmp = a / b
if tmp > 1:
return(math.floor(tmp))
else:
return(math.ceil(tmp))
What is the implementation of the //
operator that makes it not give the right result in some floating point cases? //
运算符的实现是什么使它在某些浮点情况下不能给出正确的结果? Is there a better way to get around this issue of the //
operator, other than the above code?除了上面的代码之外,还有没有更好的方法来解决//
运算符的这个问题?
This isn't about implementation.这与实施无关。 This is about the operator's semantics.这与操作符的语义有关。 Regardless of implementation, the //
operator is required to give you the results you're seeing when applied to floats, and those results really are correct (for floats).无论实现如何, //
运算符都需要为您提供应用于浮点数时看到的结果,并且这些结果确实是正确的(对于浮点数)。 If you don't want these results, floats are probably the wrong tool for what you're doing.如果你不想要这些结果,浮动可能是你正在做的事情的错误工具。
1 // 0.2
gives the floating-point number representing the floor of the exact value of the quotient of its arguments. 1 // 0.2
给出表示其参数商的确切值的下限的浮点数。 However, the right-hand argument does not quite have the value you typed in. The right-hand argument's value is the closest value to 0.2 representable in 64-bit IEEE binary floating point, which is slightly higher than 0.2:但是,右侧参数并不完全具有您键入的值。右侧参数的值是 64 位 IEEE 二进制浮点中可表示的最接近 0.2 的值,该值略高于 0.2:
>>> import decimal
>>> decimal.Decimal(0.2)
Decimal('0.200000000000000011102230246251565404236316680908203125')
The exact value of the quotient is thus slightly less than 5, so 1 // 0.2
gives you 4.0
.因此,商的确切值略小于 5,因此1 // 0.2
为您提供4.0
。
1 / 0.2
gives you 5.0
because the exact value of the quotient isn't representable as a float. 1 / 0.2
为您提供5.0
因为商的确切值不能表示为浮点数。 The result needs to be rounded, and it rounds to 5.0
.结果需要四舍五入,并四舍五入为5.0
。 //
does not perform this rounding; //
不执行此舍入; it computes the floor of the exact value, not the floor of a rounded float.它计算精确值的下限,而不是圆形浮点数的下限。 (The result of the //
may need to be rounded, but that's a different rounding.) ( //
的结果可能需要四舍五入,但这是不同的四舍五入。)
With all that said, the implementation needs to be more complex than floor(x / y)
, because that would give the wrong result.尽管如此,实现需要比floor(x / y)
更复杂,因为这会产生错误的结果。 CPython bases its //
implementation for floats on fmod
. CPython 的//
浮点数实现基于fmod
。 You can see the implementation in Objects/floatobject.c
in the CPython source repository.您可以在 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;
}
Other argument types will use other implementations, depending on the types.其他参数类型将使用其他实现,具体取决于类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.