Каково различие между этими двумя сравнениями? [дубликат]

10
задан Jaap 31 May 2018 в 08:00
поделиться

2 ответа

Ответ для исправления вашей программы:

> all.equal(0.9,1.1-0.2)
[1] TRUE
> all.equal(0.9, 1.1-0.3)
[1] "Mean relative difference: 0.1111111"
> isTRUE(all.equal(0.9, 1.1-0.3)
[1] FALSE

и если используется в коде:

if(isTRUE(all.equal(0.9,1.1-0.2)) {
   ....
}

или в векторах:

> vec1=0.9
> vec2=c(1.1-0.2,1.3-0.4,1.0-0.2)
> mapply(function(...)isTRUE(all.equal(...)),vec1, vec2)
[1]  TRUE  TRUE FALSE

Ответ для разумных людей:

Я рекомендую вам прочитать « что каждый компьютерный ученый должен знать о числах с плавающей запятой ». ( или здесь ).

Ричи также отмечает, что в часто задаваемых вопросах R упоминается эта проблема . Вам действительно стоит прочитать весь FAQ по R.

Ответ для мазохистов:

Проблема, с которой вы столкнулись, заключается в том, что в большинстве случаев числа с плавающей запятой не могут точно представлять десятичные дроби, а это означает, что вы часто обнаруживаете, что точное совпадение не выполняется.

в то время как R слегка лжет, когда вы говорите:

> 1.1-0.2
[1] 0.9
> 0.9
[1] 0.9

Вы можете узнать, что он на самом деле думает в десятичном виде:

> sprintf("%.54f",1.1-0.2)
[1] "0.900000000000000133226762955018784850835800170898437500"
> sprintf("%.54f",0.9)
[1] "0.900000000000000022204460492503130808472633361816406250"

Вы можете видеть, что эти числа разные, но представление немного громоздко. Если мы посмотрим на них в двоичном формате (ну, шестнадцатеричный, что эквивалентно), мы получим более четкую картину:

> sprintf("%a",0.9)
[1] "0x1.ccccccccccccdp-1"
> sprintf("%a",1.1-0.2)
[1] "0x1.ccccccccccccep-1"
> sprintf("%a",1.1-0.2-0.9)
[1] "0x1p-53"

Вы можете видеть, что они различаются на 2 ^ -53 , что важно, потому что это число наименьшая представимая разница между двумя числами, значение которых близко к 1, как это есть.

Мы можем узнать для любого компьютера, что это за наименьшее представимое число, посмотрев в поле машины R:

 > ?.Machine
 ....
 double.eps  the smallest positive floating-point number x 
 such that 1 + x != 1. It equals base^ulp.digits if either 
 base is 2 or rounding is 0; otherwise, it is 
 (base^ulp.digits) / 2. Normally 2.220446e-16.
 ....
 > .Machine$double.eps
 [1] 2.220446e-16
 > sprintf("%a",.Machine$double.eps)
 [1] "0x1p-52"

Вы можете использовать этот факт для создания функции «почти равно», которая проверяет, что разница близка к наименьшей представимое число с плавающей запятой. Фактически это уже существует (спасибо комментатору).

> ?all.equal
....
all.equal(x,y) is a utility to compare R objects x and y testing ‘near equality’.
....
all.equal(target, current,
      tolerance = .Machine$double.eps ^ 0.5,
      scale = NULL, check.attributes = TRUE, ...)
....

> all.equal(0.9,1.1-0.2)
[1] TRUE

Таким образом, функция all.equal фактически проверяет, является ли разница между числами квадратным корнем из наименьшей разницы между двумя мантиссами.

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

34
ответ дан 3 December 2019 в 13:54
поделиться

Нужно быть осторожным в программировании, когда вы хотите проверить, вычисляют ли два или нет. числа равны. R будет считать, что вы имеете в виду "точно равны", и что это значит. зависит от точности станка. Большинство чисел округлены до 53 двоичных разрядов точности. Поэтому, как правило, два числа с плавающей запятой не будут надежно равны, если только они не были вычисляется по одному и тому же алгоритму, и не всегда даже тогда. Вы можете увидеть это, если сравнить Квадратный корень 2: наверняка эти значения одинаковы?

x <- sqrt(2)
x * x == 2
[1] FALSE

Мы видим, насколько эти два значения различаются вычитанием:

1.1 - 0.2 - 0.9
[1] 1.110223e-16
5
ответ дан 3 December 2019 в 13:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: