Если вы изучали основы работы
компьютера или же имели дело с программированием для этой чудо-машины, вы,
возможно, помните, что вам запрещали сравнивать действительные числа. По
крайней мере говорили делать это с крайней осторожностью.
Лично я совершенно позабыл причины
осторожной работы с действительными числами. Недавно, выполняя небольшое
задание, столкнулся с требованием: «… мы надеемся не увидеть применения оператора
== к операндам типа double…».
Решил освежить в памяти вопрос. Начну, пожалуй с маленького примера (1):
Пример 1:
double
x = 1.0;
while
(x != 0.0)
{
x
= x / 2;
Console.WriteLine(x);
}
В реальном мире цикл должен выполняться бесконечно. На деле же, если вы запустите программку, то зацикливания не произойдёт:
Объясняется это несложно. Мы знаем, что для хранения
действительных чисел компьютер отводит конечное число байт. Длинные числа
округляются таким образом, чтоб влезали в это количество байт. В цикле мы постоянно
делим x на 2. Таким образом x стремится к очень маленькому и очень длинному
числу. Выражаясь языком математики, x бесконечно
стремится к нулю, но никогда не принимает нулевое значение. Так происходит в жизни
реальной. В жизни компьютерной, когда x выходит
за пределы объёма отведённой ему памяти, он округляется до нуля.
Пример 2:
static
void Main(string[]
args)
{
for
(int i = 10; i > -10; i--)
{
try
{
Console.WriteLine(5
/ i);
}
catch
(Exception exep)
{
Console.WriteLine(exep.Message);
}
}
Console.ReadKey();
}
Видно, что при попытке выполнить
операцию 5/0 генерируется исключительная ситуация. Этого и следовало ожидать.
Теперь же смените в заголовке цикла фрагмент
int i = 10;
на
double
i = 10;
Рассмотрим результат выполнения фрагмента:
Теперь же при попытке выполнить
операцию 5/0 исключительная ситуация не генерируется, а результатом операции
становится бесконечность. Данный факт наводит на мысль о том, что
действительные числа в компьютере хранятся неточно.
Ребята со stackoverflow прокомментировали мой вопрос, созвучный с заголовком данной статейки. Для желающих копать глубже,
читайте следующее:
Выводы:
Действительные числа не портируемы. В разных
системах одно и тоже число будет представлено с разным порогом точности и соответственно
округлено по-разному.
Действительные числа в компьютере не всегда
подчиняются математическим правилам. Операции сравнения минимально отличающихся
друг от друга действительных чисел опасны. Особенно опасны операции проверки на
равенство и неравенство.
Вместо того, чтобы писать
double a, b;
...
if(a == b)
{
...
}
используйте нечто в
стиле
static const double SMALL_NUMBER = 0.000000000001; inline bool FloatNumbersAreEqual(double a, double b) { return (fabs((a) - (b)) < SMALL_NUMBER); }
Комментируйте пожалуйста.



Комментариев нет:
Отправить комментарий