Вещественный поиск
Почему «пока разность больше эпсилон» — плохое условие остановки, и что писать вместо него.
3 мин
Когда ответ — вещественное число, шаблон остаётся тем же, но условие остановки меняется. Здесь делают ошибку, которая не проявляется на маленьких тестах и потому доживает до закрытых.
Так делать не надо
while (high - low > 1e-9) { // цикл может не закончиться никогда
double mid = (low + high) / 2;
...
}
У чисел с плавающей точкой точность относительная, а не абсолютная. Рядом с нулём соседние представимые числа отличаются на ничтожную величину, а рядом с — примерно на .
Значит, если границы порядка , разность high - low никогда не станет меньше : она упрётся в шаг сетки представимых чисел и перестанет убывать. Цикл будет крутиться, пока не кончится время.
Коварство в том, что при малых значениях всё работает. Примеры из условия обычно малы.
Так надо
for (int step = 0; step < 200; step++) {
double mid = (low + high) / 2;
if (check(mid)) high = mid;
else low = mid;
}
Фиксированное число шагов. Каждый делит промежуток пополам, сто шагов уменьшают его в раз — несопоставимо меньше того, что вообще различает double. Двести шагов стоят двести вычислений check, то есть практически нисколько.
Такой цикл нельзя зациклить, он не зависит от масштаба чисел, и в нём нечего настраивать.
Сколько шагов брать
Промежуток длины после шагов имеет длину . Если нужна точность при , требуется шага.
Брать с запасом дёшево: 100 шагов покрывают любой разумный случай, 200 — вообще любой. Единственная причина считать точно — если check очень дорогая.
Точность ответа и точность вывода
Если условие обещает проверку с точностью , печатать надо больше знаков, чем требуется: девять после точки достаточно всегда.
printf("%.9f\n", answer);
cout << fixed << setprecision(9) << answer << "\n";
В Python — print(f"{answer:.9f}"). Обычный print для float даёт представление, которого проверяющей программе может не хватить.
Про верхнюю границу
Её стоит выводить из условия, а не брать «побольше». В задаче «найти , при котором » при ответ не превосходит : иначе уже вылезет за . Взять границей сам формально можно, но это лишние шаги и лишние проблемы с точностью на больших числах.
Когда вещественного поиска можно избежать
Часто задача с вещественным ответом сводится к целочисленной. «Максимальная длина куска» при целых длинах — это целое число сантиметров; «минимальное время» при целых скоростях — целое число секунд.
Целочисленный поиск проще: у него честное условие остановки, нет накопления погрешности и не надо думать про формат вывода. Если ответ можно сделать целым — сделайте.