Вычисление целочисленного квадратного корня

в 17:16, , рубрики: квадратный корень, математика, теория чисел

Возникла нужда проверить, является ли целое число квадратом, и если да, то вычислить корень. Причем хочется сделать это в целочисленной арифметике. Понятно, что можно реализовать метод Ньютона в целых числах, но он требует деления на каждом шаге. А нельзя ли по другому? Найти квадратный корень по модулю степени двойки, и проверить, а не будет ли он обычным квадратным корнем.

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

Для нечетного N и 2k, k > 3, если N ≡ 1 mod 8, то есть 4 разных корня по модулю 2k, а иначе корней нет. Нам нужен наименьший из этих четырех корней x. При этом другие три корня это 2k - x, 2k-1 + x и 2k - 2k-1 - x

Хочется что-то подобное вычислению обратного по модулю 2k — удваивая количество верных бит за итерацию.

Пусть у нас уже есть корень x0 из N по модулю 2k: N - x02 = 2ka
И мы хотим найти x1 = x0 + 2k-1y, такое чтобы в N - x12 было больше младших нулевых бит.
N - (x0 + 2k-1y)2 = 2ka - 2kx0 * y - 22k-2y2
Поделим на 2k: a - x0 * y - 2k-2y2
И приравняем к 0 по модулю 2k-2: y = a * x0-1 mod 2k-2
Получилии x1 = x0 + 2k-1a * (x0-1 mod 2k-2)
И окончательно x1 = x0 + (N - x02)/2 * (x0-1 mod 2k-2)

Из k бит на следующей итерации получится 2(k-1) бит. Параллельно считаем на каждой итерации обратное к корню.

Тестовый код:

uint8_t sqr16(uint16_t n) {
  if (n % 8 != 1) return 0;
  uint16_t sqr = (n + 1) / 2;  //4 bit
  uint16_t inv = 2 - sqr;

  sqr += inv * (n-sqr*sqr)/2;   //6 bit
  inv *= 2 - sqr * inv;

  sqr += inv * (n-sqr*sqr)/2;  //10 bit
  //inv *= 2 - sqr * inv;

  if (sqr & 256)
    sqr = 0u - sqr;
  sqr = (uint8_t)sqr; // lowest root
  if (n == sqr*sqr) return sqr;
  return 0;
}

Добавив пару итераций, получим корень из uint_64

Автор: paluke

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js