initial commit

This commit is contained in:
2023-12-28 14:07:00 +08:00
commit 6edb6a95b3
16 changed files with 4401 additions and 0 deletions

791
src/rational.rs Normal file
View File

@@ -0,0 +1,791 @@
use num_traits::sign::Signed;
use num_traits::Num;
use num_traits::NumOps;
use num_traits::One;
use num_traits::Pow;
use num_traits::Signed as SignedOps;
use num_traits::Zero;
use std::cmp::Ordering;
use std::cmp::PartialEq;
use std::cmp::PartialOrd;
use std::fmt::Debug;
use std::fmt::Display;
use std::ops::Add;
use std::ops::AddAssign;
use std::ops::Div;
use std::ops::DivAssign;
use std::ops::Mul;
use std::ops::MulAssign;
use std::ops::Neg;
use std::ops::Rem;
use std::ops::Sub;
use std::ops::SubAssign;
trait_group! {
pub trait RationalInt
: NumOps
+ Debug
+ PartialEq
+ PartialOrd
+ Zero<Output = Self>
+ One<Output = Self>
+ Pow<u32, Output = Self>
+ Neg<Output = Self>
+ Clone
+ Default
}
fn gcd<T>(a: &T, b: &T) -> T
where
T: Rem<Output = T> + Clone + Zero,
{
let mut n1 = a.clone();
let mut n2 = b.clone();
let mut tmp: T;
while !n2.is_zero() {
tmp = n1;
n1 = n2.clone();
n2 = tmp % n2;
}
n1
}
fn mcm<'a, T>(n1: &'a T, n2: &'a T) -> T
where
T: Div<Output = T> + Rem<Output = T> + Clone + Zero,
&'a T: Mul<Output = T>,
{
let den = gcd(n1, n2);
n1 * n2 / den
}
#[derive(Debug)]
pub struct Rational<TYPE> {
num: TYPE,
den: TYPE,
}
impl<TYPE> Rational<TYPE>
where
TYPE: Zero + One + Clone + Rem<Output = TYPE> + PartialOrd + Neg<Output = TYPE>,
for<'a> &'a TYPE: Div<&'a TYPE, Output = TYPE>,
{
fn simplify(&mut self) {
if self.num.is_zero() {
self.den = TYPE::one();
} else if self.den.is_zero() {
} else {
(self.num, self.den) = {
let n1_opt: TYPE;
let n1 = if self.den < TYPE::zero() {
n1_opt = -self.num.clone();
&n1_opt
} else {
&self.num
};
let n2_opt: TYPE;
let n2 = if self.den < TYPE::zero() {
n2_opt = -self.den.clone();
&n2_opt
} else {
&self.den
};
let num_abs_opt: TYPE;
let num_abs = if self.num < TYPE::zero() {
num_abs_opt = -self.num.clone();
&num_abs_opt
} else {
&self.num
};
let gcd = gcd(num_abs, n2);
(n1 / &gcd, n2 / &gcd)
};
}
}
}
impl<TYPE> Rational<TYPE>
where
TYPE: RationalInt,
{
pub fn new(num: TYPE, den: TYPE) -> Rational<TYPE> {
let res = den.partial_cmp(&TYPE::zero());
match res {
Some(Ordering::Greater) => Rational { num, den },
Some(Ordering::Less) => Rational {
num: -num,
den: -den,
},
_ => {
panic!("Rational denominator cannot be zero or NaN")
}
}
}
}
#[opimps::impl_op(Pow)]
fn pow<TYPE>(self: Rational<TYPE>, exp: u32) -> Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: Pow<u32, Output = TYPE>,
{
Rational {
num: self.num.pow(exp),
den: self.den.pow(exp),
}
}
#[opimps::impl_op(Pow)]
fn pow<TYPE>(self: &Rational<TYPE>, exp: u32) -> Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: Pow<u32, Output = TYPE>,
{
Rational {
num: (&self.num).pow(exp),
den: (&self.den).pow(exp),
}
}
#[opimps::impl_ops(Add)]
fn add<TYPE>(self: Rational<TYPE>, rhs: Rational<TYPE>) -> Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
let den = mcm::<TYPE>(&self.den, &rhs.den);
let a = &self.num * &den;
let b = &rhs.num * &den;
let num = &a / &self.den + &b / &rhs.den;
let mut result: Rational<TYPE> = Rational { num, den };
result.simplify();
result
}
#[opimps::impl_ops(Sub)]
fn sub<TYPE>(self: Rational<TYPE>, rhs: Rational<TYPE>) -> Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
let den = mcm::<TYPE>(&self.den, &rhs.den);
let a = &self.num * &den;
let b = &rhs.num * &den;
let num = &a / &self.den - &b / &rhs.den;
let mut result: Rational<TYPE> = Rational { num, den };
result.simplify();
result
}
#[opimps::impl_ops(Mul)]
fn mul<TYPE>(self: Rational<TYPE>, rhs: Rational<TYPE>) -> Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
let num = &self.num * &rhs.num;
let den = &self.den * &rhs.den;
let mut result = Rational { num, den };
result.simplify();
result
}
#[opimps::impl_ops(Div)]
fn div<TYPE>(self: Rational<TYPE>, rhs: Rational<TYPE>) -> Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
let den = &self.den * &rhs.num;
let num = &self.num * &rhs.den;
let mut result = Rational::new(num, den);
result.simplify();
result
}
#[opimps::impl_ops(Rem)]
fn rem<TYPE>(self: Rational<TYPE>, rhs: Rational<TYPE>) -> Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
match self.partial_cmp(&rhs) {
Some(std::cmp::Ordering::Less) => rhs.clone(),
Some(std::cmp::Ordering::Equal) => Rational::<TYPE>::zero(),
Some(std::cmp::Ordering::Greater) => {
let div = self / rhs;
let num = &div.num / &div.den;
div - Rational::new(num, TYPE::one())
}
None => {
panic!("Cannot compare")
}
}
}
impl<'a, TYPE> AddAssign<&'a Rational<TYPE>> for Rational<TYPE>
where
TYPE: Zero
+ One
+ Clone
+ Rem<Output = TYPE>
+ PartialOrd
+ Neg<Output = TYPE>
+ Div<Output = TYPE>,
for<'b> &'b TYPE: Mul<&'b TYPE, Output = TYPE> + Div<&'b TYPE, Output = TYPE>,
{
fn add_assign(&mut self, rhs: &'a Self) {
let den = mcm::<TYPE>(&self.den, &rhs.den);
let a = &self.num * &den;
let b = &rhs.num * &den;
let num = &a / &self.den + &b / &rhs.den;
self.num = num;
self.den = den;
self.simplify();
}
}
impl<TYPE> AddAssign for Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn add_assign(&mut self, rhs: Self) {
*self += &rhs;
}
}
impl<'a, TYPE> SubAssign<&'a Rational<TYPE>> for Rational<TYPE>
where
TYPE: Div<Output = TYPE>
+ Sub<Output = TYPE>
+ Rem<Output = TYPE>
+ Neg<Output = TYPE>
+ Clone
+ Zero
+ One
+ PartialOrd,
for<'c> &'c TYPE: Mul<&'c TYPE, Output = TYPE> + Div<&'c TYPE, Output = TYPE>,
for<'b> TYPE: SubAssign<&'b TYPE>,
{
fn sub_assign(&mut self, rhs: &'a Self) {
let den = mcm::<TYPE>(&self.den, &rhs.den);
let a = &self.num * &den;
let b = &rhs.num * &den;
let num = &a / &self.den - &b / &rhs.den;
self.num = num;
self.den = den;
self.simplify();
}
}
impl<TYPE> SubAssign for Rational<TYPE>
where
TYPE: Div<Output = TYPE>
+ Sub<Output = TYPE>
+ Rem<Output = TYPE>
+ Neg<Output = TYPE>
+ Clone
+ Zero
+ One
+ PartialOrd,
for<'c> &'c TYPE: Mul<&'c TYPE, Output = TYPE> + Div<&'c TYPE, Output = TYPE>,
for<'b> TYPE: SubAssign<&'b TYPE>,
{
fn sub_assign(&mut self, rhs: Self) {
*self -= &rhs;
}
}
impl<'a, TYPE> MulAssign<&'a Rational<TYPE>> for Rational<TYPE>
where
for<'b> TYPE: MulAssign<&'b TYPE>,
TYPE: PartialOrd + One + Clone + Zero + Rem<Output = TYPE> + Neg<Output = TYPE>,
for<'c> &'c TYPE: Div<&'c TYPE, Output = TYPE>,
{
fn mul_assign(&mut self, rhs: &'a Self) {
self.num *= &rhs.num;
self.den *= &rhs.den;
self.simplify();
}
}
impl<TYPE> MulAssign for Rational<TYPE>
where
for<'a> TYPE: MulAssign<&'a TYPE>,
TYPE: PartialOrd + One + Clone + Zero + Rem<Output = TYPE> + Neg<Output = TYPE>,
for<'c> &'c TYPE: Div<&'c TYPE, Output = TYPE>,
{
fn mul_assign(&mut self, rhs: Self) {
*self *= &rhs;
}
}
impl<'a, TYPE> DivAssign<&'a Rational<TYPE>> for Rational<TYPE>
where
for<'b> TYPE: MulAssign<&'b TYPE>,
TYPE: PartialOrd + One + Clone + Zero + Rem<Output = TYPE> + Neg<Output = TYPE>,
for<'c> &'c TYPE: Div<&'c TYPE, Output = TYPE>,
{
fn div_assign(&mut self, rhs: &'a Self) {
self.num *= &rhs.den;
self.den *= &rhs.num;
self.simplify()
}
}
impl<TYPE> DivAssign for Rational<TYPE>
where
for<'a> TYPE: MulAssign<&'a TYPE>,
TYPE: PartialOrd + One + Clone + Zero + Rem<Output = TYPE> + Neg<Output = TYPE>,
for<'c> &'c TYPE: Div<&'c TYPE, Output = TYPE>,
{
fn div_assign(&mut self, rhs: Self) {
*self /= &rhs;
self.simplify()
}
}
impl<TYPE> Display for Rational<TYPE>
where
TYPE: RationalInt + Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}/{}", self.num, self.den)
}
}
impl<TYPE> PartialEq for Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn eq(&self, other: &Self) -> bool {
self.partial_cmp(other) == Some(Ordering::Equal)
}
}
impl<TYPE> Eq for Rational<TYPE>
where
TYPE: RationalInt + Eq,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
}
impl<TYPE> PartialOrd for Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
(&self.num * &other.den).partial_cmp(&(&other.num * &self.den))
}
}
impl<TYPE> Ord for Rational<TYPE>
where
TYPE: RationalInt + Ord,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn cmp(&self, other: &Self) -> Ordering {
(&self.num * &other.den).cmp(&(&other.num * &self.den))
}
}
impl<TYPE> Clone for Rational<TYPE>
where
TYPE: Clone,
{
fn clone(&self) -> Self {
Rational {
num: self.num.clone(),
den: self.den.clone(),
}
}
}
impl<TYPE> Copy for Rational<TYPE> where TYPE: Copy {}
impl<TYPE> Zero for Rational<TYPE>
where
TYPE: RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn zero() -> Rational<TYPE> {
Rational {
num: TYPE::zero(),
den: TYPE::one(),
}
}
fn is_zero(&self) -> bool {
self.num.is_zero() && !self.den.is_zero()
}
}
impl<TYPE> One for Rational<TYPE>
where
TYPE: RationalInt + Display,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn one() -> Self {
Rational {
num: TYPE::one(),
den: TYPE::one(),
}
}
fn is_one(&self) -> bool {
self.num == self.den
}
}
impl<TYPE> Default for Rational<TYPE>
where
TYPE: RationalInt + Display,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn default() -> Self {
Rational::<TYPE>::zero()
}
}
#[opimps::impl_uni_op(Neg)]
fn neg<TYPE>(self: Rational<TYPE>) -> Rational<TYPE>
where
TYPE: RationalInt,
{
Rational::new(-self.num, self.den)
}
#[opimps::impl_uni_op(Neg)]
fn neg<TYPE>(self: &Rational<TYPE>) -> Rational<TYPE>
where
TYPE: RationalInt,
{
Rational::new(-self.num.clone(), self.den.clone())
}
impl<TYPE> Num for Rational<TYPE>
where
TYPE: Num + RationalInt + Display,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn from_str_radix(_: &str, _: u32) -> Result<Self, Self::FromStrRadixErr> {
Result::Err(Rational::<TYPE>::default())
}
type FromStrRadixErr = Self;
}
impl<TYPE> SignedOps for Rational<TYPE>
where
TYPE: Signed + SignedOps + Display + RationalInt,
for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>,
{
fn abs(&self) -> Self {
Rational::new(self.num.abs(), self.den.abs())
}
fn abs_sub(&self, other: &Self) -> Self {
if self <= other {
Rational::<TYPE>::zero()
} else {
self.clone() - other.clone()
}
}
fn is_negative(&self) -> bool {
!self.num.is_zero() && self.num.is_negative() ^ self.den.is_negative()
}
fn is_positive(&self) -> bool {
!self.num.is_zero() && !(self.num.is_positive() ^ self.den.is_positive())
}
fn signum(&self) -> Self {
if self.is_positive() {
Rational::<TYPE>::one()
} else if self.is_negative() {
-Rational::<TYPE>::one()
} else {
Rational::<TYPE>::zero()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeSet;
#[test]
fn test_simplify() {
let mut r1 = Rational::new(15, 105);
assert_eq!(Rational::new(1, 7), r1);
r1.simplify();
assert_eq!(Rational::new(1, 7), r1);
}
#[test]
fn test_add() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(4, 10);
let r3 = Rational::new(1, 7);
let one: Rational<i32> = Rational::<i32>::one();
assert_eq!(one, r1 + r2);
assert_eq!(r2 + r1, r1 + r2);
assert_eq!(r1 + r2 + r3, r3 + r2 + r1);
}
#[test]
fn test_add_assign() {
let mut r1 = Rational::new(3, 5);
let r2 = Rational::new(4, 10);
let r3 = Rational::<i32>::one();
r1 += r2;
assert_eq!(r3, r1);
}
#[test]
fn test_sub() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(4, 10);
let r3 = Rational::new(1, 7);
assert_eq!(Rational::<i32>::zero(), r1 - r1);
assert_eq!(Rational::new(-1, 5), r2 - r1);
assert!(Rational::<i32>::zero() > r3 - r1);
assert!(Rational::<i32>::zero() > r3 - r2);
assert!(Rational::<i32>::zero() > r3 - r1);
}
#[test]
fn test_sub_assign() {
let mut r1 = Rational::new(3, 5);
let r2 = Rational::new(4, 10);
let r3 = Rational::new(1, 5);
r1 -= r2;
assert_eq!(r3, r1);
}
#[test]
fn test_mul() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(-4, 10);
let r3 = Rational::new(1, 7);
assert_eq!(Rational::new(9, 25), r1 * r1);
assert_eq!(Rational::new(-12, 50), r2 * r1);
assert_eq!(Rational::new(2, -35), r2 * r3);
}
#[test]
fn test_mul_assign() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(-4, 10);
let r3 = Rational::new(-12, 50);
let mut r4 = r1.clone();
r4 *= r1;
assert_eq!(Rational::<i32>::new(9, 25), r4);
let mut r5 = r1.clone();
r5 *= r2;
assert_eq!(r3, r5);
}
#[test]
fn test_div() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(-4, 10);
let r3 = Rational::new(1, 7);
assert_eq!(Rational::<i32>::one(), r1 / r1);
assert_eq!(Rational::new(-2, 3), r2 / r1);
assert_eq!(Rational::new(28, -10), r2 / r3);
}
#[test]
fn test_div_assign() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(-4, 10);
let r3 = Rational::new(30, -20);
let mut r4 = r1.clone();
r4 /= r1;
assert_eq!(Rational::<i32>::one(), r4);
let mut r5 = r1.clone();
r5 /= r2;
assert_eq!(r3, r5);
}
#[test]
fn test_eq() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(6, 10);
let r3 = Rational::new(300, 500);
let r4 = Rational::new(300, -500);
assert!(r1 == r2);
assert!(r1 == r3);
assert!(r1 != r4);
}
#[test]
fn test_ord() {
let r1 = Rational::new(3, 5);
let r2 = Rational::new(7, 10);
let r3 = Rational::new(301, 500);
let r4 = Rational::new(300, -500);
let values: Vec<Rational<i32>> = BTreeSet::from([r1, r2, r3, r4])
.iter()
.map(|it| it.clone())
.collect();
let expected_order = Vec::from([r4, r1, r3, r2]);
assert_eq!(expected_order, values);
}
#[test]
fn test_gcd() {
let a = 14;
let b = 21;
assert_eq!(7, gcd(&a, &b));
}
#[test]
fn test_mcm() {
let a = 14;
let b = 21;
assert_eq!(42, mcm::<i32>(&a, &b));
}
}
#[cfg(test)]
mod big_int_tests {
use super::*;
use num_bigint::BigInt;
use std::collections::BTreeSet;
#[test]
fn test_gcd() {
assert_eq!(6, gcd(&12, &18));
assert_eq!(6, gcd(&18, &12));
}
#[test]
fn test_simplify() {
let mut r1 = Rational::new(BigInt::from(15), BigInt::from(105));
assert_eq!(Rational::new(BigInt::from(1), BigInt::from(7)), r1);
r1.simplify();
assert_eq!(Rational::new(BigInt::from(1), BigInt::from(7)), r1);
}
#[test]
fn test_add() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(4), BigInt::from(10));
let r3 = Rational::new(BigInt::from(1), BigInt::from(7));
assert_eq!(Rational::<BigInt>::one(), &r1 + &r2);
assert_eq!(&r2 + &r1, &r1 + &r2);
assert_eq!(&r1 + &r2 + &r3, &r3 + &r2 + &r1);
}
#[test]
fn test_add_assign() {
let mut r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(4), BigInt::from(10));
r1 += r2;
assert_eq!(Rational::<BigInt>::one(), r1);
}
#[test]
fn test_sub() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(4), BigInt::from(10));
let r3 = Rational::new(BigInt::from(1), BigInt::from(7));
assert_eq!(Rational::<BigInt>::zero(), &r1 - &r1);
assert_eq!(Rational::new(BigInt::from(-1), BigInt::from(5)), &r2 - &r1);
assert!(Rational::<BigInt>::zero() > &r3 - &r1);
assert!(Rational::<BigInt>::zero() > &r3 - &r2);
assert!(Rational::<BigInt>::zero() > r3 - r1);
}
#[test]
fn test_sub_assign() {
let mut r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(4), BigInt::from(10));
r1 -= r2;
assert_eq!(Rational::<BigInt>::new(BigInt::one(), BigInt::from(5)), r1);
}
#[test]
fn test_mul() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(-4), BigInt::from(10));
let r3 = Rational::new(BigInt::from(1), BigInt::from(7));
assert_eq!(Rational::new(BigInt::from(9), BigInt::from(25)), &r1 * &r1);
assert_eq!(
Rational::new(BigInt::from(-12), BigInt::from(50)),
&r2 * &r1
);
assert_eq!(Rational::new(BigInt::from(2), BigInt::from(-35)), r2 * r3);
}
#[test]
fn test_mul_assign() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(-4), BigInt::from(10));
let r3 = Rational::new(BigInt::from(-12), BigInt::from(50));
let mut r4 = r1.clone();
r4 *= &r1;
assert_eq!(
Rational::<BigInt>::new(BigInt::from(9), BigInt::from(25)),
r4
);
let mut r5 = r1.clone();
r5 *= r2;
assert_eq!(r3, r5);
}
#[test]
fn test_div() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(-4), BigInt::from(10));
let r3 = Rational::new(BigInt::from(1), BigInt::from(7));
assert_eq!(Rational::<BigInt>::one(), &r1 / &r1);
assert_eq!(Rational::new(BigInt::from(-2), BigInt::from(3)), &r2 / r1);
assert_eq!(Rational::new(BigInt::from(28), BigInt::from(-10)), r2 / r3);
}
#[test]
fn test_div_assign() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(-4), BigInt::from(10));
let r3 = Rational::new(BigInt::from(30), BigInt::from(-20));
let mut r4 = r1.clone();
r4 /= &r1;
assert_eq!(Rational::<BigInt>::one(), r4);
let mut r5 = r1.clone();
r5 /= r2;
assert_eq!(r3, r5);
}
#[test]
fn test_eq() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(6), BigInt::from(10));
let r3 = Rational::new(BigInt::from(300), BigInt::from(500));
let r4 = Rational::new(BigInt::from(300), BigInt::from(-500));
assert!(r1 == r2);
assert!(r1 == r3);
assert!(r1 != r4);
}
#[test]
fn test_ord() {
let r1 = Rational::new(BigInt::from(3), BigInt::from(5));
let r2 = Rational::new(BigInt::from(7), BigInt::from(10));
let r3 = Rational::new(BigInt::from(301), BigInt::from(500));
let r4 = Rational::new(BigInt::from(300), BigInt::from(-500));
let values: Vec<&Rational<BigInt>> = BTreeSet::from([&r1, &r2, &r3, &r4])
.iter()
.map(|it| *it)
.collect();
let expected_order = Vec::from([&r4, &r1, &r3, &r2]);
assert_eq!(expected_order, values);
}
}