use crate::IntegralDomain;
pub trait EuclideanDomain: IntegralDomain {
type EuclideanValue: Ord;
fn euclidean_fn(&self) -> Self::EuclideanValue;
fn div_euclid(&self, other: &Self) -> Self;
fn rem_euclid(&self, other: &Self) -> Self;
fn normalize(&self) -> Self;
fn checked_normalize(&self) -> Option<Self>
where
Self: Sized;
fn checked_mul(&self, other: &Self) -> Option<Self>
where
Self: Sized;
fn checked_sub(&self, other: &Self) -> Option<Self>
where
Self: Sized;
fn gcd(&self, other: &Self) -> Self
where
Self: Sized + Clone,
{
let mut a = self.clone();
let mut b = other.clone();
while !b.is_zero() {
let r = a.rem_euclid(&b);
a = b;
b = r;
}
a.normalize()
}
fn checked_gcd(&self, other: &Self) -> Option<Self>
where
Self: Sized + Clone,
{
let mut a = self.clone();
let mut b = other.clone();
while !b.is_zero() {
let r = a.rem_euclid(&b);
a = b;
b = r;
}
a.checked_normalize()
}
fn lcm(&self, other: &Self) -> Self
where
Self: Sized + Clone,
{
if self.is_zero() || other.is_zero() {
return Self::zero();
}
let g = self.gcd(other);
(self.div_euclid(&g) * other.clone()).normalize()
}
}
impl EuclideanDomain for i8 {
type EuclideanValue = u8;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
self.unsigned_abs()
}
#[inline]
fn checked_mul(&self, other: &Self) -> Option<Self> {
i8::checked_mul(*self, *other)
}
#[inline]
fn checked_sub(&self, other: &Self) -> Option<Self> {
i8::checked_sub(*self, *other)
}
#[inline]
fn div_euclid(&self, other: &Self) -> Self {
i8::div_euclid(*self, *other)
}
#[inline]
fn rem_euclid(&self, other: &Self) -> Self {
i8::rem_euclid(*self, *other)
}
#[inline]
fn normalize(&self) -> Self {
i8::abs(*self)
}
#[inline]
fn checked_normalize(&self) -> Option<Self> {
i8::checked_abs(*self)
}
}
impl EuclideanDomain for i16 {
type EuclideanValue = u16;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
self.unsigned_abs()
}
#[inline]
fn checked_mul(&self, other: &Self) -> Option<Self> {
i16::checked_mul(*self, *other)
}
#[inline]
fn checked_sub(&self, other: &Self) -> Option<Self> {
i16::checked_sub(*self, *other)
}
#[inline]
fn div_euclid(&self, other: &Self) -> Self {
i16::div_euclid(*self, *other)
}
#[inline]
fn rem_euclid(&self, other: &Self) -> Self {
i16::rem_euclid(*self, *other)
}
#[inline]
fn normalize(&self) -> Self {
i16::abs(*self)
}
#[inline]
fn checked_normalize(&self) -> Option<Self> {
i16::checked_abs(*self)
}
}
impl EuclideanDomain for i32 {
type EuclideanValue = u32;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
self.unsigned_abs()
}
#[inline]
fn checked_mul(&self, other: &Self) -> Option<Self> {
i32::checked_mul(*self, *other)
}
#[inline]
fn checked_sub(&self, other: &Self) -> Option<Self> {
i32::checked_sub(*self, *other)
}
#[inline]
fn div_euclid(&self, other: &Self) -> Self {
i32::div_euclid(*self, *other)
}
#[inline]
fn rem_euclid(&self, other: &Self) -> Self {
i32::rem_euclid(*self, *other)
}
#[inline]
fn normalize(&self) -> Self {
i32::abs(*self)
}
#[inline]
fn checked_normalize(&self) -> Option<Self> {
i32::checked_abs(*self)
}
}
impl EuclideanDomain for i64 {
type EuclideanValue = u64;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
self.unsigned_abs()
}
#[inline]
fn checked_mul(&self, other: &Self) -> Option<Self> {
i64::checked_mul(*self, *other)
}
#[inline]
fn checked_sub(&self, other: &Self) -> Option<Self> {
i64::checked_sub(*self, *other)
}
#[inline]
fn div_euclid(&self, other: &Self) -> Self {
i64::div_euclid(*self, *other)
}
#[inline]
fn rem_euclid(&self, other: &Self) -> Self {
i64::rem_euclid(*self, *other)
}
#[inline]
fn normalize(&self) -> Self {
i64::abs(*self)
}
#[inline]
fn checked_normalize(&self) -> Option<Self> {
i64::checked_abs(*self)
}
}
impl EuclideanDomain for i128 {
type EuclideanValue = u128;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
self.unsigned_abs()
}
#[inline]
fn checked_mul(&self, other: &Self) -> Option<Self> {
i128::checked_mul(*self, *other)
}
#[inline]
fn checked_sub(&self, other: &Self) -> Option<Self> {
i128::checked_sub(*self, *other)
}
#[inline]
fn div_euclid(&self, other: &Self) -> Self {
i128::div_euclid(*self, *other)
}
#[inline]
fn rem_euclid(&self, other: &Self) -> Self {
i128::rem_euclid(*self, *other)
}
#[inline]
fn normalize(&self) -> Self {
i128::abs(*self)
}
#[inline]
fn checked_normalize(&self) -> Option<Self> {
i128::checked_abs(*self)
}
}
impl EuclideanDomain for isize {
type EuclideanValue = usize;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
self.unsigned_abs()
}
#[inline]
fn checked_mul(&self, other: &Self) -> Option<Self> {
isize::checked_mul(*self, *other)
}
#[inline]
fn checked_sub(&self, other: &Self) -> Option<Self> {
isize::checked_sub(*self, *other)
}
#[inline]
fn div_euclid(&self, other: &Self) -> Self {
isize::div_euclid(*self, *other)
}
#[inline]
fn rem_euclid(&self, other: &Self) -> Self {
isize::rem_euclid(*self, *other)
}
#[inline]
fn normalize(&self) -> Self {
isize::abs(*self)
}
#[inline]
fn checked_normalize(&self) -> Option<Self> {
isize::checked_abs(*self)
}
}