Безопасно ли сравнивать два двойных числа с помощью оператора равенства? - PullRequest
4 голосов
/ 02 марта 2011

Я знаю, что вы никогда не должны сравнивать значение с плавающей запятой, используя оператор равенства == в .NET, но безопасно ли это делать, если два числа были получены с использованием Math.Floor?

Я работаю с картографической программой, и фрагменты карты хранятся в разных «региональных» файлах. Я могу определить, какую область получить, разделив координаты мира на 16 и получив результат, который дает мне координаты региона.

По сути, я спрашиваю, будут ли сравниваться два одинаковых значения, которые имеют одинаковую целую часть числа (например, 4.3 и 4.8), которые находятся на полу, как оператор ==.

Ответы [ 3 ]

5 голосов
/ 02 марта 2011

Общая проблема сравнений с плавающей запятой состоит в том, что они могут легко накапливать ошибку округления.Когда вы берете значение типа 1.2 (которое не может быть точно в десятичном виде), умножьте его на 100 и сравните его на равенство 120.Рекомендуется всегда сравнивать разницу следующим образом:

var a = 1.2;
a *= 100;

if (a - 120 < 0.0001)
{
}

Операция Math.Floor всегда приводит к целочисленному значению.То есть любые дробные значения будут усечены, а целое значение точное останется.

Итак, если ваша семантика действительно равна для использования пола, вы в безопасности.

Однако, если вы действительно пытаетесь округлить, используйте вместо этого Math.Round ().

4 голосов
/ 02 марта 2011

Ну, это зависит от того, что вы пытаетесь сделать.

Это скажет вам, равны ли значения этажей - но если один вход был просто smidge меньше 2, а один вход был просто smidge более 2, то они ' будет выглядеть иначе, несмотря на то, что они потенциально крошечные.

Это нормально для вашего сценария? В некоторых случаях это будет, в некоторых - нет.

2 голосов
/ 02 марта 2011

Я думаю, что ваш вопрос основан на ошибочном предположении. Совершенно безопасно сравнивать значения с плавающей запятой, используя == в .Net. Единственное странное поведение, связанное с == и значениями с плавающей запятой, заключается в том, что Double.NaN и Single.NaN по сравнению с самими собой с == вернут false (как диктуется спецификацией с плавающей запятой).

Использование Math.Floor не делает эту ситуацию лучше. Если любое из специальных значений с плавающей запятой (NaN, NegativeInfinity, PositiveInfinity) передается в Math.Floor, они возвращаются без изменений. Таким образом, сравнение через == все равно будет иметь странное поведение ( Reference )

Основной эффект при использовании Math.Floor будет иметь большее число плавающих значений будут сравниваться равными друг другу. Например, 7.1 и 7.5 будут равны после Math.Floor. По сути, это не лучше, но может быть в контексте вашего приложения, но трудно сказать, что будет без дополнительной информации. Не могли бы вы рассказать подробнее о том, почему вы думаете == небезопасно?

...