Следующий код явно неверен. В чем проблема?
i <- 0.1
i <- i + 0.05
i
## [1] 0.15
if(i==0.15) cat("i equals 0.15") else cat("i does not equal 0.15")
## i does not equal 0.15
r
floating-point
floating-accuracy
r-faq
dplanet
источник
источник
Ответы:
Общая (языковая независимость) причина
Поскольку не все числа могут быть представлены точно в арифметике IEEE с плавающей точкой (стандарт, который почти все компьютеры используют для представления десятичных чисел и выполнения с ними математических операций ), вы не всегда получите то, что ожидали. Это особенно верно, потому что некоторые значения, которые являются простыми конечными десятичными знаками (такими как 0,1 и 0,05), не представлены точно в компьютере, и поэтому результаты арифметики на них могут не дать результат, который идентичен прямому представлению " известный "ответ.
Это хорошо известное ограничение компьютерной арифметики, которое обсуждается в нескольких местах:
Сравнение скаляров
Стандартным решением этой проблемы
R
является не использование==
, аall.equal
функция. Или , вернее, так какall.equal
дает много деталей о различиях , если таковые имеются,isTRUE(all.equal(...))
.доходность
Еще несколько примеров использования
all.equal
вместо==
(последний пример должен показать, что это правильно покажет различия).Еще несколько подробностей, прямо скопированных из ответа на аналогичный вопрос :
Проблема, с которой вы столкнулись, заключается в том, что в большинстве случаев с плавающей запятой невозможно точно представить десятичные дроби, что означает, что вы часто обнаружите, что точное совпадение не удается.
в то время как R слегка врет, когда вы говорите:
Вы можете узнать, что он действительно думает в десятичном виде:
Вы можете видеть, что эти цифры разные, но представление немного громоздкое. Если мы посмотрим на них в двоичном (ну, в шестнадцатеричном, что эквивалентно), мы получим более четкую картину:
Вы можете видеть, что они отличаются на
2^-53
, что важно, потому что это число является наименьшей представимой разницей между двумя числами, значение которых близко к 1, как это.Мы можем узнать для любого данного компьютера, что это наименьшее представимое число, посмотрев в поле машины R :
Вы можете использовать этот факт для создания функции «почти равно», которая проверяет, что разница близка к наименьшему представимому числу в плавающей точке. На самом деле это уже существует
all.equal
.Таким образом, функция all.equal фактически проверяет, что разница между числами является квадратным корнем наименьшего различия между двумя мантиссами.
Этот алгоритм выглядит немного смешно рядом с очень маленькими числами, называемыми денормальными, но вам не нужно об этом беспокоиться.
Сравнение векторов
Приведенное выше обсуждение предполагает сравнение двух отдельных значений. В R нет скаляров, только векторы, и неявная векторизация является сильной стороной языка. Для сравнения значения векторов по элементам, предыдущие принципы верны, но реализация немного отличается.
==
векторизован (выполняет поэлементное сравнение), в то времяall.equal
как целые векторы сравниваются как единое целое.Используя предыдущие примеры
==
не дает "ожидаемого" результата иall.equal
не выполняет поэлементноСкорее версия, которая зацикливается на двух векторах, должна использоваться
Если функциональная версия этого желательна, она может быть написана
который можно назвать просто
В качестве альтернативы, вместо того, чтобы включать
all.equal
еще больше вызовов функций, вы можете просто скопировать соответствующие внутренние компонентыall.equal.numeric
и использовать неявную векторизацию:Это подход
dplyr::near
, который документирует себя какисточник
Добавив комментарий Брайана (что является причиной), вы можете изменить это, используя
all.equal
вместо этого:За предупреждением Джошуа вот обновленный код (спасибо Джошуа):
источник
all.equal
не возвращается,FALSE
когда есть различия, поэтому вам нужно обернуть егоisTRUE
при использовании вif
выражении.Это хакерский, но быстрый
источник
all.equal(... tolerance)
параметр.all.equal(0.147, 0.15, tolerance=0.05)
правда.dplyr::near()
опция для проверки, если два вектора чисел с плавающей точкой равны Это пример из документов :Функция имеет встроенный параметр допуска:
tol = .Machine$double.eps^0.5
его можно настроить. Параметр по умолчанию совпадает с параметром по умолчанию дляall.equal()
.источник
У меня была похожая проблема. Я использовал следующее решение.
вывод неравных интервалов резки в зависимости от параметров (цифры = 2):
вывод равных интервалов среза на основе функции округления:
источник
Обобщенные сравнения ("<=", "> =", "=") в арифметике с двойными прецизионами:
Сравнивая <= b:
Сравнивая a> = b:
Сравнивая а = б:
источник