Целочисленный квадратный корень
В теории чисел целочисленный квадратный корень (isqrt) из неотрицательного целого числа n — это неотрицательное целое число m, которое является наибольшим целым числом, меньшим или равным квадратному корню из n ,
Например,
Вступительное замечание
[ редактировать ]Позволять и быть неотрицательными целыми числами.
Алгоритмы вычисления ( десятичное представление ) работать вечно на каждом входе что не является идеальным квадратом . [примечание 1]
Алгоритмы, которые вычисляют не бегай вечно . Тем не менее, они способны вычислять с любой желаемой точностью .
Выбирайте любой и вычислить .
Например (установка ):
Сравните результаты с
Оказывается, что умножение входных данных на дает точность k десятичных цифр. [примечание 2]
Чтобы вычислить (полное) десятичное представление , можно выполнить бесконечное число раз, увеличивая по фактору на каждом проходе.
Предположим, что в следующей программе ( ) процедура уже определено и — ради аргумента — что все переменные могут содержать целые числа неограниченной величины.
Затем напечатает все десятичное представление . [примечание 3]
// Печатаем sqrt(y), не останавливаясь void sqrtForever ( unsigned int y ) { unsigned int result = isqrt ( y ); printf ( "%d." , результат ); // вывести результат, за которым следует десятичная точка while ( true ) // повторять вечно ... { y = y * 100 ; // теоретический пример: переполнение игнорируется result = isqrt ( y ); printf ( "%d" , результат % 10 ); // выводим последнюю цифру результата } }
Вывод состоит в том, что алгоритмы, вычисляющие isqrt()
вычислительно эквивалентны алгоритмам, которые вычисляют sqrt()
. [1]
Основные алгоритмы
[ редактировать ]Целый квадратный корень из неотрицательного целого числа можно определить как
Например, потому что .
Алгоритм с использованием линейного поиска
[ редактировать ]Следующие программы на языке C представляют собой простую реализацию.
// Целочисленный квадратный корень // (с использованием линейного поиска по возрастанию) unsigned int isqrt ( unsigned int y ) { // начальное занижение, L <= isqrt(y) unsigned int L = 0 ; в то время как (( L + 1 ) * ( L + 1 ) <= y ) L знак равно L + 1 ; вернуть Л ; }
// Целочисленный квадратный корень // (с использованием линейного поиска по убыванию) unsigned int isqrt ( unsigned int y ) { // начальное завышение, isqrt(y) <= R unsigned int R = y ; в то время как ( р * р > y ) р знак равно р - 1 ; вернуть Р ; }
Линейный поиск с использованием сложения
[ редактировать ]В приведенной выше программе (линейный поиск по возрастанию) можно заменить умножение сложением, используя эквивалентность
// Целочисленный квадратный корень // (линейный поиск, по возрастанию) с использованием сложения unsigned int isqrt ( unsigned int y ) { unsigned int L = 0 ; беззнаковое целое число = 1 ; беззнаковое целое число d = 3 ; в то время как ( а <= y ) { а знак равно а + d ; // (а + 1) ^ 2 d = d + 2 ; Л = Л + 1 ; } Вернуть Л ; }
Алгоритм, использующий бинарный поиск
[ редактировать ]Линейный поиск последовательно проверяет каждое значение, пока не достигнет наименьшего. где .
Ускорение достигается за счет использования вместо этого двоичного поиска . Следующая C-программа является реализацией.
// Целочисленный квадратный корень (с использованием двоичного поиска) unsigned int isqrt ( unsigned int y ) { unsigned int L = 0 ; беззнаковый интервал M ; беззнаковый int R = y + 1 ; в то время как ( L != р - 1 ) { M знак равно ( L + р ) / 2 ; если ( M * M <= y ) L знак равно M ; иначе Р = М ; } Вернуть Л ; }
Численный пример
Например, если вычислить используя бинарный поиск, можно получить последовательность
Это вычисление занимает 21 итерацию, тогда как линейный поиск (по возрастанию, начиная с ) нужно 1414 шагов.
Алгоритм с использованием метода Ньютона
[ редактировать ]Один из способов расчета и заключается в использовании метода Герона , который является частным случаем метода Ньютона , для нахождения решения уравнения , давая итерационную формулу
Последовательность сходится квадратично к как .
Критерий остановки
[ редактировать ]Можно доказать [ нужна ссылка ] что — максимально возможное число, для которого критерий остановки обеспечивает в алгоритме выше.
В реализациях, которые используют числовые форматы, которые не могут точно представлять все рациональные числа (например, с плавающей запятой), следует использовать останавливающую константу меньше 1 для защиты от ошибок округления.
Область вычислений
[ редактировать ]Хотя иррационально для многих , последовательность содержит только рациональные члены, когда является рациональным. Таким образом, при этом методе нет необходимости выходить из поля рациональных чисел, чтобы вычислить , факт, который имеет некоторые теоретические преимущества.
Использование только целочисленного деления
[ редактировать ]Для вычислений для очень больших целых чисел n можно использовать частное евклидова деления для обеих операций деления. Это имеет то преимущество, что для каждого промежуточного значения используются только целые числа, что делает ненужным использование с плавающей запятой представлений больших чисел . Это эквивалентно использованию итерационной формулы
Используя тот факт, что
можно показать, что это достигнет за конечное число итераций.
В оригинальной версии есть для , и для . Итак, в целочисленной версии имеем и до окончательного решения достигается. Для окончательного решения , у одного есть и , поэтому критерием остановки является .
Однако, не обязательно является фиксированной точкой приведенной выше итерационной формулы. Действительно, можно показать, что является фиксированной точкой тогда и только тогда, когда не является идеальным квадратом. Если является идеальным квадратом, последовательность завершается циклом второго периода между и вместо того, чтобы сходиться.
Пример реализации на C
[ редактировать ]// Квадратный корень из целого числа unsigned int int_sqrt ( unsigned int s ) { // Ноль дает ноль // Единица дает единицу if ( s <= 1 ) return s ; // Начальная оценка (должна быть слишком высокой) unsigned int x0 = s / 2 ; // Обновляем unsigned int x1 = ( x0 + s / x0 ) / 2 ; while ( x1 < x0 ) // Проверка границ { x0 = x1 ; х1 знак равно ( х0 + s / х0 ) / 2 ; } Вернуть х0 ; }
Численный пример
[ редактировать ]Например, если вычислить целый квадратный корень из 2000000 , используя приведенный выше алгоритм, можно получить последовательность Всего необходимо 13 итераций. Хотя метод Герона сходится квадратично близко к решению, в начале достигается точность менее одного бита на итерацию. Это означает, что выбор начальной оценки имеет решающее значение для производительности алгоритма.
быстрое вычисление целой части двоичного логарифма или длины бита (например, Когда доступно std::bit_width
в C++20 ), лучше начать с что является наименьшей степенью двух больше, чем . В примере целочисленного квадратного корня из 2000000 , , , и результирующая последовательность В этом случае необходимо всего четыре шага итерации.
Поразрядный алгоритм
[ редактировать ]Традиционный с помощью ручки и бумаги. алгоритм вычисления квадратного корня основан на работе от более высоких цифр к меньшим, и по мере того, как каждая новая цифра выбирает самую большую, которая по-прежнему дает квадрат . Если остановиться после единицы, вычисленный результат будет целым квадратным корнем.
Использование побитовых операций
[ редактировать ]При работе с базой 2 выбор цифры упрощается до выбора между 0 («маленький кандидат») и 1 («большой кандидат»), а манипуляции с цифрами могут быть выражены с помощью операций двоичного сдвига. С *
будучи умножением, <<
будучи левой сменой, и >>
будучи логическим сдвигом вправо, рекурсивный алгоритм нахождения целого квадратного корня из любого натурального числа :
def целое_sqrt ( n : int ) -> int : утверждать n >= 0 , «sqrt работает только для неотрицательных входных данных», если n < 2 : return n # Рекурсивный вызов: small_cand = целое_sqrt ( n >> 2 ) << 1 big_cand = small_cand + 1 if big_cand * big_cand > n : return small_cand else : return big_cand # эквивалентно: def целое_sqrt_iter ( n : int ) -> int : утверждать n >= 0 , «sqrt работает только для неотрицательных входных данных» , если n < 2 : return n # Найти сумму сдвига. См. также [[найти первый набор]], # сдвиг = ceil(log2(n) * 0,5) * 2 = ceil(ffs(n) * 0,5) * 2 сдвиг = 2 while ( n >> сдвиг ) != 0 : сдвиг += 2 # Разворачиваем цикл установки битов. result = 0 whileshift ) >= 0 : result = result << 1 big_cand = ( result + 1 if что и result ^ 1 (xor), потому что последний бит всегда равен 0. # То же , big_cand * big_cand <= n >> сдвиг : result = big_cand сдвиг -= 2 возвращает результат
Традиционные описания поразрядного алгоритма на бумаге включают в себя различные оптимизации, отсутствующие в приведенном выше коде, в частности, трюк предварительного вычитания квадрата предыдущих цифр, что делает ненужным общий шаг умножения. Пример см . в разделе «Методы вычисления квадратных корней § Двоичная система счисления (основание 2») . [2]
В языках программирования
[ редактировать ]Некоторые языки программирования выделяют явную операцию для вычисления квадратного корня целого числа в дополнение к общему случаю или могут быть расширены с этой целью библиотеками.
(isqrt x)
: Общий Лисп . [3]math.isqrt(x)
: Питон . [4]
См. также
[ редактировать ]Примечания
[ редактировать ]- ^ Квадратные корни идеальных квадратов (например, 0, 1, 4, 9, 16) являются целыми числами. Во всех остальных случаях квадратные корни натуральных чисел являются иррациональными числами.
- ^ Неудивительно, что повторное умножение на 100 является особенностью Джарвиса (2006).
- ^ Дробная часть квадратных корней из полных квадратов отображается как 000... .
Ссылки
[ редактировать ]- ^ см. « Методы вычисления квадратных корней ».
- ^ Ву, К. (июнь 1985 г.). «Квадратный корень по алгоритму счетов (в архиве)» . Архивировано из оригинала 06 марта 2012 г.
- ^ ЛиспВоркс Лтд. (1996). «CLHS: Функция SQRT, ISQRT» . www.lispworks.com .
- ^ Фонд программного обеспечения Python (2001). «Математические функции» . Документация стандартной библиотеки Python . (начиная с версии 3.8).
Внешние ссылки
[ редактировать ]- Джарвис, Эшли Фрейзер (2006). «Квадратные корни путем вычитания» (PDF) . Математический спектр . 37 : 119–122.
- Мински, Марвин (1967). «9. Вычислимые действительные числа». Вычисления: конечные и бесконечные машины . Прентис-Холл. ISBN 0-13-165563-9 . OCLC 0131655639 .
- «Геометрический взгляд на алгоритм извлечения квадратного корня» .