In R why not -1 + 1 = 0

Can someone please help me understand why -1 + 1 <> 0?

Can someone please help me understand why I am getting three different values ​​between the built-in consum () function, my ct () function and Excel when they are all doing the same thing?

Now I'm sure the answer is "round", but I can't figure out where this part of this problem comes from. I mean it all looks pretty straight forward.

In R, when I construct the sequence "a" and then run cumsum (a), I don't get the result 0 as I expect. I also get a different answer if I try to calculate the same value using a function. Finally, I get the third answer if I try to calculate the same value using Excel.

This is what I am using 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

      

I wrote a quick function to test this and expected to get the same answer (or 0), but I get a completely different answer. Here is my function with its results:

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

      

If I change the last line in the for loop to this, then I get the expected 0 response:

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

      

In Excel, using the same logic as in my ct () function, I get the final result from -2.886580E-15 (no rounding of values).

+3


source to share


2 answers


This is the nature of using a fixed precision representation with values ​​that it cannot represent accurately.

Just as 1/3

it cannot be represented exactly with a fixed number of decimal places, 0.1

it cannot be accurately represented with a fixed number of binary places. Just as 3 x (1/3)

it can't give you 1 with a fixed number of decimal places, adding multiples 0.1

will never give you exactly 1 in a fixed-precision binary.

So, look at the ten-representation with six points, to see this more clearly ( this

used to indicate the value, not the ideas):
1

→ 1.000000
1/3

→ .333333
2/3

→ .666667
3

→ 3.000000

This gives:

1/3

+ 2/3

→ 0.333333 + 0.666667 → 1.000000 → 1

(yay)



1/3

+ 1/3

→ 0.3333333 + 0.3333333 → 0.6666666 (not 2/3

, oh good)

3

* 1/3

→ 3.00000 * 0.333333 → .999999 (no 1

, okay)

How you deal with this is up to you, but the behavior is to be expected from it.

To answer your last question, why "the same" two different ways can give different results, this comes from intermediate rounding. If you've ever done a calculation with a calculator, writing down some partial intermediate results, you know what can affect which intermediate results you write.

+5


source


I guess this just rounds up the issues. If you use a function seq.int

to make a vector from -10 to 10 and then do cumsum

, you get the sum of 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

      

If you really want to make a sequence between -1 and 1, then just split the whole sequence by 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

      

You will still be dealing with some rounding errors as always, but this appears to be below the R threshold of rounding to 0.

0


source







All Articles