Когда тесты на равенство работают и не работают с числами с плавающей запятой
Вы должны узнать о представлении чисел с плавающей запятой в памяти компьютера.Смотрите другие ответы для полезных ссылок.Фактически, строгое сравнение (==)
почти никогда не работает над ними надежно.
Большинство действительных чисел не могут быть точно представлены с помощью машинной плавающей запятой.Только немногие из них (например, i/2^n
, где i
и n
- целые числа) представлены точно.Другие нет.Это подразумевает, что в общем случае тест на равенство имеет непредсказуемый результат для чисел с плавающей запятой, и единственная ситуация, в которой вы можете его использовать, - это когда вы знаете, что это число в приведенной выше форме.Это может хорошо работать при планировании и написании тестов.
Три подхода
Обходной путь должен использовать меньше чем или больше чем тесты с плавающей запятойчисел большую часть времени (или использовать рациональные числа).Если вы все еще хотите сравнить два числа с плавающей запятой (например, в тестах), вы можете определить точность сравнения.
ghci> let eq tol a b = tol > abs (a-b)
ghci> eq 1e-6 4 3.9999999999999999
True
ghci> eq 1e-6 (10.2^2) 104.04
True
Вы также можете рассмотреть возможность использования (~==)
приблизительного сравнения с ieee754 пакет.Но точность результатов в большинстве реальных вычислений значительно ниже точности типов обработки с плавающей запятой, поэтому все же имеет смысл допустить некоторую ошибку.
Ответ
Почему второе выражение возвращает False?
104.04 должно быть 2601/25, а не число в форме i/2^n
, поэтому его нельзя точно представить с помощью чисел с плавающей запятой (по умолчанию GHCi Double
, наверное).Так получилось, что на вашей платформе 10.2 ^ 2 не равно 104.04.На другой платформе они могли бы оказаться равными.
Однако, если бы вы использовали рациональные числа, они были бы равны:
ghci> (102%10)^2 == (10404%100)
True