jpp/lab3/zad1/include/GF.hpp
2024-05-10 14:12:10 +02:00

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; }
};