2020-02-12 23:10:08 -05:00
|
|
|
//! # Rational Numbers (fractions)
|
2020-02-12 22:29:57 -05:00
|
|
|
|
2020-04-16 14:07:12 -04:00
|
|
|
use core::cmp::{Ord, Ordering, PartialOrd};
|
|
|
|
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
2020-02-12 23:10:08 -05:00
|
|
|
|
2022-02-11 15:48:41 -05:00
|
|
|
use crate::num::Sign::{Negative, Positive};
|
|
|
|
use crate::num::{FracOp, Int, Sign, Unsigned};
|
|
|
|
|
2020-02-18 16:38:26 -05:00
|
|
|
/// Type representing a fraction
|
2020-02-19 16:22:01 -05:00
|
|
|
///
|
|
|
|
/// There are three basic constructors:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rusty_numbers::frac;
|
|
|
|
/// use rusty_numbers::rational::Frac;
|
|
|
|
///
|
|
|
|
/// // Macro
|
|
|
|
/// let reduced_macro = frac!(3 / 4);
|
|
|
|
///
|
|
|
|
/// // Frac::new (called by the macro)
|
|
|
|
/// let reduced = Frac::new(3, 4);
|
|
|
|
/// # assert_eq!(reduced_macro, reduced);
|
|
|
|
///
|
|
|
|
/// // Frac::new_unreduced
|
|
|
|
/// let unreduced = Frac::new_unreduced(4, 16);
|
|
|
|
/// ```
|
2020-02-14 17:24:51 -05:00
|
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
2020-02-12 22:29:57 -05:00
|
|
|
pub struct Frac<T: Unsigned = usize> {
|
2021-12-08 09:57:27 -05:00
|
|
|
numerator: T,
|
|
|
|
denominator: T,
|
2020-02-12 23:10:08 -05:00
|
|
|
sign: Sign,
|
2020-02-12 22:29:57 -05:00
|
|
|
}
|
|
|
|
|
2020-02-18 16:38:26 -05:00
|
|
|
/// Create a [Frac](rational/struct.Frac.html) type with signed or unsigned number literals
|
|
|
|
///
|
2020-02-19 16:22:01 -05:00
|
|
|
/// Example:
|
|
|
|
/// ```
|
|
|
|
/// use rusty_numbers::frac;
|
2020-02-18 16:38:26 -05:00
|
|
|
///
|
2020-02-19 16:22:01 -05:00
|
|
|
/// // Proper fractions
|
|
|
|
/// frac!(1 / 3);
|
|
|
|
///
|
|
|
|
/// // Improper fractions
|
|
|
|
/// frac!(4 / 3);
|
2020-02-18 16:38:26 -05:00
|
|
|
///
|
|
|
|
/// // Whole numbers
|
|
|
|
/// frac!(5u8);
|
|
|
|
///
|
|
|
|
/// // Whole numbers and fractions
|
|
|
|
/// frac!(1 1/2);
|
|
|
|
/// ```
|
2020-02-20 11:35:04 -05:00
|
|
|
#[macro_export]
|
2020-02-14 17:24:51 -05:00
|
|
|
macro_rules! frac {
|
2020-02-18 10:19:57 -05:00
|
|
|
($w:literal $n:literal / $d:literal) => {
|
|
|
|
frac!($w) + frac!($n / $d)
|
2020-02-14 17:24:51 -05:00
|
|
|
};
|
2020-02-14 23:41:14 -05:00
|
|
|
($n:literal / $d:literal) => {
|
2020-02-19 09:39:19 -05:00
|
|
|
$crate::rational::Frac::new($n, $d)
|
2020-02-14 17:24:51 -05:00
|
|
|
};
|
2020-02-18 10:19:57 -05:00
|
|
|
($w:literal) => {
|
2020-02-19 09:39:19 -05:00
|
|
|
$crate::rational::Frac::new($w, 1)
|
2020-02-18 10:19:57 -05:00
|
|
|
};
|
2020-02-14 17:24:51 -05:00
|
|
|
}
|
|
|
|
|
2020-02-19 09:39:19 -05:00
|
|
|
impl<T: Unsigned> Frac<T> {
|
|
|
|
/// Create a new rational number from signed or unsigned arguments
|
|
|
|
///
|
|
|
|
/// Generally, you will probably prefer to use the [frac!](../macro.frac.html) macro
|
|
|
|
/// instead, as that is easier for mixed fractions and whole numbers
|
2021-12-08 09:57:27 -05:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
/// if `d` is 0, this constructor will panic
|
2020-02-19 14:08:43 -05:00
|
|
|
pub fn new<N: Int<Un = T>>(n: N, d: N) -> Frac<T> {
|
2020-02-19 09:39:19 -05:00
|
|
|
Self::new_unreduced(n, d).reduce()
|
2020-02-14 23:41:14 -05:00
|
|
|
}
|
2020-02-14 17:24:51 -05:00
|
|
|
|
2020-02-19 09:39:19 -05:00
|
|
|
/// Create a new rational number from signed or unsigned arguments
|
|
|
|
/// where the resulting fraction is not reduced
|
2021-12-08 09:57:27 -05:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
/// if `d` is 0, this constructor will panic
|
2020-02-19 14:08:43 -05:00
|
|
|
pub fn new_unreduced<N: Int<Un = T>>(n: N, d: N) -> Frac<T> {
|
2022-02-11 15:48:41 -05:00
|
|
|
assert!(!d.is_zero(), "Fraction can not have a zero denominator");
|
2020-02-14 23:41:14 -05:00
|
|
|
|
2020-02-19 14:08:43 -05:00
|
|
|
let mut sign = Positive;
|
2020-02-18 16:38:26 -05:00
|
|
|
|
2020-02-19 09:39:19 -05:00
|
|
|
if n.is_neg() {
|
|
|
|
sign = !sign;
|
|
|
|
}
|
2020-02-14 17:24:51 -05:00
|
|
|
|
2020-02-19 09:39:19 -05:00
|
|
|
if d.is_neg() {
|
|
|
|
sign = !sign;
|
|
|
|
}
|
|
|
|
|
2020-02-19 14:08:43 -05:00
|
|
|
// Convert the possibly signed arguments to unsigned values
|
2021-12-08 09:57:27 -05:00
|
|
|
let numerator = n.to_unsigned();
|
|
|
|
let denominator = d.to_unsigned();
|
2020-02-19 09:39:19 -05:00
|
|
|
|
2021-12-08 10:35:10 -05:00
|
|
|
Frac {
|
|
|
|
numerator,
|
|
|
|
denominator,
|
|
|
|
sign,
|
|
|
|
}
|
2020-02-18 21:29:40 -05:00
|
|
|
}
|
|
|
|
|
2022-02-11 15:48:41 -05:00
|
|
|
/// Create a new, reduced rational from all the raw parts
|
2021-12-08 09:57:27 -05:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
/// if `d` is 0, this constructor will panic
|
2020-02-19 09:39:19 -05:00
|
|
|
fn raw(n: T, d: T, s: Sign) -> Frac<T> {
|
2022-02-11 15:48:41 -05:00
|
|
|
assert!(!d.is_zero(), "Fraction can not have a zero denominator");
|
2020-02-13 17:13:25 -05:00
|
|
|
|
2020-02-12 22:29:57 -05:00
|
|
|
Frac {
|
2021-12-08 09:57:27 -05:00
|
|
|
numerator: n,
|
|
|
|
denominator: d,
|
2020-02-14 17:24:51 -05:00
|
|
|
sign: s,
|
2020-02-19 15:07:40 -05:00
|
|
|
}
|
|
|
|
.reduce()
|
2020-02-13 17:13:25 -05:00
|
|
|
}
|
|
|
|
|
2020-02-14 17:24:51 -05:00
|
|
|
/// Determine the output sign given the two input signs
|
2020-02-19 15:07:40 -05:00
|
|
|
fn get_sign(a: Self, b: Self, op: FracOp) -> Sign {
|
2020-03-13 17:08:43 -04:00
|
|
|
// -a + -b = -c
|
|
|
|
if op == FracOp::Addition && a.sign == Negative && b.sign == Negative {
|
|
|
|
return Negative;
|
|
|
|
}
|
2020-02-19 21:10:53 -05:00
|
|
|
|
2020-03-13 17:08:43 -04:00
|
|
|
// a - -b = c
|
|
|
|
if op == FracOp::Subtraction && a.sign == Positive && b.sign == Negative {
|
|
|
|
return Positive;
|
2020-02-19 14:08:43 -05:00
|
|
|
}
|
|
|
|
|
2021-12-08 10:35:10 -05:00
|
|
|
if a.sign == b.sign {
|
2020-03-13 17:08:43 -04:00
|
|
|
Positive
|
2021-12-08 10:35:10 -05:00
|
|
|
} else {
|
|
|
|
Negative
|
2020-02-14 17:24:51 -05:00
|
|
|
}
|
2020-02-13 17:13:25 -05:00
|
|
|
}
|
|
|
|
|
2020-02-14 17:24:51 -05:00
|
|
|
/// Convert the fraction to its simplest form
|
2020-02-19 16:22:01 -05:00
|
|
|
pub fn reduce(mut self) -> Self {
|
2021-12-08 09:57:27 -05:00
|
|
|
let gcd = T::gcd(self.numerator, self.denominator);
|
|
|
|
self.numerator /= gcd;
|
|
|
|
self.denominator /= gcd;
|
2020-02-13 17:13:25 -05:00
|
|
|
|
|
|
|
self
|
2020-02-12 22:29:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-19 21:23:07 -05:00
|
|
|
impl<T: Unsigned> PartialOrd for Frac<T> {
|
2020-02-18 20:59:58 -05:00
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-19 21:23:07 -05:00
|
|
|
impl<T: Unsigned> Ord for Frac<T> {
|
2020-02-18 20:59:58 -05:00
|
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
2020-02-19 09:39:19 -05:00
|
|
|
if self.sign != other.sign {
|
2020-02-19 14:08:43 -05:00
|
|
|
return if self.sign == Positive {
|
2020-02-19 09:39:19 -05:00
|
|
|
Ordering::Greater
|
2020-02-18 20:59:58 -05:00
|
|
|
} else {
|
2020-02-19 09:39:19 -05:00
|
|
|
Ordering::Less
|
|
|
|
};
|
|
|
|
}
|
2020-02-18 21:29:40 -05:00
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
if self.denominator == other.denominator {
|
|
|
|
return self.numerator.cmp(&other.numerator);
|
2020-02-19 09:39:19 -05:00
|
|
|
}
|
2020-02-18 20:59:58 -05:00
|
|
|
|
2020-02-19 09:39:19 -05:00
|
|
|
let mut a = self.reduce();
|
|
|
|
let mut b = other.reduce();
|
2020-02-18 20:59:58 -05:00
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
if a.denominator == b.denominator {
|
|
|
|
return a.numerator.cmp(&b.numerator);
|
2020-02-18 20:59:58 -05:00
|
|
|
}
|
2020-02-19 09:39:19 -05:00
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
let lcm = T::lcm(self.denominator, other.denominator);
|
|
|
|
let x = lcm / self.denominator;
|
|
|
|
let y = lcm / other.denominator;
|
2020-02-19 09:39:19 -05:00
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
a.numerator *= x;
|
|
|
|
a.denominator *= x;
|
2020-02-19 09:39:19 -05:00
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
b.numerator *= y;
|
|
|
|
b.denominator *= y;
|
2020-02-19 09:39:19 -05:00
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
a.numerator.cmp(&b.numerator)
|
2020-02-18 20:59:58 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-19 21:23:07 -05:00
|
|
|
impl<T: Unsigned> Mul for Frac<T> {
|
2020-02-14 12:30:09 -05:00
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn mul(self, rhs: Self) -> Self {
|
2021-12-08 09:57:27 -05:00
|
|
|
let numerator = self.numerator * rhs.numerator;
|
|
|
|
let denominator = self.denominator * rhs.denominator;
|
2020-02-18 16:38:26 -05:00
|
|
|
let sign = Self::get_sign(self, rhs, FracOp::Other);
|
2020-02-14 17:24:51 -05:00
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
Self::raw(numerator, denominator, sign)
|
2020-02-14 17:24:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-19 21:23:07 -05:00
|
|
|
impl<T: Unsigned> MulAssign for Frac<T> {
|
2020-02-18 10:19:57 -05:00
|
|
|
fn mul_assign(&mut self, rhs: Self) {
|
2021-12-08 09:57:27 -05:00
|
|
|
*self = *self * rhs;
|
2020-02-18 10:19:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-19 21:23:07 -05:00
|
|
|
impl<T: Unsigned> Div for Frac<T> {
|
2020-02-14 17:24:51 -05:00
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn div(self, rhs: Self) -> Self {
|
2021-12-08 09:57:27 -05:00
|
|
|
let numerator = self.numerator * rhs.denominator;
|
|
|
|
let denominator = self.denominator * rhs.numerator;
|
2020-02-18 16:38:26 -05:00
|
|
|
let sign = Self::get_sign(self, rhs, FracOp::Other);
|
2020-02-14 17:24:51 -05:00
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
Self::raw(numerator, denominator, sign)
|
2020-02-14 17:24:51 -05:00
|
|
|
}
|
|
|
|
}
|
2020-02-14 12:30:09 -05:00
|
|
|
|
2020-02-19 21:23:07 -05:00
|
|
|
impl<T: Unsigned> DivAssign for Frac<T> {
|
2020-02-18 10:19:57 -05:00
|
|
|
fn div_assign(&mut self, rhs: Self) {
|
2021-12-08 09:57:27 -05:00
|
|
|
*self = *self / rhs;
|
2020-02-18 10:19:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-19 21:23:07 -05:00
|
|
|
impl<T: Unsigned> Add for Frac<T> {
|
2020-02-14 17:24:51 -05:00
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn add(self, rhs: Self) -> Self::Output {
|
|
|
|
let a = self;
|
|
|
|
let b = rhs;
|
|
|
|
|
|
|
|
// If the sign of one input differs,
|
|
|
|
// subtraction is equivalent
|
2020-02-19 14:08:43 -05:00
|
|
|
if a.sign == Negative && b.sign == Positive {
|
|
|
|
return b - -a;
|
|
|
|
} else if a.sign == Positive && b.sign == Negative {
|
|
|
|
return a - -b;
|
2020-02-14 12:30:09 -05:00
|
|
|
}
|
2020-02-14 17:24:51 -05:00
|
|
|
|
|
|
|
// Find a common denominator if needed
|
2021-12-08 09:57:27 -05:00
|
|
|
if a.denominator != b.denominator {
|
2020-02-14 17:24:51 -05:00
|
|
|
// Let's just use the simplest method, rather than
|
|
|
|
// worrying about reducing to the least common denominator
|
2021-12-08 09:57:27 -05:00
|
|
|
let numerator = (a.numerator * b.denominator) + (b.numerator * a.denominator);
|
|
|
|
let denominator = a.denominator * b.denominator;
|
2020-02-19 14:08:43 -05:00
|
|
|
let sign = Self::get_sign(a, b, FracOp::Addition);
|
2020-02-14 17:24:51 -05:00
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
return Self::raw(numerator, denominator, sign);
|
2020-02-14 17:24:51 -05:00
|
|
|
}
|
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
let numerator = a.numerator + b.numerator;
|
|
|
|
let denominator = self.denominator;
|
2020-02-19 14:08:43 -05:00
|
|
|
let sign = Self::get_sign(a, b, FracOp::Addition);
|
2020-02-14 17:24:51 -05:00
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
Self::raw(numerator, denominator, sign)
|
2020-02-14 17:24:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-19 21:23:07 -05:00
|
|
|
impl<T: Unsigned> AddAssign for Frac<T> {
|
2020-02-18 10:19:57 -05:00
|
|
|
fn add_assign(&mut self, rhs: Self) {
|
2021-12-08 09:57:27 -05:00
|
|
|
*self = *self + rhs;
|
2020-02-18 10:19:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-19 21:23:07 -05:00
|
|
|
impl<T: Unsigned> Sub for Frac<T> {
|
2020-02-14 17:24:51 -05:00
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn sub(self, rhs: Self) -> Self::Output {
|
2020-02-18 20:59:58 -05:00
|
|
|
let a = self;
|
2020-02-18 16:38:26 -05:00
|
|
|
let b = rhs;
|
2020-02-14 17:24:51 -05:00
|
|
|
|
2020-02-19 14:08:43 -05:00
|
|
|
if a.sign == Positive && b.sign == Negative {
|
|
|
|
return a + -b;
|
|
|
|
} else if a.sign == Negative && b.sign == Positive {
|
2020-02-19 15:07:40 -05:00
|
|
|
return -(b + -a);
|
2020-02-19 14:08:43 -05:00
|
|
|
}
|
2020-02-18 20:59:58 -05:00
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
if a.denominator != b.denominator {
|
2021-12-08 10:35:10 -05:00
|
|
|
let (numerator, overflowed) =
|
|
|
|
(a.numerator * b.denominator).left_overflowing_sub(b.numerator * a.denominator);
|
2020-02-19 14:08:43 -05:00
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
let denominator = a.denominator * b.denominator;
|
2020-02-19 15:07:40 -05:00
|
|
|
let sign = Self::get_sign(a, b, FracOp::Subtraction);
|
2021-12-08 09:57:27 -05:00
|
|
|
let res = Self::raw(numerator, denominator, sign);
|
2020-02-19 15:07:40 -05:00
|
|
|
return if overflowed { -res } else { res };
|
2020-02-18 10:19:57 -05:00
|
|
|
}
|
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
let (numerator, overflowed) = a.numerator.left_overflowing_sub(b.numerator);
|
2020-02-19 14:08:43 -05:00
|
|
|
|
2021-12-08 09:57:27 -05:00
|
|
|
let denominator = a.denominator;
|
2020-02-19 15:07:40 -05:00
|
|
|
let sign = Self::get_sign(a, b, FracOp::Subtraction);
|
2021-12-08 09:57:27 -05:00
|
|
|
let res = Self::raw(numerator, denominator, sign);
|
2020-02-18 10:19:57 -05:00
|
|
|
|
2020-02-19 16:22:01 -05:00
|
|
|
if overflowed {
|
|
|
|
-res
|
|
|
|
} else {
|
|
|
|
res
|
|
|
|
}
|
2020-02-18 10:19:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-19 21:23:07 -05:00
|
|
|
impl<T: Unsigned> SubAssign for Frac<T> {
|
2020-02-18 10:19:57 -05:00
|
|
|
fn sub_assign(&mut self, rhs: Self) {
|
2021-12-08 09:57:27 -05:00
|
|
|
*self = *self - rhs;
|
2020-02-14 12:30:09 -05:00
|
|
|
}
|
2020-02-13 17:13:25 -05:00
|
|
|
}
|
|
|
|
|
2020-02-12 23:10:08 -05:00
|
|
|
impl<T: Unsigned> Neg for Frac<T> {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn neg(self) -> Self::Output {
|
2020-02-19 14:08:43 -05:00
|
|
|
let mut out = self;
|
2020-02-12 23:10:08 -05:00
|
|
|
out.sign = !self.sign;
|
|
|
|
|
|
|
|
out
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-12 22:29:57 -05:00
|
|
|
#[cfg(test)]
|
2020-09-15 10:31:44 -04:00
|
|
|
#[cfg(not(tarpaulin_include))]
|
2020-02-14 12:11:57 -05:00
|
|
|
mod tests {
|
2020-02-19 21:10:53 -05:00
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic(expected = "Fraction can not have a zero denominator")]
|
2021-12-08 09:57:27 -05:00
|
|
|
fn zero_denominator() {
|
2020-02-19 21:10:53 -05:00
|
|
|
Frac::raw(1u8, 0u8, Sign::default());
|
|
|
|
}
|
|
|
|
|
2020-03-13 17:08:43 -04:00
|
|
|
#[test]
|
|
|
|
#[should_panic(expected = "Fraction can not have a zero denominator")]
|
2021-12-08 09:57:27 -05:00
|
|
|
fn zero_denominator_new() {
|
2020-03-13 21:22:25 -04:00
|
|
|
frac!(1 / 0);
|
2020-03-13 17:08:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_get_sign() {
|
2020-03-13 21:22:25 -04:00
|
|
|
assert_eq!(
|
|
|
|
Sign::Positive,
|
|
|
|
Frac::get_sign(frac!(1), frac!(-1), FracOp::Subtraction)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
Sign::Negative,
|
|
|
|
Frac::get_sign(frac!(-1), frac!(-1), FracOp::Addition)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
Sign::Negative,
|
|
|
|
Frac::get_sign(frac!(-1), frac!(1), FracOp::Addition)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
Sign::Negative,
|
|
|
|
Frac::get_sign(frac!(-1), frac!(1), FracOp::Subtraction)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
Sign::Negative,
|
|
|
|
Frac::get_sign(frac!(-1), frac!(1), FracOp::Other)
|
|
|
|
);
|
2020-03-13 17:08:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_cmp() {
|
2020-03-13 21:22:25 -04:00
|
|
|
assert_eq!(Ordering::Greater, frac!(3 / 4).cmp(&frac!(1 / 4)));
|
|
|
|
assert_eq!(Ordering::Less, frac!(1 / 4).cmp(&frac!(3 / 4)));
|
|
|
|
assert_eq!(Ordering::Equal, frac!(1 / 2).cmp(&frac!(4 / 8)));
|
2020-03-13 17:08:43 -04:00
|
|
|
}
|
|
|
|
|
2020-02-14 17:24:51 -05:00
|
|
|
#[test]
|
|
|
|
fn macro_test() {
|
2020-02-14 23:41:14 -05:00
|
|
|
let frac1 = frac!(1 / 3);
|
2020-02-18 16:38:26 -05:00
|
|
|
let frac2 = frac!(1u32 / 3);
|
2020-02-14 17:24:51 -05:00
|
|
|
assert_eq!(frac1, frac2);
|
|
|
|
|
2020-02-14 23:41:14 -05:00
|
|
|
let frac1 = -frac!(1 / 2);
|
2020-02-18 16:38:26 -05:00
|
|
|
let frac2 = -frac!(1u32 / 2);
|
2020-02-14 17:24:51 -05:00
|
|
|
assert_eq!(frac1, frac2);
|
2020-02-18 10:19:57 -05:00
|
|
|
|
|
|
|
assert_eq!(frac!(3 / 2), frac!(1 1/2));
|
|
|
|
assert_eq!(frac!(3 / 1), frac!(3));
|
2020-02-19 21:10:53 -05:00
|
|
|
|
2020-02-19 21:23:07 -05:00
|
|
|
assert_eq!(-frac!(1 / 2), frac!(-1 / 2));
|
|
|
|
assert_eq!(-frac!(1 / 2), frac!(1 / -2));
|
|
|
|
assert_eq!(frac!(1 / 2), frac!(-1 / -2));
|
2020-02-14 17:24:51 -05:00
|
|
|
}
|
2020-02-14 12:11:57 -05:00
|
|
|
}
|