在 R 中,为什么不 -1 + 1 = 0
In R, why doesn't -1 + 1 = 0
有人可以帮我理解为什么 -1 + 1 <> 0 吗?
有人能帮我理解为什么当内置函数 consum()、我的函数 ct() 和 Excel 都在做同样的事情时,我会得到三个不同的值吗?
现在,我很确定答案是 'round' 问题,但我无法弄清楚这部分问题的来源。我的意思是,这一切看起来都很简单。
在 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 循环中的最后一行更改为此,那么我将得到预期的答案 0:
result = round(result + x[I], digits = 2)
在 Excel 中,使用与我的 ct() 函数中相同的逻辑,我得到了 -2.886580E-15 的最终结果(没有四舍五入值)。
这是使用固定精度表示的性质,其值无法准确表示。
就像1/3
不能用固定的小数位数精确表示一样,0.1
也不能用固定的二进制位数精确表示。所以就像 3 x (1/3)
不可能给你 1 有固定的小数位数,添加 0.1
的倍数永远不会给你精确的二进制 1.
所以,让我们看一下六精度十进制表示,以便更清楚地看到这一点(this
用于指示值,而不是表示):
1
-> 1.000000
1/3
-> .333333
2/3
-> .666667
3
-> 3.000000
这给出:
1/3
+ 2/3
-> 0.333333 + 0.666667 -> 1.000000 -> 1
(耶)
1/3
+ 1/3
-> 0.333333 + 0.333333 -> 0.666666(不是 2/3
,好吧)
3
* 1/3
-> 3.00000 * 0.333333 -> .999999(不是 1
,好吧)
如何处理这取决于您,但这应该是预期的行为。
要解决你的最后一个问题,为什么"same thing"两种不同的方法会产生不同的结果,它来自中间舍入。如果您曾经使用计算器进行过计算,记下一些部分中间结果,您就会知道记下哪些中间结果会有所不同。
我猜这只是四舍五入的问题。如果您使用 seq.int
函数生成一个从 -10 到 10 的向量,然后执行 cumsum
,您将得到总和 0:
> 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
如果你真的想做一个介于 -1 和 1 之间的序列,那么只需将整数序列除以 10L
。
cumsum(seq.int(-10,10,1)/10L)
[1] -1.0 -1.9 -2.7 -3.4 -4.0 -4.5 -4.9 -5.2 -5.4 -5.5 -5.5 -5.4 -5.2 -4.9 -4.5 -4.0 -3.4 -2.7
[19] -1.9 -1.0 0.0
您仍将一如既往地处理一些舍入误差,但这似乎低于 R 舍入到 0 的阈值。
有人可以帮我理解为什么 -1 + 1 <> 0 吗?
有人能帮我理解为什么当内置函数 consum()、我的函数 ct() 和 Excel 都在做同样的事情时,我会得到三个不同的值吗?
现在,我很确定答案是 'round' 问题,但我无法弄清楚这部分问题的来源。我的意思是,这一切看起来都很简单。
在 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 循环中的最后一行更改为此,那么我将得到预期的答案 0:
result = round(result + x[I], digits = 2)
在 Excel 中,使用与我的 ct() 函数中相同的逻辑,我得到了 -2.886580E-15 的最终结果(没有四舍五入值)。
这是使用固定精度表示的性质,其值无法准确表示。
就像1/3
不能用固定的小数位数精确表示一样,0.1
也不能用固定的二进制位数精确表示。所以就像 3 x (1/3)
不可能给你 1 有固定的小数位数,添加 0.1
的倍数永远不会给你精确的二进制 1.
所以,让我们看一下六精度十进制表示,以便更清楚地看到这一点(this
用于指示值,而不是表示):
1
-> 1.000000
1/3
-> .333333
2/3
-> .666667
3
-> 3.000000
这给出:
1/3
+ 2/3
-> 0.333333 + 0.666667 -> 1.000000 -> 1
(耶)
1/3
+ 1/3
-> 0.333333 + 0.333333 -> 0.666666(不是 2/3
,好吧)
3
* 1/3
-> 3.00000 * 0.333333 -> .999999(不是 1
,好吧)
如何处理这取决于您,但这应该是预期的行为。
要解决你的最后一个问题,为什么"same thing"两种不同的方法会产生不同的结果,它来自中间舍入。如果您曾经使用计算器进行过计算,记下一些部分中间结果,您就会知道记下哪些中间结果会有所不同。
我猜这只是四舍五入的问题。如果您使用 seq.int
函数生成一个从 -10 到 10 的向量,然后执行 cumsum
,您将得到总和 0:
> 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
如果你真的想做一个介于 -1 和 1 之间的序列,那么只需将整数序列除以 10L
。
cumsum(seq.int(-10,10,1)/10L)
[1] -1.0 -1.9 -2.7 -3.4 -4.0 -4.5 -4.9 -5.2 -5.4 -5.5 -5.5 -5.4 -5.2 -4.9 -4.5 -4.0 -3.4 -2.7
[19] -1.9 -1.0 0.0
您仍将一如既往地处理一些舍入误差,但这似乎低于 R 舍入到 0 的阈值。