Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么(0.0006*100000)%10是10_Python_C++_Floating Point_Floating Accuracy_Modulus - Fatal编程技术网

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

Python 为什么(0.0006*100000)%10是10,python,c++,floating-point,floating-accuracy,modulus,Python,C++,Floating Point,Floating Accuracy,Modulus,当我在python中执行(0.0006*100000)%10和(0.0003*100000)%10时,它分别返回9.99999999993,但实际上它必须是0。 同样,在C++中,fMOD(0.0003×100000,10)给出了10的值。有人能帮我找出哪里出了错。给我一个明显的答案:0.0006和0.0003不能用双精度机器表示(至少在现代机器上是如此)。所以你实际上并没有乘以这些值,而是乘以一些非常接近的值。稍多或稍少,取决于编译器对其进行舍入的方式。与0.0003最接近的IEEE 754

当我在python中执行(0.0006*100000)%10和(0.0003*100000)%10时,它分别返回9.99999999993,但实际上它必须是0。
同样,在C++中,fMOD(0.0003×100000,10)给出了10的值。有人能帮我找出哪里出了错。

给我一个明显的答案:
0.0006
0.0003
不能用双精度机器表示(至少在现代机器上是如此)。所以你实际上并没有乘以这些值,而是乘以一些非常接近的值。稍多或稍少,取决于编译器对其进行舍入的方式。

与0.0003最接近的IEEE 754 64位二进制数为0.00029999999999737189393389513725196593441069126129150390625。与100000相乘的结果最接近的可表示数字为29.9999999996447286321199499070644378662109375


有许多操作,例如floor和mod,可以使非常低的显著性差异非常明显。在浮点数中使用它们时需要小心——请记住,在许多情况下,您的近似值非常非常接近于无限精度值,而不是无限精度值本身。实际值可以稍高,也可以稍低。

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

它将计算四舍五入后的余数最接近整数的商,并进行精确计算(无四舍五入误差):

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

remainder(0.0006*100000,10.0) -> -7.105427357601002e-15
remainder(0.0003*100000,10.0) -> -3.552713678800501e-15
我不知道python中有这样的余数函数支持,但gnulib python模块中似乎有一个匹配项(有待验证…)

编辑 为什么在[1,9]间隔内,除了3和6之外,它显然与其他N/10000一起工作

这并不完全是幸运的,这是IEEE 754在默认舍入模式下(舍入到最近,平分到偶数)的良好特性

浮点运算的结果四舍五入为最接近的浮点值。
因此,您得到的不是N/D(N/D+err),而是这个代码段给出的绝对错误err(我在Smalltalk中感觉更舒服,但我相信您会在Python中找到等价物):

它会给你一些类似的东西:

#(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:

#(0.2158203125 0.2158203125 -0.591796875 0.2158203125 0.1171875 -0.591796875 -0.080078125 0.2158203125 -0.138671875)
注意,对于2的精确幂,距离不是对称的,1.0之后的下一个浮点是1.0+2^-52,但在1.0之前是1.0-2^-53

尽管如此,我们在这里看到的是,在第二次舍入操作后,误差确实在四种情况下消失,并且仅在一种情况下累积(仅计算具有不同有效位的情况)

我们可以推广这个结果。只要我们不使用不同指数的数字求和,而只使用多重/除法运算,而P运算后的误差范围可能很高,累积误差的统计分布与此范围相比有一个非常窄的峰值,结果在某种程度上是出人意料的好,我们经常读到的关于浮动不精确性的w.r.t。例如,参见我对的回答


我只是想提一提,是的,浮动是不精确的,但它们有时做得很好,它们正在培养精确的错觉。发现一些像本文中提到的异常值是令人惊讶的。惊喜越早,惊喜越少。啊,如果浮点数的实现不那么小心,这类问题就会少一些……

浮点数就是这样工作的。你永远不会得到完美的精度,因为数字系统中所有的浮点值都是近似值。@MarcB,你可以得到完美的精度。只是不是全部numbers@Depado你总是得到一个精确的结果。它可能不是您想要的结果,并且它通常不同于对实数进行相同运算时的结果,但它是精确且完全确定的。机器浮点不是实数,遵循不同的规则。而且,我是唯一一个对浮点数的模运算感到不确定的人吗?@tangrs 0.0002和0.0005都不能精确表示。两者都略高:0.0002000000000009584347204771859196625888275969028472900390625和0.0005000000000104083408586084256647154688835144296875
| d |
d := 10000.
^(1 to: 9) collect: [:n | ((n/d) asFloat asFraction - (n/d)) * d / n asFloat ulp]
#(0.2158203125 0.2158203125 -0.591796875 0.2158203125 0.1171875 -0.591796875 -0.080078125 0.2158203125 -0.138671875)