#pragma once #include #include #include template class GF { uint value; public: std::strong_ordering operator<=>(const GF &rhs) const = default; GF &operator=(const GF &value) = default; GF() : value(0u) {} GF(const uint &value) : value(value % N) {} GF &operator=(const uint &value) { this->value = value % N; return *this; } GF operator+(const GF &rhs) const { return (this->value + rhs.value) % N; } GF operator+(const uint &rhs) const { return this->operator+(GF(rhs)); } GF operator-(const GF &rhs) const { if (this->value < rhs.value) { return N - (rhs.value - this->value); } return (this->value - rhs.value); } GF operator-(const uint &rhs) const { return this->operator-(GF(rhs)); } GF operator*(const GF &rhs) const { return (this->value * rhs.value) % N; } GF operator*(const uint &rhs) const { return this->operator*(GF(rhs)); } GF operator/(const GF &rhs) const { if (rhs.value == 0) { throw std::invalid_argument("division by 0 is illegal"); } return (this->value / rhs.value) % N; } GF operator/(const uint &rhs) const { return this->operator/(GF(rhs)); } GF operator+=(const GF &rhs) { *this = *this + rhs; return *this; } GF operator+=(const uint &rhs) { return this->operator+=(GF(rhs)); } GF operator-=(const GF &rhs) { *this = *this - rhs; return *this; } GF operator-=(const uint &rhs) { return this->operator-=(GF(rhs)); } GF operator*=(const GF &rhs) { *this = *this * rhs; return *this; } GF operator*=(const uint &rhs) { return this->operator*=(GF(rhs)); } GF operator/=(const GF &rhs) { *this = *this / rhs; return *this; } GF operator/=(const uint &rhs) { return this->operator/=(GF(rhs)); } friend std::ostream &operator<<(std::ostream &stream, const GF &value) { stream << "GF<" << N << ">(" << value.value << ")"; return stream; } friend std::istream &operator>>(std::istream &stream, GF &value) { stream >> value.value; return stream; } uint characteristic() { return N; }; };