149 lines
3.4 KiB
C++
149 lines
3.4 KiB
C++
#pragma once
|
|
|
|
#include <cinttypes>
|
|
#include <compare>
|
|
#include <sstream>
|
|
#include <iostream>
|
|
|
|
template<uint64_t N>
|
|
class GF {
|
|
uint64_t _value;
|
|
public:
|
|
std::strong_ordering operator<=>(const GF<N> &rhs) const = default;
|
|
|
|
GF<N> &operator=(const GF<N> &value) = default;
|
|
|
|
GF()
|
|
: _value(0u) {}
|
|
|
|
GF(const uint64_t &value)
|
|
: _value(value % N) {}
|
|
|
|
GF<N> &operator=(const uint64_t &value) {
|
|
this->_value = value % N;
|
|
return *this;
|
|
}
|
|
|
|
GF<N> inverse() const {
|
|
int64_t t1 = 0;
|
|
int64_t t2 = 1;
|
|
int64_t r1 = N;
|
|
int64_t r2 = this->_value;
|
|
|
|
while (r2 != 0) {
|
|
int64_t q = r1 / r2;
|
|
int64_t temp = t2;
|
|
t2 = t1 - q * t2;
|
|
t1 = temp;
|
|
temp = r2;
|
|
r2 = r1 - q * r2;
|
|
r1 = temp;
|
|
}
|
|
if (r1 > 1) {
|
|
throw std::invalid_argument("value isn't invertible");
|
|
}
|
|
if (t1 < 0) {
|
|
t1 += N;
|
|
}
|
|
return t1;
|
|
}
|
|
|
|
GF<N> operator+(const GF<N> &rhs) const {
|
|
return (this->_value + rhs._value) % N;
|
|
}
|
|
|
|
GF<N> operator+(const uint64_t &rhs) const {
|
|
return this->operator+(GF<N>(rhs));
|
|
}
|
|
|
|
GF<N> operator-(const GF<N> &rhs) const {
|
|
if (this->_value < rhs._value) {
|
|
return N - (rhs._value - this->_value);
|
|
}
|
|
return (this->_value - rhs._value);
|
|
}
|
|
|
|
GF<N> operator-(const uint64_t &rhs) const {
|
|
return this->operator-(GF<N>(rhs));
|
|
}
|
|
|
|
GF<N> operator*(const GF<N> &rhs) const {
|
|
return (this->_value * rhs._value) % N;
|
|
}
|
|
|
|
GF<N> operator*(const uint64_t &rhs) const {
|
|
return this->operator*(GF<N>(rhs));
|
|
}
|
|
|
|
/*
|
|
* throws std::invalid_argument when dividing by 0 or value isn't inversible
|
|
*/
|
|
GF<N> operator/(const GF<N> &rhs) const {
|
|
if (rhs._value == 0) {
|
|
throw std::invalid_argument("division by 0 is illegal");
|
|
}
|
|
|
|
return *this * rhs.inverse();
|
|
}
|
|
|
|
GF<N> operator/(const uint64_t &rhs) const {
|
|
return this->operator/(GF<N>(rhs));
|
|
}
|
|
|
|
GF<N> operator+=(const GF<N> &rhs) {
|
|
*this = *this + rhs;
|
|
return *this;
|
|
}
|
|
|
|
GF<N> operator+=(const uint64_t &rhs) {
|
|
return this->operator+=(GF<N>(rhs));
|
|
}
|
|
|
|
GF<N> operator-=(const GF<N> &rhs) {
|
|
*this = *this - rhs;
|
|
return *this;
|
|
}
|
|
|
|
GF<N> operator-=(const uint64_t &rhs) {
|
|
return this->operator-=(GF<N>(rhs));
|
|
}
|
|
|
|
GF<N> operator*=(const GF<N> &rhs) {
|
|
*this = *this * rhs;
|
|
return *this;
|
|
}
|
|
|
|
GF<N> operator*=(const uint64_t &rhs) {
|
|
return this->operator*=(GF<N>(rhs));
|
|
}
|
|
|
|
GF<N> operator/=(const GF<N> &rhs) {
|
|
*this = *this / rhs;
|
|
return *this;
|
|
}
|
|
|
|
GF<N> operator/=(const uint64_t &rhs) {
|
|
return this->operator/=(GF<N>(rhs));
|
|
}
|
|
|
|
friend std::ostream &operator<<(std::ostream &stream, const GF<N> &val) {
|
|
stream << "GF<" << N << ">(" << val._value << ")";
|
|
return stream;
|
|
}
|
|
|
|
friend std::istream &operator>>(std::istream &stream, GF<N> &val) {
|
|
stream >> val._value;
|
|
val._value %= N;
|
|
return stream;
|
|
}
|
|
|
|
/*
|
|
* returns the characteristic of this GF
|
|
*/
|
|
uint64_t characteristic() const { return N; }
|
|
|
|
/*
|
|
* returns the value of this GF
|
|
*/
|
|
uint64_t value() const { return _value; }
|
|
};
|