В чем разница между этими двумя сравнениями?
Возможный дубликат:
Почему эти цифры не равны?
0.9 == 1-0.1 >>> TRUE
0.9 == 1.1-0.2 >>> FALSE
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 FAQ.
Ответ для мазохистов:
Проблема, с которой вы столкнулись, заключается в том, что в большинстве случаев с плавающей запятой нельзя точно представить десятичные дроби, что означает, что вы часто обнаружите, что точное совпадение не удается.
в то время как 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 фактически проверяет, что разница между числами является квадратным корнем наименьшего различия между двумя мантиссами.
Этот алгоритм выглядит немного смешно рядом с очень маленькими числами, называемыми денормальными, но вам не нужно об этом беспокоиться.
Вы должны быть осторожны в программировании, когда хотите проверить, равны ли два вычисленных числа. R будет предполагать, что вы имеете в виду "абсолютно равный", и что это означает, зависит от точности станка. Большинство чисел округлены с точностью до 53 двоичных цифр. Поэтому, как правило, два числа с плавающей запятой не будут надежно равны, если только они не были вычислены по одному и тому же алгоритму, и не всегда даже тогда. Вы можете увидеть это, возведя квадратный корень из 2 в квадрат: наверняка эти значения одинаковы?
x <- sqrt(2)
x * x == 2
[1] FALSE
Мы можем видеть, насколько эти два значения отличаются вычитанием:
1.1 - 0.2 - 0.9
[1] 1.110223e-16