Точность функции C++ sqrt для полных квадратов
Позволять, x
является целым числом и y = x * x
,
Тогда гарантируется ли sqrt(y) == x
?
Например, могу ли я быть уверен, что sqrt(25)
или же sqrt(25.0)
вернусь 5.0
не 5.0000000003
или же 4.999999998
?
3 ответа
Нет, вы не можете быть гарантированы. Для целых чисел и их квадратов, которые соответствуют динамическому диапазону мантиссы типа с плавающей запятой (2^53 для типичного C / C++ double
), вы, вероятно, будете в порядке, но не обязательно гарантировано.
Следует избегать сравнений на равных между значениями с плавающей точкой и точными значениями, особенно точными целочисленными значениями. Режимы округления с плавающей точкой и другие подобные вещи могут действительно мешать вам.
Вы либо хотите использовать "диапазон сравнения", чтобы принять "примерно равный" результат, либо пересмотреть свой алгоритм в терминах целых чисел. Есть несколько вопросов Stackru, охватывающих сравнения равенства с плавающей точкой. Я предлагаю вам найти их и прочитать.
Для определенного класса задач я написал здесь альтернативное решение: найти n-й корень всех чисел в интервале
Это решение отличалось от подходов, отличных от хитрой арифметики с плавающей точкой.
Реализация, соответствующая стандарту IEEE-754, по разрешенным ошибкам для основных операций (из которых sqrt
пример) требует, чтобы значения были правильно округлены.
Это означает, что ошибка будет меньше, чем 1/2 ULP (единица на последнем месте) или в основном будет максимально приближена к фактическому ответу.
Чтобы ответить на ваш вопрос, если фактический ответ точно представлен double
тогда вы получите точный ответ.
Примечание: это не гарантируется стандартом C++, но стандартом IEEE-754, что, вероятно, не является проблемой для большинства людей.
В конечном счете, для ваших целей должно быть достаточно простого теста:
for(int i = 0; i < (int)std::sqrt(std::numeric_limits<int>::max()); i++)
{
assert((int)(double)i == i);//Ensure exactly representable, because why not
assert(std::sqrt((double)i*i) == i);
}
Если это пройдет, я не вижу причин для беспокойства.
Вы должны быть в состоянии грубо форсировать поиск всех значений до 2^26 довольно легко, но я считаю, что ответ - да. После этого номера нет.
Алгоритм за цифрой для квадратного корня заканчивается остатком == 0, что дает точные результаты. С другой стороны, если библиотека с плавающей запятой заявляет о совместимости ieee-754, она также передаст это значение любым другим способом.