algo

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub dnx04/algo

:heavy_check_mark: math/ModSQRT.h

Verified with

Code

i64 modsqrt(i64 a, i64 p) {
  a %= p;
  if (a < 0) a += p;
  if (a == 0) return 0;

  if (modpow(a, (p - 1) / 2, p) != 1) return -1;
  if (p % 4 == 3) return modpow(a, (p + 1) / 4, p);
  // a^(n+3)/8 or 2^(n+3)/8 * 2^(n-1)/4 works if p % 8 == 5
  i64 s = p - 1, n = 2;
  int r = 0, m;
  while (s % 2 == 0) ++r, s /= 2;
  /// find a non-square mod p
  while (modpow(n, (p - 1) / 2, p) != p - 1) ++n;
  i64 x = modpow(a, (s + 1) / 2, p);
  i64 b = modpow(a, s, p), g = modpow(n, s, p);
  for (;; r = m) {
    i64 t = b;
    for (m = 0; m < r && t != 1; ++m) t = t * t % p;
    if (m == 0) return x;
    i64 gs = modpow(g, 1LL << (r - m - 1), p);
    g = gs * gs % p;
    x = x * gs % p;
    b = b * g % p;
  }
}
#line 1 "math/ModSQRT.h"
i64 modsqrt(i64 a, i64 p) {
  a %= p;
  if (a < 0) a += p;
  if (a == 0) return 0;

  if (modpow(a, (p - 1) / 2, p) != 1) return -1;
  if (p % 4 == 3) return modpow(a, (p + 1) / 4, p);
  // a^(n+3)/8 or 2^(n+3)/8 * 2^(n-1)/4 works if p % 8 == 5
  i64 s = p - 1, n = 2;
  int r = 0, m;
  while (s % 2 == 0) ++r, s /= 2;
  /// find a non-square mod p
  while (modpow(n, (p - 1) / 2, p) != p - 1) ++n;
  i64 x = modpow(a, (s + 1) / 2, p);
  i64 b = modpow(a, s, p), g = modpow(n, s, p);
  for (;; r = m) {
    i64 t = b;
    for (m = 0; m < r && t != 1; ++m) t = t * t % p;
    if (m == 0) return x;
    i64 gs = modpow(g, 1LL << (r - m - 1), p);
    g = gs * gs % p;
    x = x * gs % p;
    b = b * g % p;
  }
}
Back to top page