cpp/residue/residue.h
2023-07-16 10:03:47 +03:00

245 lines
6 KiB
C++

#include <vector>
#include <deque>
#include <iostream>
#include <algorithm>
using namespace std;
template<unsigned N, long long i>
struct is_prime_ {
static const bool value = !(N % i == 0) && is_prime_<N, (i + 1) * (i + 1) <= N ? (N % i == 0 ? 1 : i + 1) : -1>::value;
};
template<unsigned N>
struct is_prime_<N, 1LL> {
static const bool value = false;
};
template<unsigned N>
struct is_prime_<N, -1LL> {
static const bool value = true;
};
template<unsigned N>
struct is_prime {
static const bool value = (is_prime_<N, 2>::value && (N != 1)) || (N == 2);
};
template<unsigned N>
static const bool is_prime_v = is_prime<N>::value;
template<unsigned N, unsigned long long i, bool find_divider>
struct is_power_of_prime_ {
static const bool value = is_power_of_prime_<N % i == 0 ? N / i : (find_divider ? 0 : (i * i >= N ? 1 : N)), N % i == 0 ? i : i + 2, N % i == 0>::value;
};
template<unsigned long long i, bool find_divider>
struct is_power_of_prime_<1, i, find_divider> {
static const bool value = true;
};
template<unsigned long long i, bool find_divider>
struct is_power_of_prime_<0, i, find_divider> {
static const bool value = false;
};
template<unsigned N>
struct is_power_of_prime {
static const bool value = is_power_of_prime_<N, 3, false>::value;
};
template<unsigned N>
struct has_primitive_root {
static const bool value = is_power_of_prime<(N == 4 || N == 2 ? 1 : (N % 4 == 0 ? 0 : (N % 2 == 0 ? N / 2 : N)))>::value;
};
template<unsigned N>
static const bool has_primitive_root_v = has_primitive_root<N>::value;
template<bool T>
void my_static_assert() {
int* a = new int [T ? 1 : -1];
delete[] a;
}
unsigned phi(unsigned n) {
unsigned result = n;
for (int i = 2; i * i <= n; ++i) {
if (n % i == 0) {
while (n % i == 0) {
n /= i;
}
result -= result / i;
}
}
if (n > 1)
result -= result / n;
return result;
}
template<unsigned Modulus>
class Residue {
public:
Residue() = default;
Residue(const Residue<Modulus>& another) = default;
explicit Residue(long long x) : x(x) { Normilize(); }
explicit operator int() const { return x; }
bool operator==(const Residue<Modulus>& another) {
return x == another.x;
}
bool operator!=(const Residue<Modulus>& another) {
return !(*this == another);
}
Residue& operator+=(const Residue<Modulus>& another);
Residue& operator-=(const Residue<Modulus>& another);
Residue& operator*=(const Residue<Modulus>& another);
Residue& operator/=(const Residue<Modulus>& another);
Residue getInverse() const {
cerr << "getInverse " << x << " " << Modulus << endl;
my_static_assert<is_prime_v<Modulus>>();
return Residue(pow(x, Modulus - 2));
}
unsigned order() const {
cerr << "order " << x << " " << Modulus << endl;
unsigned phi = ::phi(Modulus);
unsigned copy_phi = phi;
std::vector<unsigned> first = {1}, second = {phi};
for (unsigned i = 2; i * i <= phi; ++i) {
if (copy_phi % i == 0) {
first.push_back(i);
second.push_back(phi / i);
}
}
std::reverse(second.begin(), second.end());
first.insert(first.end(), second.begin(), second.end());
for (unsigned i: first) {
if (pow(i) == Residue(1)) {
return i;
}
}
return 0;
}
static Residue getPrimitiveRoot() {
cerr << "getPrimitiveRoot " << Modulus << endl;
my_static_assert<has_primitive_root_v<Modulus>>();
if (Modulus == 2) {
return Residue(1);
} else if (Modulus == 4) {
return Residue(3);
}
unsigned phi = ::phi(Modulus);
unsigned copy_phi = phi;
std::vector<unsigned> deviders;
for (unsigned i = 2; i * i <= phi; ++i) {
if (copy_phi % i == 0) {
deviders.push_back(i);
deviders.push_back(phi / i);
while (copy_phi % i == 0) copy_phi /= i;
}
}
if (copy_phi > 1)
deviders.push_back(copy_phi);
for (unsigned res = 2; res < phi; ++res) {
bool ok = pow(res, phi) == 1;
for (unsigned i: deviders) {
ok &= pow(res, i) != 1;
}
if (ok) {
return Residue(res);
}
}
return Residue(phi);
}
Residue<Modulus> pow(unsigned degree) const;
private:
static int pow(int x, unsigned degree);
void Normilize() {
x %= static_cast<long long>(Modulus);
if (x < 0)
x += Modulus;
}
long long x;
};
template<unsigned Modulus>
Residue<Modulus>& Residue<Modulus>::operator+=(const Residue<Modulus>& another) {
x += another.x;
Normilize();
return *this;
}
template<unsigned Modulus>
Residue<Modulus>& Residue<Modulus>::operator-=(const Residue<Modulus>& another) {
x -= another.x;
Normilize();
return *this;
}
template<unsigned Modulus>
Residue<Modulus>& Residue<Modulus>::operator*=(const Residue<Modulus>& another) {
x *= another.x;
Normilize();
return *this;
}
template<unsigned Modulus>
Residue<Modulus>& Residue<Modulus>::operator/=(const Residue<Modulus>& another) {
*this *= another.getInverse();
return *this;
}
template<unsigned Modulus>
Residue<Modulus> operator+(const Residue<Modulus>& a, const Residue<Modulus>& b) {
Residue<Modulus> tmp(a);
tmp += b;
return tmp;
}
template<unsigned Modulus>
Residue<Modulus> operator-(const Residue<Modulus>& a, const Residue<Modulus>& b) {
Residue<Modulus> tmp(a);
tmp -= b;
return tmp;
}
template<unsigned Modulus>
Residue<Modulus> operator*(const Residue<Modulus>& a, const Residue<Modulus>& b) {
Residue<Modulus> tmp(a);
tmp *= b;
return tmp;
}
template<unsigned Modulus>
Residue<Modulus> operator/(const Residue<Modulus>& a, const Residue<Modulus>& b) {
Residue<Modulus> tmp(a);
tmp /= b;
return tmp;
}
template<unsigned Modulus>
Residue<Modulus> Residue<Modulus>::pow(unsigned degree) const {
return Residue(pow(x, degree));
}
template<unsigned Modulus>
int Residue<Modulus>::pow(int x, unsigned degree) {
if (degree == 0) {
return 1;
} else {
long long t = pow(x, degree / 2);
return (((t * t) % static_cast<long long>(Modulus)) * (degree % 2 == 0 ? 1 : x)) % static_cast<long long>(Modulus);
}
}