2015-05-21 1 views
3

Может кто-то, пожалуйста, помогите мне понять, почему -1 + 1 <> 0?В R, почему нет -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 

Если изменить последнюю строку в цикл к этому, то я получаю ожидаемый ответ 0:

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

В Excel, используя то же самое логики, как и в моей функции ct(), я получаю окончательный результат от -2.886580E-15 (без округления значений).

ответ

5

Это характер использования представления с фиксированной точностью со значениями, которые он не может точно представлять.

Точно так же, как 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, а также хорошо)

Как вы справляетесь с этим, зависит от вас, но этого следует ожидать.

Чтобы ответить на ваш последний вопрос, почему «одно и то же» два разных способа могут давать разные результаты, он исходит из промежуточного округления. Если вы когда-либо делали вычисления с калькулятором, записывая некоторые частичные промежуточные результаты, вы знаете, что может повлиять на то, какие промежуточные результаты вы записываете.

+3

Также полезно, * R * FAQ # 7,31, [* "почему Безразлично 't R считают, что эти числа равны »* (http://cran.r-project.org/doc/FAQ/R-FAQ.html#Why-doesn_0027t-R-think-these-numbers-are-equal_003f) , – r2evans

+2

Я добавлю +1 что-нибудь, что цитирует [Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой] (http://www.validlab.com/goldberg/paper.pdf), даже косвенно. –

+2

и .. [Почему эти цифры не равны?] (Http://stackoverflow.com/questions/9508518/why-are-these-numbers-not-equal) –

0

Я бы предположил, что это просто проблемы округления. Если вы используете функцию 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 

Вы все еще будете иметь дело с некоторыми ошибками округления, как всегда, но это, кажется, ниже порога АиР округления до 0.