fmod函数python fmod函数出错

为什么Python中//和math.floor运算结果会不同

先说结论:这个问题是由于cpython的地板除运算符(//)的实现不是 浮点除法+floor 来实现而是用了(被除数 - 余数)/除数 导致的。

站在用户的角度思考问题,与客户深入沟通,找到滨海新区网站设计与滨海新区网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:成都网站建设、成都网站制作、企业官网、英文网站、手机端网站、网站推广、国际域名空间、网站空间、企业邮箱。业务覆盖滨海新区地区。

PS:Jython下可以得到20.0,而PEP里规定了a // b应该等于round(a/b),所以似乎这是cpython实现的一个bug?

首先先分析下1 / 0.05究竟应该等于多少。答案就是精确的20.0。

简单解释下:IEEE754浮点数规定,如果一个浮点数的值不能被精确记录,那么它的值会被记成与这个数距离最近的可以被IEEE浮点数表示的数。

首先,0.05在二进制下是无限循环小数,自然不能被精确记录,因此0.05这个浮点数的实际值是不等于0.05的,实际值是约为0.05 + 2.7e-18。

之后做浮点除法,实际上做的是1 / (0.05+2.7...e-18),这个除法的结果大约是20 - 1.1e-15。这个值也不能被精确表示,恰好离这个数最近的可以表示的值就是20.0,因此即使有浮点数误差结果也是精确的20.0。

既然1/0.05就是20.0,那么对他做floor运算自然也是20了。

现在的问题就是为什么1 // 0.05会变成19.0,要解决这个问题只能翻源码看//运算符的实现。

直接把cpython/floatobject.c at 829b49cbd2e4b1d573470da79ca844b730120f3d · python/cpython · GitHub 中实现//运算的一段贴上来:

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);

}

可以发现cpython中x // y的实现实际上是

round((x - fmod(x, y)) / y)

,其中fmod函数是求两个浮点数相除的余数。

这样一来就解释的通了:在十进制下,显然1除以0.05的余数应该是0.0。然而在IEEE浮点数环境中,0.05的实际值是约0.05 + 2.7e-18,略大于0.05,这样一来1除以这个数的余数就成了约0.05 - 5e-17,从1中减掉这么多之后就只剩0.95了,除以0.05再round后变成19.0。

在python交互模式下,20÷6的余数怎么表达?

在 Python 交互模式下,你可以使用模运算符(%)来表示整数的余数。例如,要求 20 除以 6 的余数,可以使用如下代码:

模运算1

这里,20 除以 6 的余数是 2。

注意,模运算符(%)只能用于求整数的余数,对于浮点数,它是不适用的。如果要求浮点数的余数,可以使用内置函数 math.fmod()。

例如:

模运算2

这里,函数 math.fmod() 返回了浮点数 20 除以 6 的余数 2.0。

python之数学相关模块

先来看一下 math 模块中包含内容,如下所示:

接下来具体看一下该模块的常用函数和常量。

ceil(x)

返回 x 的上限,即大于或者等于 x 的最小整数。看下示例:

floor(x)

返回 x 的向下取整,小于或等于 x 的最大整数。看下示例:

fabs(x)

返回 x 的绝对值。看下示例:

fmod(x, y)

返回 x/y 的余数,值为浮点数。看下示例:

factorial(x)

返回 x 的阶乘,如果 x 不是整数或为负数时则将引发 ValueError。看下示例:

pow(x, y)

返回 x 的 y 次幂。看下示例:

fsum(iterable)

返回迭代器中所有元素的和。看下示例:

gcd(x, y)

返回整数 x 和 y 的最大公约数。看下示例:

sqrt(x)

返回 x 的平方根。看下示例:

trunc(x)

返回 x 的整数部分。看下示例:

exp(x)

返回 e 的 x 次幂。看下示例:

log(x[, base])

返回 x 的对数,底数默认为 e。看下示例:

常量

tan(x)

返回 x 弧度的正切值。看下示例:

atan(x)

返回 x 的反正切值。看下示例:

sin(x)

返回 x 弧度的正弦值。看下示例:

asin(x)

返回 x 的反正弦值。看下示例:

cos(x)

返回 x 弧度的余弦值。看下示例:

acos(x)

返回 x 的反余弦值。看下示例:

decimal 模块为正确舍入十进制浮点运算提供了支持,相比内置的浮点类型 float,它能更加精确的控制精度,能够为精度要求较高的金融等领域提供支持。

decimal 在一个独立的 context 下工作,可以使用 getcontext() 查看当前上下文,如下所示:

从上面的结果中我们可以看到 prec=28,这就是默认的精度,我们可以使用 getcontext().prec = xxx 来重新设置精度。接下来通过具体示例看一下。

基本运算

执行结果:

上面结果是用了默认精度,我们重新设置下精度再来看一下:

执行结果:

random 模块可以生成随机数,我们来看一下其常用函数。

random()

返回 [0.0, 1.0) 范围内的一个随机浮点数。看下示例:

uniform(a, b)

返回 [a, b) 范围内的一个随机浮点数。看下示例:

randint(a, b)

返回 [a, b] 范围内的一个随机整数。看下示例:

randrange(start, stop[, step])

返回 [start, stop) 范围内步长为 step 的一个随机整数。看下示例:

choice(seq)

从非空序列 seq 返回一个随机元素。 看下示例:

shuffle(x[, random])

将序列 x 随机打乱位置。看下示例:

sample(population, k)

返回从总体序列或集合中选择的唯一元素的 k 长度列表,用于无重复的随机抽样。看下示例:

参考:


分享题目:fmod函数python fmod函数出错
链接URL:http://scjbc.cn/article/dogjssp.html

其他资讯