Сравнение дробного типа - PullRequest
3 голосов
/ 18 мая 2011
ghci> 4 == 3.9999999999999999
True

ghci> 10.2^2 == 104.04
False

Почему второе выражение возвращает False?

Ответы [ 4 ]

9 голосов
/ 18 мая 2011

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

Некоторые ссылки на числа с плавающей точкой:

Попробуйте использовать тип Rational в Haskell , если вам нужна здесь правильная математика, но обратите внимание, что она поддерживает меньший диапазон операций и меньше аппаратной поддержки.

Prelude> 4 == (3.9999999999999 :: Rational)
False
Prelude> 10.2^2 == (104.04 :: Rational)
True
3 голосов
/ 18 мая 2011

Когда тесты на равенство работают и не работают с числами с плавающей запятой

Вы должны узнать о представлении чисел с плавающей запятой в памяти компьютера.Смотрите другие ответы для полезных ссылок.Фактически, строгое сравнение (==) почти никогда не работает над ними надежно.

Большинство действительных чисел не могут быть точно представлены с помощью машинной плавающей запятой.Только немногие из них (например, 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
1 голос
/ 18 мая 2011

Это просто случай округления.Если вы просто введете 3.9999999999999999 в GHCI, вы увидите, что оно округляется до 4.0, что явно равно 4. 10.2 ^ 2 оценивается как 104.03999999999999, который не округляется и не равен 104.04.Причина неправильной оценки, о которой вы, возможно, уже знаете, кроется в арифметических задачах с плавающей точкой .

...