initial commit
This commit is contained in:
791
src/rational.rs
Normal file
791
src/rational.rs
Normal 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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user