Точность функции 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, она также передаст это значение любым другим способом.

Другие вопросы по тегам