为什么(0.0006*100000)%10是10

2024-03-28 19:37:21 发布

您现在位置:Python中文网/ 问答频道 /正文

当我在python中执行(0.0006*100000)%10和(0.0003*100000)%10时,它分别返回了9.99999999993,但实际上它必须是0。 类似地,在c++中fmod(0.0003*100000,10)的值为10。有人能帮我解决我的错误吗。在


Tags: 错误fmod
3条回答

最接近0.0003的IEEE 754 64位二进制数是0.000299999999999999737189393389513725196593441069126129150390625。与100000相乘的结果最接近的可表示数字是29.9999999999644728632199499070644378662109375。在

有许多操作,如floor和mod,可以使非常低的显著性差异非常明显。在使用浮点数时要小心——记住,在很多情况下,你有一个非常非常接近无限精度值的近似值,而不是无限精度值本身。实际值可以略高,或者在本例中,略低。在

我可以建议在C语言中使用余数函数吗?在

它将计算取整商后的余数,精确计算(无舍入误差):

remainder = dividend - round(dividend/divisor)*divisor

这样,您的结果将以[-divisor/2,+divisor/2]为间隔。
这仍然会强调这样一个事实:你没有得到一个完全等于6/10000的浮点数,但是当你期望一个空余数时,可能会以一种不那么令人惊讶的方式出现:

^{pr2}$

我不知道python中对remainment函数的支持,但gnulibpython模块中似乎有一个匹配项(有待验证…)
https://github.com/ghostmansd/gnulib-python/blob/master/modules/remainder

编辑 为什么它在[1,9]间隔内每隔N/10000工作一次,除了3和6?在

这并不完全是幸运的,这是ieee754在默认舍入模式下(舍入到最近的,并列到偶数)的好特性。在

浮点运算的结果四舍五入到最接近的浮点值。
因此,您将得到(N/D+err)而不是N/D,其中绝对错误err是由这个片段给出的(我在Smalltalk中比较舒服,但是我相信您会在Python中找到等效的):

^{3}$

它给你的感觉是:

#(4.79217360238593e-21 9.58434720477186e-21 -2.6281060661048628e-20 1.916869440954372e-20 1.0408340855860843e-20 -5.2562121322097256e-20 -7.11236625150491e-21 3.833738881908744e-20 -2.4633073358870662e-20)

改变浮点有效位的最后一位会导致一个小的差异,称为最小精度单位(ulp),用ulp来表示误差可能比较好:

| d |
d := 10000.
^(1 to: 9) collect: [:n | ((n/d) asFloat asFraction - (n/d)) / (n/d) asFloat ulp]

因此,精确分数的ulp数为:

#(0.3536 0.3536 -0.4848 0.3536 0.096 -0.4848 -0.0656 0.3536 -0.2272)

N=1,2,4,8的误差是相同的,因为它们基本上是相同的浮点-相同的有效位,只是指数发生变化。
由于相同的原因,N=3和6也是相同的,但非常接近于单个操作的最大误差,即0.5 ulp(不幸的是,数字可能在两个浮点之间的一半)。
对于N=9,相对误差小于N=1;对于5和7,相对误差很小。在

当我们把这些近似值乘以10000,它可以精确地表示为一个浮点数,(N/D+err)D就是N+Derr,然后四舍五入到最近的浮点值。如果D*err小于距下一个浮点的一半距离,则舍入到N,舍入误差消失。在

| d |
d := 10000.
^(1 to: 9) collect: [:n | ((n/d) asFloat asFraction - (n/d)) * d / n asFloat ulp]

好吧,对于N=3和6,我们很不幸,已经很高的舍入误差量已经超过0.5 ulp:

^{8}$

注意,距离对于2的精确幂不是对称的,1.0之后的下一个浮点数是1.0+2^-52,而在1.0之前是1.0-2^-53。在

尽管如此,我们在这里看到的是,在第二次舍入运算之后,误差在四种情况下消失,只在一种情况下累积(只计算具有不同有效位的情况)。在

我们可以推广这个结果。只要我们不求指数相差很大的数的和,而只使用muliply/divide运算,而P运算后的误差界可能很高,那么累积误差的统计分布与这个界相比有一个非常窄的峰值,结果是出人意料的好,我们经常读到的浮点数不精确。例如,请参阅我对The number of correct decimal digits in a product of doubles with a large number of terms的回答。在

我只是想说,是的,浮动是不精确的,但是他们有时做得很好,以至于他们在培养精确的错觉。找到一些像这篇文章中提到的离群值是令人惊讶的。惊喜越早,惊喜越少。啊,如果浮动实施得不那么仔细,这类问题就少了。。。在

给出一个显而易见的答案:0.0006和{}在机器双精度中不可表示(至少在现代机器上)。所以你实际上并没有乘以这些值,而是乘以某个非常接近的值。稍微多一点,或者稍微少一点,这取决于编译器如何取整它们。在

相关问题 更多 >