Как стать автором
Обновить

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

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

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

Для нечетного 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
Теги:
Хабы:
Всего голосов 29: ↑24 и ↓5+19
Комментарии13

Публикации

Истории

Ближайшие события

27 августа – 7 октября
Премия digital-кейсов «Проксима»
МоскваОнлайн
11 сентября
Митап по BigData от Честного ЗНАКа
Санкт-ПетербургОнлайн
14 сентября
Конференция Practical ML Conf
МоскваОнлайн
19 сентября
CDI Conf 2024
Москва
24 сентября
Конференция Fin.Bot 2024
МоскваОнлайн
25 сентября
Конференция Yandex Scale 2024
МоскваОнлайн
28 – 29 сентября
Конференция E-CODE
МоскваОнлайн
28 сентября – 5 октября
О! Хакатон
Онлайн
30 сентября – 1 октября
Конференция фронтенд-разработчиков FrontendConf 2024
МоскваОнлайн