[C#] Безопасно ли проверять значения с плавающей запятой на равенство 0?


Answers

Если вам нужно сделать много сравнений «равенства», может быть хорошей идеей написать небольшую вспомогательную функцию или метод расширения в .NET 3.5 для сравнения:

public static bool AlmostEquals(this double double1, double double2, double precision)
{
    return (Math.Abs(double1 - double2) <= precision);
}

Это можно использовать следующим образом:

double d1 = 10.0 * .1;
bool equals = d1.AlmostEquals(0.0, 0.0000001);
Question

Я знаю, что вы не можете полагаться на равенство между значениями двойного или десятичного типа, но мне интересно, является ли 0 особым случаем.

Хотя я могу понять неточности между 0.00000000000001 и 0.00000000000002, 0 сам по себе довольно сложно испортить, так как это просто ничего. Если вы неточенны ни на что, это уже ничего.

Но я не знаю много об этой теме, так что не для меня.

double x = 0.0;
return (x == 0.0) ? true : false;

Это всегда вернет истину?




На самом деле, я думаю, что лучше использовать следующие коды для сравнения двойного значения против 0.0:

double x = 0.0;
return (Math.Abs(x) < double.Epsilon) ? true : false;

То же самое для float:

float x = 0.0f;
return (Math.Abs(x) < float.Epsilon) ? true : false;



Если номер был назначен непосредственно для float или double, тогда можно безопасно протестировать нуль или любое целое число, которое может быть представлено в 53 битах для двойной или 24 бит для float.

Или, говоря иначе, вы всегда можете присваивать и целое значение двойнику, а затем сравнивать двойную спину с одним и тем же целым числом и быть гарантированным, что оно будет равным.

Вы также можете начать с присвоения целого числа, а простые сравнения продолжают работать, придерживаясь добавления, вычитания или умножения на целые числа (при условии, что результат меньше 24 бит для float abd 53 бит для double). Таким образом, вы можете обрабатывать поплавки и удваивать как целые числа в определенных контролируемых условиях.




Из записи MSDN для Double.Equals :

Точность в сравнении

Метод Equals следует использовать с осторожностью, поскольку два явно эквивалентных значения могут быть неравными из-за различной точности этих двух значений. В следующем примере показано, что двойное значение .3333 и Double возвращаются путем деления 1 на 3, являются неравными.

...

Вместо сравнения для равенства один рекомендуемый метод включает определение допустимого разницы между двумя значениями (например, 0,01% от одного из значений). Если абсолютное значение разницы между этими двумя значениями меньше или равно этому маржу, разница, вероятно, будет обусловлена ​​различиями в точности, и поэтому значения, вероятно, будут равны. В следующем примере этот метод используется для сравнения .33333 и 1/3, двух значений Double, которые, как было показано в предыдущем примере кода, были неравными.

Также см. Double.Epsilon .




Links