cai_lw's competitive programming library
 
Loading...
Searching...
No Matches
sqrt.hpp
1#pragma once
2
3#include <optional>
4
5#include "cplib/num/mmint.hpp"
6#include "cplib/num/pow.hpp"
7
8namespace cplib {
9
24template <typename Fp>
25std::optional<Fp> sqrt_mod_fp(Fp n) {
26 const Fp fp0(0), fp1(1);
27 auto p = Fp::mod();
28 if (n == fp0 || p == 2) {
29 return n;
30 } else if (pow(n, (p - 1) / 2) != fp1) {
31 return std::nullopt;
32 } else if (p % 4 == 3) {
33 return pow(n, (p + 1) / 4);
34 }
35 Fp a(0), w2;
36 do {
37 a += fp1;
38 w2 = a * a - n;
39 } while (pow(w2, (p - 1) / 2) == fp1);
40 std::pair<Fp, Fp> pow{a, fp1};
41 std::pair<Fp, Fp> ret{fp1, fp0};
42 auto e = (p + 1) / 2;
43 while (e) {
44 auto [ap, bp] = pow;
45 if (e & 1) {
46 auto [ar, br] = ret;
47 // Save one multiplication using the Karatsuba technique
48 Fp arap = ar * ap;
49 Fp brbp = br * bp;
50 Fp arbp_brap = (ar + br) * (ap + bp) - (arap + brbp);
51 ret = {arap + brbp * w2, arbp_brap};
52 }
53 Fp apbp = ap * bp;
54 pow = {ap * ap + bp * bp * w2, apbp + apbp};
55 e >>= 1;
56 }
57 return ret.first;
58}
59
69template <typename T, std::enable_if_t<std::is_unsigned_v<T>>* = nullptr>
70std::optional<T> sqrt_mod_prime(T n, T p) {
71 if (p == 2) {
72 // Cannot use MontgomeryModInt since 2 is even.
73 return n % 2;
74 }
75 return mmint_by_modulus(
76 [](const auto& n_mod_p) {
77 auto ret = sqrt_mod_fp(n_mod_p);
78 return ret ? ret->val() : std::optional<T>();
79 },
80 p, n);
81}
82
83} // namespace cplib
constexpr T pow(T base, uint64_t exp, Op &&op={})
A generic exponetiation by squaring function.
Definition: pow.hpp:14
std::optional< T > sqrt_mod_prime(T n, T p)
Square root modulo a prime number.
Definition: sqrt.hpp:70
std::optional< Fp > sqrt_mod_fp(Fp n)
Square root modulo a prime number.
Definition: sqrt.hpp:25