Jump to content

Целочисленный квадратный корень

В теории чисел целочисленный квадратный корень (isqrt) из неотрицательного целого числа n — это неотрицательное целое число m, которое является наибольшим целым числом, меньшим или равным квадратному корню из n ,

Например,

Вступительное замечание

[ редактировать ]

Позволять и быть неотрицательными целыми числами.

Алгоритмы вычисления ( десятичное представление ) работать вечно на каждом входе что не является идеальным квадратом . [примечание 1]

Алгоритмы, которые вычисляют не беги вечно . Тем не менее, они способны вычислять с любой желаемой точностью .

Выбирайте любой и вычислить .

Например (установка ):

Сравните результаты с

Оказывается, что умножение входных данных на дает точность k десятичных цифр. [примечание 2]

Чтобы вычислить (полное) десятичное представление , можно выполнить бесконечное число раз, увеличивая по фактору на каждом проходе.

Предположим, что в следующей программе ( ) процедура уже определено и — ради аргумента — что все переменные могут содержать целые числа неограниченной величины.

Затем напечатает все десятичное представление . [примечание 3]

// Print sqrt(y), without halting
void sqrtForever(unsigned int y)
{
	unsigned int result = isqrt(y);
	printf("%d.", result);	// print result, followed by a decimal point

	while (true)	// repeat forever ...
	{
		y = y * 100;	// theoretical example: overflow is ignored
		result = isqrt(y);
		printf("%d", result % 10);	// print last digit of result
	}
}

Вывод состоит в том, что алгоритмы, вычисляющие isqrt() вычислительно эквивалентны алгоритмам, которые вычисляют sqrt(). [1]

Основные алгоритмы

[ редактировать ]

Целый квадратный корень из неотрицательного целого числа может быть определен как

Например, потому что .

[ редактировать ]

Следующие программы на языке C представляют собой простую реализацию.

// Integer square root
// (using linear search, ascending)
unsigned int isqrt(unsigned int y)
{
	// initial underestimate, L <= isqrt(y)
	unsigned int L = 0;

	while ((L + 1) * (L + 1) <= y)
		L = L + 1;

	return L;
}
// Integer square root
// (using linear search, descending)
unsigned int isqrt(unsigned int y)
{
	// initial overestimate, isqrt(y) <= R
	unsigned int R = y;

	while (R * R > y)
		R = R - 1;

	return R;
}

Линейный поиск с использованием сложения

[ редактировать ]

В приведенной выше программе (линейный поиск по возрастанию) можно заменить умножение сложением, используя эквивалентность

// Integer square root
// (linear search, ascending) using addition
unsigned int isqrt(unsigned int y)
{
	unsigned int L = 0;
	unsigned int a = 1;
	unsigned int d = 3;

	while (a <= y)
	{
		a = a + d;	// (a + 1) ^ 2
		d = d + 2;
		L = L + 1;
	}

	return L;
}
[ редактировать ]

Линейный поиск последовательно проверяет каждое значение, пока не достигнет наименьшего. где .

Ускорение достигается за счет использования вместо этого двоичного поиска . Следующая C-программа является реализацией.

// Integer square root (using binary search)
unsigned int isqrt(unsigned int y)
{
	unsigned int L = 0;
	unsigned int M;
	unsigned int R = y + 1;

    while (L != R - 1)
    {
        M = (L + R) / 2;

		if (M * M <= y)
			L = M;
		else
			R = M;
	}

    return L;
}

Численный пример

Например, если вычислить используя бинарный поиск, можно получить последовательность

Это вычисление занимает 21 итерацию, тогда как линейный поиск (по возрастанию, начиная с ) нужно 1414 шагов.

Алгоритм с использованием метода Ньютона

[ редактировать ]

Один из способов расчета и заключается в использовании метода Герона , который является частным случаем метода Ньютона , для нахождения решения уравнения , давая итерационную формулу

Последовательность сходится квадратично к как .

Критерий остановки

[ редактировать ]

Можно доказать [ нужна ссылка ] что — максимально возможное число, для которого критерий остановки обеспечивает в алгоритме выше.

В реализациях, которые используют числовые форматы, которые не могут точно представлять все рациональные числа (например, с плавающей запятой), следует использовать останавливающую константу меньше 1 для защиты от ошибок округления.

Область вычислений

[ редактировать ]

Хотя иррационально для многих , последовательность содержит только рациональные члены, когда является рациональным. Таким образом, при этом методе нет необходимости выходить из поля рациональных чисел, чтобы вычислить , факт, который имеет некоторые теоретические преимущества.

Использование только целочисленного деления

[ редактировать ]

Для вычислений для очень больших целых чисел n можно использовать частное евклидова деления для обеих операций деления. Это имеет то преимущество, что для каждого промежуточного значения используются только целые числа, что делает ненужным использование с плавающей запятой представлений больших чисел . Это эквивалентно использованию итерационной формулы

Используя тот факт, что

можно показать, что это достигнет за конечное число итераций.

В оригинальной версии есть для , и для . Итак, в целочисленной версии имеем и до окончательного решения достигается. Для окончательного решения , у одного есть и , поэтому критерием остановки является .

Однако, не обязательно является фиксированной точкой приведенной выше итерационной формулы. Действительно, можно показать, что является фиксированной точкой тогда и только тогда, когда не является идеальным квадратом. Если является идеальным квадратом, последовательность завершается циклом второго периода между и вместо того, чтобы сходиться.

Пример реализации на C

[ редактировать ]
// Square root of integer
unsigned int int_sqrt(unsigned int s)
{
	// Zero yields zero
    // One yields one
	if (s <= 1) 
		return s;

    // Initial estimate (must be too high)
	unsigned int x0 = s / 2;

	// Update
	unsigned int x1 = (x0 + s / x0) / 2;

	while (x1 < x0)	// Bound check
	{
		x0 = x1;
		x1 = (x0 + s / x0) / 2;
	}		
	return x0;
}

Численный пример

[ редактировать ]

Например, если вычислить целый квадратный корень из 2000000 , используя приведенный выше алгоритм, можно получить последовательность Всего необходимо 13 итераций. Хотя метод Герона сходится квадратично близко к решению, в начале достигается точность менее одного бита на итерацию. Это означает, что выбор начальной оценки имеет решающее значение для производительности алгоритма.

быстрое вычисление целой части двоичного логарифма или длины бита (например, Когда доступно std::bit_width в C++20 ), лучше начать с что является наименьшей степенью двух больше, чем . В примере целочисленного квадратного корня из 2000000 , , , и результирующая последовательность В этом случае необходимо всего четыре шага итерации.

Поразрядный алгоритм

[ редактировать ]

Традиционный с помощью ручки и бумаги. алгоритм вычисления квадратного корня основан на работе от более высоких цифр к меньшим, и по мере того, как каждая новая цифра выбирает самую большую, которая по-прежнему дает квадрат . Если остановиться после единицы, вычисленный результат будет целым квадратным корнем.

Использование побитовых операций

[ редактировать ]

При работе с базой 2 выбор цифры упрощается до выбора между 0 («маленький кандидат») и 1 («большой кандидат»), а манипуляции с цифрами могут быть выражены с помощью операций двоичного сдвига. С * будучи умножением, << будучи левой сменой, и >> будучи логическим сдвигом вправо, рекурсивный алгоритм нахождения целого квадратного корня из любого натурального числа :

def integer_sqrt(n: int) -> int:
    assert n >= 0, "sqrt works for only non-negative inputs"
    if n < 2:
        return n

    # Recursive call:
    small_cand = integer_sqrt(n >> 2) << 1
    large_cand = small_cand + 1
    if large_cand * large_cand > n:
        return small_cand
    else:
        return large_cand


# equivalently:
def integer_sqrt_iter(n: int) -> int:
    assert n >= 0, "sqrt works for only non-negative inputs"
    if n < 2:
        return n

    # Find the shift amount. See also [[find first set]],
    # shift = ceil(log2(n) * 0.5) * 2 = ceil(ffs(n) * 0.5) * 2
    shift = 2
    while (n >> shift) != 0:
        shift += 2

    # Unroll the bit-setting loop.
    result = 0
    while shift >= 0:
        result = result << 1
        large_cand = (
            result + 1
        )  # Same as result ^ 1 (xor), because the last bit is always 0.
        if large_cand * large_cand <= n >> shift:
            result = large_cand
        shift -= 2

    return result

Традиционные описания поразрядного алгоритма на бумаге включают в себя различные оптимизации, отсутствующие в приведенном выше коде, в частности, трюк предварительного вычитания квадрата предыдущих цифр, что делает ненужным общий шаг умножения. Пример см . в разделе «Методы вычисления квадратных корней» § Двоичная система счисления (основание 2) . [2]

В языках программирования

[ редактировать ]

Некоторые языки программирования в дополнение к общему случаю выделяют явную операцию для вычисления квадратного корня целого числа или могут быть расширены с этой целью библиотеками.

См. также

[ редактировать ]

Примечания

[ редактировать ]
  1. ^ Квадратные корни идеальных квадратов (например, 0, 1, 4, 9, 16) являются целыми числами. Во всех остальных случаях квадратные корни натуральных чисел являются иррациональными числами.
  2. ^ Неудивительно, что повторное умножение на 100 является особенностью Джарвиса (2006).
  3. ^ Дробная часть квадратных корней из полных квадратов отображается как 000... .
  1. ^ см. « Методы вычисления квадратных корней ».
  2. ^ Ву, К. (июнь 1985 г.). «Квадратный корень по алгоритму счетов (в архиве)» . Архивировано из оригинала 06 марта 2012 г.
  3. ^ ЛиспВоркс Лтд. (1996). «CLHS: Функция SQRT, ISQRT» . www.lispworks.com .
  4. ^ Фонд программного обеспечения Python (2001). «Математические функции» . Документация стандартной библиотеки Python . (начиная с версии 3.8).
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 6b907ce0cb7cc5f27e1974bc8cf59ced__1702427820
URL1:https://arc.ask3.ru/arc/aa/6b/ed/6b907ce0cb7cc5f27e1974bc8cf59ced.html
Заголовок, (Title) документа по адресу, URL1:
Integer square root - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)