diff options
Diffstat (limited to 'zmodn.h')
| -rw-r--r-- | zmodn.h | 71 |
1 files changed, 71 insertions, 0 deletions
| @@ -0,0 +1,71 @@ | |||
| 1 | #ifndef ZMODN_H | ||
| 2 | #define ZMODN_H | ||
| 3 | |||
| 4 | #include <cstdint> | ||
| 5 | #include <iostream> | ||
| 6 | #include <optional> | ||
| 7 | #include <tuple> | ||
| 8 | |||
| 9 | std::tuple<int64_t, int64_t, int64_t> extended_gcd(int64_t, int64_t); | ||
| 10 | |||
| 11 | template<int64_t N> requires(N > 1) | ||
| 12 | class Zmod { | ||
| 13 | public: | ||
| 14 | Zmod(int64_t z) : int64{(z%N + N) % N} {} | ||
| 15 | int64_t toint64() const { return int64; } | ||
| 16 | |||
| 17 | Zmod operator+(const Zmod& z) const { return int64 + z.int64; } | ||
| 18 | Zmod operator-(const Zmod& z) const { return int64 - z.int64; } | ||
| 19 | Zmod operator*(const Zmod& z) const { return int64 * z.int64; } | ||
| 20 | Zmod operator+=(const Zmod& z) { return int64 += z.int64; } | ||
| 21 | Zmod operator-=(const Zmod& z) { return int64 -= z.int64; } | ||
| 22 | Zmod operator*=(const Zmod& z) { return int64 *= z.int64; } | ||
| 23 | |||
| 24 | bool operator==(const Zmod& z) const { return int64 == z.int64; } | ||
| 25 | bool operator!=(const Zmod& z) const { return int64 != z.int64; } | ||
| 26 | |||
| 27 | std::optional<Zmod> inverse() const { | ||
| 28 | auto [g, a, _] = extended_gcd(int64, N); | ||
| 29 | return g == 1 ? Zmod(a) : std::optional<Zmod>{}; | ||
| 30 | } | ||
| 31 | |||
| 32 | std::optional<Zmod> operator/(const Zmod& d) const { | ||
| 33 | auto i = d.inverse(); | ||
| 34 | return i ? (*this) * i.value() : i; | ||
| 35 | } | ||
| 36 | |||
| 37 | std::optional<Zmod> operator/=(const Zmod& d) { | ||
| 38 | auto q = *this / d; | ||
| 39 | return q ? (*this = q.value()) : q; | ||
| 40 | } | ||
| 41 | |||
| 42 | friend std::ostream& operator<<(std::ostream& os, const Zmod<N>& z) { | ||
| 43 | return os << "(" << z.int64 << " mod " << N << ")"; | ||
| 44 | } | ||
| 45 | private: | ||
| 46 | int64_t int64; | ||
| 47 | }; | ||
| 48 | |||
| 49 | void swapdiv(int64_t& oldx, int64_t& x, int64_t q) { | ||
| 50 | int64_t tmp = x; | ||
| 51 | x = oldx - q*tmp; | ||
| 52 | oldx = tmp; | ||
| 53 | } | ||
| 54 | |||
| 55 | std::tuple<int64_t, int64_t, int64_t> extended_gcd(int64_t a, int64_t b) { | ||
| 56 | int64_t oldr = a; | ||
| 57 | int64_t r = b; | ||
| 58 | int64_t olds = 1; | ||
| 59 | int64_t s = 0; | ||
| 60 | int64_t oldt = 0; | ||
| 61 | int64_t t = 1; | ||
| 62 | while (r != 0) { | ||
| 63 | auto q = oldr / r; | ||
| 64 | swapdiv(oldr, r, q); | ||
| 65 | swapdiv(olds, s, q); | ||
| 66 | swapdiv(oldt, t, q); | ||
| 67 | } | ||
| 68 | return {oldr, olds, oldt}; | ||
| 69 | } | ||
| 70 | |||
| 71 | #endif | ||
