A \$Z^m\$ number system includes integers in the interval \$[0, m)\$ when \$m > 0\$ or \$(m, 0]\$ when \$m < 0\$. The code defines a trait Mod
to represent numbers in this system and the +
, -
, and *
operator for it.
use std::ops::Add;
use std::ops::Mul;
use std::ops::Sub;
use std::ops::Rem;
struct Mod<T>
where T: Modulo<T> + Mul<Output=T> + Sub<Output=T> + Add<Output=T> + Rem<Output=T> + Copy + Clone
{
modulo: T,
i: T,
}
trait Modulo<T>
where T: Add<Output=T> + Rem<Output=T> + Copy + Clone
{
fn modulo(self, n: T) -> T;
}
impl<T> Modulo<T> for T
where T: Add<Output=T> + Rem<Output=T> + Copy + Clone
{
fn modulo(self, n: T) -> T {
((self % n) + n) % n
}
}
impl<T> Mod<T>
where T: Modulo<T> + Mul<Output=T> + Sub<Output=T> + Add<Output=T> + Rem<Output=T> + Copy + Clone
{
fn new(modulo: T, i: T) -> Mod<T> {
let n = i.modulo(modulo);
Mod {
modulo: modulo,
i: n,
}
}
}
impl<T> Add for Mod<T>
where T: Modulo<T> + Mul<Output=T> + Sub<Output=T> + Add<Output=T> + Rem<Output=T> + Copy + Clone
{
type Output = Mod<T>;
fn add(self, other: Mod<T>) -> Mod<T> {
Mod::new(self.modulo, self.i + other.i)
}
}
impl<T> Sub for Mod<T>
where T: Modulo<T> + Mul<Output=T> + Sub<Output=T> + Add<Output=T> + Rem<Output=T> + Copy + Clone
{
type Output = Mod<T>;
fn sub(self, other: Mod<T>) -> Mod<T> {
Mod::new(self.modulo, self.i - other.i)
}
}
impl<T> Mul for Mod<T>
where T: Modulo<T> + Mul<Output=T> + Sub<Output=T> + Add<Output=T> + Rem<Output=T> + Copy + Clone
{
type Output = Mod<T>;
fn mul(self, other: Mod<T>) -> Mod<T> {
Mod::new(self.modulo, self.i * other.i)
}
}
fn main() {
let x = Mod::new(-5i8, 3i8);
let y = Mod::new(-5i8, 8i8);
println!("{}", (x + y).i);
let x = Mod::new(-5i8, 3i8);
let y = Mod::new(-5i8, 8i8);
println!("{}", (x - y).i);
let x = Mod::new(-5i8, 3i8);
let y = Mod::new(-5i8, 8i8);
println!("{}", (x * y).i);
let x = Mod::new(-5i16, 3i16);
let y = Mod::new(-5i16, 8i16);
println!("{}", (x + y).i);
let x = Mod::new(-5i16, 3i16);
let y = Mod::new(-5i16, 8i16);
println!("{}", (x - y).i);
let x = Mod::new(-5i16, 3i16);
let y = Mod::new(-5i16, 8i16);
println!("{}", (x * y).i);
let x = Mod::new(-5, 3);
let y = Mod::new(-5, 8);
println!("{}", (x + y).i);
let x = Mod::new(-5, 3);
let y = Mod::new(-5, 8);
println!("{}", (x - y).i);
let x = Mod::new(-5, 3);
let y = Mod::new(-5, 8);
println!("{}", (x * y).i);
let x = Mod::new(5u8, 3u8);
let y = Mod::new(5u8, 8u8);
println!("{}", (x + y).i);
let x = Mod::new(5u8, 3u8);
let y = Mod::new(5u8, 8u8);
println!("{}", (x - y).i);
let x = Mod::new(5u8, 3u8);
let y = Mod::new(5u8, 8u8);
println!("{}", (x * y).i);
}
I tried to achieve the goals laid out in the previous version:
- Changed the modulo method for better performance.
- Generalized over a bunch of types other than
i32
.
All suggestions are still welcome. In particular, requiring T
to implement Copy
and Clone
might be a bit too restrictive, I would like to relax that.