use crate::CommutativeRing;
use core::ops::Div;
pub trait EuclideanDomain: CommutativeRing {
type EuclideanValue: Ord;
fn euclidean_fn(&self) -> Self::EuclideanValue;
fn div_euclid(&self, other: &Self) -> Self;
fn rem_euclid(&self, other: &Self) -> Self;
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
}
fn lcm(&self, other: &Self) -> Self
where
Self: Sized + Clone + Div<Output = Self>,
{
if self.is_zero() || other.is_zero() {
return Self::zero();
}
let g = self.gcd(other);
self.clone() * other.clone() / g
}
}
impl EuclideanDomain for i8 {
type EuclideanValue = u8;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
self.unsigned_abs()
}
#[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)
}
}
impl EuclideanDomain for i16 {
type EuclideanValue = u16;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
self.unsigned_abs()
}
#[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)
}
}
impl EuclideanDomain for i32 {
type EuclideanValue = u32;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
self.unsigned_abs()
}
#[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)
}
}
impl EuclideanDomain for i64 {
type EuclideanValue = u64;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
self.unsigned_abs()
}
#[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)
}
}
impl EuclideanDomain for i128 {
type EuclideanValue = u128;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
self.unsigned_abs()
}
#[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)
}
}
impl EuclideanDomain for isize {
type EuclideanValue = usize;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
self.unsigned_abs()
}
#[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)
}
}
impl EuclideanDomain for u8 {
type EuclideanValue = u8;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
*self
}
#[inline]
fn div_euclid(&self, other: &Self) -> Self {
u8::div_euclid(*self, *other)
}
#[inline]
fn rem_euclid(&self, other: &Self) -> Self {
u8::rem_euclid(*self, *other)
}
}
impl EuclideanDomain for u16 {
type EuclideanValue = u16;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
*self
}
#[inline]
fn div_euclid(&self, other: &Self) -> Self {
u16::div_euclid(*self, *other)
}
#[inline]
fn rem_euclid(&self, other: &Self) -> Self {
u16::rem_euclid(*self, *other)
}
}
impl EuclideanDomain for u32 {
type EuclideanValue = u32;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
*self
}
#[inline]
fn div_euclid(&self, other: &Self) -> Self {
u32::div_euclid(*self, *other)
}
#[inline]
fn rem_euclid(&self, other: &Self) -> Self {
u32::rem_euclid(*self, *other)
}
}
impl EuclideanDomain for u64 {
type EuclideanValue = u64;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
*self
}
#[inline]
fn div_euclid(&self, other: &Self) -> Self {
u64::div_euclid(*self, *other)
}
#[inline]
fn rem_euclid(&self, other: &Self) -> Self {
u64::rem_euclid(*self, *other)
}
}
impl EuclideanDomain for u128 {
type EuclideanValue = u128;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
*self
}
#[inline]
fn div_euclid(&self, other: &Self) -> Self {
u128::div_euclid(*self, *other)
}
#[inline]
fn rem_euclid(&self, other: &Self) -> Self {
u128::rem_euclid(*self, *other)
}
}
impl EuclideanDomain for usize {
type EuclideanValue = usize;
#[inline]
fn euclidean_fn(&self) -> Self::EuclideanValue {
*self
}
#[inline]
fn div_euclid(&self, other: &Self) -> Self {
usize::div_euclid(*self, *other)
}
#[inline]
fn rem_euclid(&self, other: &Self) -> Self {
usize::rem_euclid(*self, *other)
}
}