Я писал поучительный пример для коллеги, чтобы показать ему, почему тестирование поплавков на равенство часто является плохой идеей. В примере, в котором я участвовал, добавлялось .1 десять раз и сравнивалось с 1.0 (тот, который я показал в моем вводном числовом классе). Я с удивлением обнаружил, что два результата были равны (code + output).
float @float = 0.0f;
for(int @int = 0; @int < 10; @int += 1)
{
@float += 0.1f;
}
Console.WriteLine(@float == 1.0f);
Некоторое расследование показало, что на этот результат нельзя положиться (подобно равенству поплавка). Наиболее удивительным было то, что добавление кода после другого кода может изменить результат вычисления (code + output). Обратите внимание, что этот пример имеет точно такой же код и IL, при этом добавляется еще одна строка С#.
float @float = 0.0f;
for(int @int = 0; @int < 10; @int += 1)
{
@float += 0.1f;
}
Console.WriteLine(@float == 1.0f);
Console.WriteLine(@float.ToString("G9"));
Я знаю, что я не должен использовать равенство в поплавках и, следовательно, не должен заботиться об этом слишком сильно, но я обнаружил, что это довольно удивительно, так же как и обо всех, кого я показал. Выполнение работы после выполнения вычисления изменяет значение предыдущего вычисления? Я не думаю, что модель вычислительных людей обычно имеет в виду.
Я не полностью зациклен, кажется безопасным предположить, что в "равном" случае, который меняет результат вычисления, существует какая-то оптимизация (построение в режиме отладки предотвращает "равный" случай). По-видимому, оптимизация прекращается, когда CLR обнаруживает, что позже ей нужно будет поместить float.
Я искал немного, но не мог найти причину такого поведения. Может ли кто-нибудь понять меня?