// Copyright (C) 2026 Kiyotsugu Arai // SPDX-License-Identifier: LGPL-3.0-or-later // ModularInt.hpp #ifndef SANGI_MODULAR_INT_HPP #define SANGI_MODULAR_INT_HPP // Modular integer class (C++20/23 ready, concept-aware version) // // This file defines a class template that provides efficient modular integer // arithmetic. // ModularInt

represents an element of the residue field Z/PZ for the // prime modulus P. // It supports basic arithmetic operations (addition, subtraction, // multiplication, division), exponentiation, and comparison operations. // // Main features: // - Modulus is specified through a template parameter // - Integrates with C++20 concepts // - Efficient algorithms // - Integrates with algebraic structures (monoid, group, ring, field) // - Stream I/O support // // Usage example: // ``` // ModularInt<1000000007> a = 42; // 42 mod 10^9+7 // ModularInt<1000000007> b = 987654321; // auto c = a * b; // 41477417 mod 10^9+7 // auto d = a.pow(12345); // a^12345 mod 10^9+7 // ``` #include #include #include #include #include #include #include namespace sangi { // Modular integer class (C++20 concepts version) template class ModularInt { private: int value_; // Simple implementation using a 64-bit integer in place of Barrett // reduction to avoid overflow during multiplication static inline constexpr int mul_mod(int64_t a, int64_t b) { return static_cast((a * b) % P); } // Fast modulo of a 64-bit integer static inline constexpr int fast_mod(int64_t x) { return static_cast(x % P); } public: // Default constructor (initializes to 0) constexpr ModularInt() noexcept : value_(0) {} // Converting constructor from an integer value template constexpr ModularInt(T v) noexcept : value_(fast_mod(static_cast(v) % P + P)) {} // Copy constructor constexpr ModularInt(const ModularInt& other) noexcept = default; // Move constructor constexpr ModularInt(ModularInt&& other) noexcept = default; // Assignment operator constexpr ModularInt& operator=(const ModularInt& other) noexcept = default; // Move assignment operator constexpr ModularInt& operator=(ModularInt&& other) noexcept = default; // Assignment from an integer type template constexpr ModularInt& operator=(T v) noexcept { value_ = fast_mod(static_cast(v) % P + P); return *this; } // Destructor ~ModularInt() = default; // Accessor constexpr int value() const noexcept { return value_; } // Addition constexpr ModularInt operator+(const ModularInt& other) const noexcept { int sum = value_ + other.value_; return ModularInt(sum >= P ? sum - P : sum); } // Addition with an integer template constexpr ModularInt operator+(T other) const noexcept { return *this + ModularInt(other); } // Subtraction constexpr ModularInt operator-(const ModularInt& other) const noexcept { int diff = value_ - other.value_; return ModularInt(diff < 0 ? diff + P : diff); } // Subtraction with an integer template constexpr ModularInt operator-(T other) const noexcept { return *this - ModularInt(other); } // Multiplication constexpr ModularInt operator*(const ModularInt& other) const noexcept { return ModularInt(mul_mod(value_, other.value_)); } // Multiplication with an integer template constexpr ModularInt operator*(T other) const noexcept { return *this * ModularInt(other); } // Division (uses the modular inverse) ModularInt operator/(const ModularInt& other) const { if (other.value_ == 0) { throw MathError("Division by zero in ModularInt"); } return (*this) * other.inverse(); } // Division by an integer template ModularInt operator/(T other) const { return *this / ModularInt(other); } // Unary minus operator constexpr ModularInt operator-() const noexcept { return ModularInt(value_ == 0 ? 0 : P - value_); } // Compound addition constexpr ModularInt& operator+=(const ModularInt& other) noexcept { value_ += other.value_; if (value_ >= P) value_ -= P; return *this; } // Compound addition with an integer template constexpr ModularInt& operator+=(T other) noexcept { return *this += ModularInt(other); } // Compound subtraction constexpr ModularInt& operator-=(const ModularInt& other) noexcept { value_ -= other.value_; if (value_ < 0) value_ += P; return *this; } // Compound subtraction with an integer template constexpr ModularInt& operator-=(T other) noexcept { return *this -= ModularInt(other); } // Compound multiplication constexpr ModularInt& operator*=(const ModularInt& other) noexcept { value_ = mul_mod(value_, other.value_); return *this; } // Compound multiplication with an integer template constexpr ModularInt& operator*=(T other) noexcept { return *this *= ModularInt(other); } // Compound division ModularInt& operator/=(const ModularInt& other) { if (other.value_ == 0) { throw MathError("Division by zero in ModularInt"); } return (*this) *= other.inverse(); } // Compound division by an integer template ModularInt& operator/=(T other) { return *this /= ModularInt(other); } // Pre-increment constexpr ModularInt& operator++() noexcept { ++value_; if (value_ == P) value_ = 0; return *this; } // Post-increment constexpr ModularInt operator++(int) noexcept { ModularInt old = *this; ++(*this); return old; } // Pre-decrement constexpr ModularInt& operator--() noexcept { if (value_ == 0) value_ = P; --value_; return *this; } // Post-decrement constexpr ModularInt operator--(int) noexcept { ModularInt old = *this; --(*this); return old; } // Equality operator constexpr bool operator==(const ModularInt& other) const noexcept { return value_ == other.value_; } // Equality with an integer template constexpr bool operator==(T other) const noexcept { return *this == ModularInt(other); } // Inequality operator constexpr bool operator!=(const ModularInt& other) const noexcept { return value_ != other.value_; } // Inequality with an integer template constexpr bool operator!=(T other) const noexcept { return *this != ModularInt(other); } // Less-than operator constexpr bool operator<(const ModularInt& other) const noexcept { return value_ < other.value_; } // Less-than with an integer template constexpr bool operator<(T other) const noexcept { return *this < ModularInt(other); } constexpr bool operator<=(const ModularInt& other) const noexcept { return value_ <= other.value_; } template constexpr bool operator<=(T other) const noexcept { return *this <= ModularInt(other); } constexpr bool operator>(const ModularInt& other) const noexcept { return value_ > other.value_; } template constexpr bool operator>(T other) const noexcept { return *this > ModularInt(other); } constexpr bool operator>=(const ModularInt& other) const noexcept { return value_ >= other.value_; } template constexpr bool operator>=(T other) const noexcept { return *this >= ModularInt(other); } // Implicit conversion to an integer type constexpr operator int() const noexcept { return value_; } // Inverse computation (extended Euclidean algorithm) constexpr ModularInt inverse() const { if (value_ == 0) { throw MathError("Division by zero in ModularInt::inverse"); } int a = value_; int b = P; int u = 1, v = 0; while (b > 0) { int q = a / b; std::swap(a, b); b = b - q * a; std::swap(u, v); v = v - q * u; } // If the result is negative, convert to a positive value return ModularInt(u < 0 ? u + P : u); } // Exponentiation (repeated squaring) constexpr ModularInt pow(int64_t n) const { if (n < 0) { return inverse().pow(-n); } ModularInt res(1); ModularInt base(*this); while (n > 0) { if (n & 1) res *= base; base *= base; n >>= 1; } return res; } // Stream output friend std::ostream& operator<<(std::ostream& os, const ModularInt& m) { return os << m.value_; } // Stream input friend std::istream& operator>>(std::istream& is, ModularInt& m) { int val; is >> val; m = ModularInt(val); return is; } }; // Free functions // Addition (right-hand side is an integer) template constexpr ModularInt

operator+(T left, const ModularInt

& right) noexcept { return ModularInt

(left) + right; } // Subtraction (right-hand side is an integer) template constexpr ModularInt

operator-(T left, const ModularInt

& right) noexcept { return ModularInt

(left) - right; } // Multiplication (right-hand side is an integer) template constexpr ModularInt

operator*(T left, const ModularInt

& right) noexcept { return ModularInt

(left) * right; } // Division (right-hand side is an integer) template ModularInt

operator/(T left, const ModularInt

& right) { return ModularInt

(left) / right; } // Equality (left-hand side is an integer) template constexpr bool operator==(T left, const ModularInt

& right) noexcept { return ModularInt

(left) == right; } // Inequality (left-hand side is an integer) template constexpr bool operator!=(T left, const ModularInt

& right) noexcept { return ModularInt

(left) != right; } // Ordering (left-hand side is an integer) template constexpr bool operator<(T left, const ModularInt

& right) noexcept { return ModularInt

(left) < right; } template constexpr bool operator<=(T left, const ModularInt

& right) noexcept { return ModularInt

(left) <= right; } template constexpr bool operator>(T left, const ModularInt

& right) noexcept { return ModularInt

(left) > right; } template constexpr bool operator>=(T left, const ModularInt

& right) noexcept { return ModularInt

(left) >= right; } // Absolute value template constexpr int abs(const ModularInt

& m) noexcept { return m.value(); // Modular integers are always non-negative, so just return the value } // Fast exponentiation template constexpr ModularInt

pow(const ModularInt

& base, int64_t exponent) { return base.pow(exponent); } // Specialization that confirms ModularInt's concept compatibility template struct numeric_traits> { using value_type = ModularInt

; using category = floating_point_tag; // Behaves like a real-number-like type static constexpr bool is_supported = true; static constexpr bool is_complex = false; static constexpr bool is_integer = false; // Treated as a field static constexpr bool is_floating_point = false; static constexpr ModularInt

zero() { return ModularInt

(0); } static constexpr ModularInt

one() { return ModularInt

(1); } static constexpr ModularInt

epsilon() { return ModularInt

(1); } static constexpr ModularInt

abs(const ModularInt

& value) { return value; } static constexpr ModularInt

conj(const ModularInt

& value) { return value; } static constexpr int norm(const ModularInt

& value) { return static_cast(static_cast(value.value()) * value.value() % P); } static bool pivotBetter(const ModularInt

& a, const ModularInt

&) { return a.value() != 0; // In a finite field, all non-zero elements are equally good } }; } // namespace sangi namespace std { // std::hash specialization template struct hash> { std::size_t operator()(const sangi::ModularInt

& m) const noexcept { return std::hash{}(m.value()); } }; } #endif // SANGI_MODULAR_INT_HPP