在R中,为什么不-1 + 1 = 0

时间:2015-05-21 19:42:16

标签: r seq cumsum

有人可以帮我理解为什么-1 + 1<> 0?

有人可以帮助我理解为什么我在内置函数consum(),我的函数ct()和Excel之间得到三个不同的值,当它们都做同样的事情时?

现在,我很确定答案是一个“回合”问题,但我无法弄清楚这个问题的部分来自哪里。我的意思是,这一切似乎都非常直接。

在R中,当我构建序列'a'然后运行cumsum(a)时,我没有像我期望的那样得到0的结果。如果我尝试使用函数计算相同的值,我也会得到不同的答案。最后,如果我尝试使用Excel计算相同的值,我会得到第三个答案。

这是我使用cumsum():

> a<- seq(-1, 1, by=.1)
> a
 [1] -1.0 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1  0.0  0.1  0.2  0.3
[15]  0.4  0.5  0.6  0.7  0.8  0.9  1.0
> cumsum(a)
 [1] -1.000000e+00 -1.900000e+00 -2.700000e+00 -3.400000e+00 -4.000000e+00
 [6] -4.500000e+00 -4.900000e+00 -5.200000e+00 -5.400000e+00 -5.500000e+00
[11] -5.500000e+00 -5.400000e+00 -5.200000e+00 -4.900000e+00 -4.500000e+00
[16] -4.000000e+00 -3.400000e+00 -2.700000e+00 -1.900000e+00 -1.000000e+00
[21]  1.110223e-15

我写了一个快速函数来测试这个并期望得到相同的答案(或0),但我得到一个完全不同的答案。这是我的功能及其结果:

ct<- function(x){
        result = 0
        for(i in 1:length(x)){
           cat(i, ": Result = ", result, " + ", x[i], " = ", result + x[i], "\n")
           result = result + x[i]
        }
}

> ct(a)
1 : Result =  0  +  -1  =  -1 
2 : Result =  -1  +  -0.9  =  -1.9 
3 : Result =  -1.9  +  -0.8  =  -2.7 
4 : Result =  -2.7  +  -0.7  =  -3.4 
5 : Result =  -3.4  +  -0.6  =  -4 
6 : Result =  -4  +  -0.5  =  -4.5 
7 : Result =  -4.5  +  -0.4  =  -4.9 
8 : Result =  -4.9  +  -0.3  =  -5.2 
9 : Result =  -5.2  +  -0.2  =  -5.4 
10 : Result =  -5.4  +  -0.1  =  -5.5 
11 : Result =  -5.5  +  0  =  -5.5 
12 : Result =  -5.5  +  0.1  =  -5.4 
13 : Result =  -5.4  +  0.2  =  -5.2 
14 : Result =  -5.2  +  0.3  =  -4.9 
15 : Result =  -4.9  +  0.4  =  -4.5 
16 : Result =  -4.5  +  0.5  =  -4 
17 : Result =  -4  +  0.6  =  -3.4 
18 : Result =  -3.4  +  0.7  =  -2.7 
19 : Result =  -2.7  +  0.8  =  -1.9 
20 : Result =  -1.9  +  0.9  =  -1 
21 : Result =  -1  +  1  =  4.440892e-16

如果我将for循环中的最后一行更改为this,那么我得到的预期答案为0:

result = round(result + x[I], digits = 2)

在Excel中,使用与我的ct()函数相同的逻辑,得到-2.886580E-15的最终结果(没有舍入值)。

2 个答案:

答案 0 :(得分:5)

这是使用具有无法准确表示的值的固定精度表示的本质。

就像1/3无法用固定的小数位数精确表示一样,0.1无法用固定数量的二进制位数精确表示。因此,就像3 x (1/3)可能无法为您提供具有固定小数位数的1,添加0.1的倍数将永远不会为您提供固定精度二进制中的1。

所以,让我们看看六精度十进制表示只是为了更清楚地看到这一点(this用于表示值,而不是表示):
1 - &gt; 1.000000
1/3 - &gt; 0.333333
2/3 - &gt; 0.666667
3 - &gt; 3.000000

这给出了:

1/3 + 2/3 - &gt; 0.333333 + 0.666667 - &gt; 1.000000 - &gt; 1(yay)

1/3 + 1/3 - &gt; 0.333333 + 0.333333 - &gt; 0.666666(不是2/3,哦,好吧)

3 * 1/3 - &gt; 3.00000 * 0.333333 - &gt; .999999(不是1,哦,好吧)

你如何处理这取决于你,但这应该是预期的行为。

为了解决你的上一个问题,为什么要做同样的事情&#34;两种不同的方式可以产生不同的结果,它来自中间舍入。如果您曾经使用计算器进行过计算,写下一些部分中间结果,您知道它会对您记下的中间结果产生影响。

答案 1 :(得分:0)

我猜它只是围绕问题。如果你使用 var Camera = require('gopro').Camera var cam = new Camera('10.5.5.9', 'camera password') cam.startCapture() .then(function() { cam.stopCapture() }) 函数从-10到10生成一个向量,然后用seq.int得到0的总和:

cumsum

如果你真的想在-1和1之间做一个序列,那么只需将整数序列除以> seq.int(-10,10,1) [1] -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 > cumsum(seq.int(-10,10,1)) [1] -10 -19 -27 -34 -40 -45 -49 -52 -54 -55 -55 -54 -52 -49 -45 -40 -34 -27 -19 -10 0

10L

你仍然会像往常一样处理一些舍入错误,但这似乎低于R的四舍五入的阈值。