diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8269222 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +coverage: coverage.html + +coverage.html: coverage-report + +generate-coverage: + cargo tarpaulin --out Xml + +coverage-report: generate-coverage + pycobertura show --format html --output coverage.html cobertura.xml + +clean: + cargo clean + rm cobertura.xml + rm coverage.html \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 9ca4e41..15d68b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ //! Playin' with Numerics in Rust #![forbid(unsafe_code)] +#[cfg_attr(tarpaulin, skip)] pub mod bigint; pub mod num; pub mod rational; @@ -99,6 +100,7 @@ fn _factorial(n: usize, table: &mut Vec) -> Option { } #[cfg(test)] +#[cfg_attr(tarpaulin, skip)] mod tests { use super::*; diff --git a/src/num.rs b/src/num.rs index beefea6..e9c0674 100644 --- a/src/num.rs +++ b/src/num.rs @@ -9,6 +9,7 @@ use core::ops::{ /// Represents the sign of a rational number #[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(u8)] pub enum Sign { /// Greater than zero, or zero Positive, @@ -51,17 +52,11 @@ pub trait Num: + Sub + SubAssign { - /// Is this number type signed? - fn is_signed(&self) -> bool { - true + fn abs(self) -> Self { + self } } -/// Float primitive -pub trait Float: Num { - fn is_neg(self) -> bool; -} - /// Integer primitive pub trait Int: Num @@ -95,10 +90,6 @@ pub trait Int: /// overflow would occur. If an overflow would have occurred then the wrapped value is returned. fn left_overflowing_sub(self, rhs: Self) -> (Self, bool); - /// Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic - /// overflow would occur. If an overflow would have occurred then the wrapped value is returned. - fn left_overflowing_mul(self, rhs: Self) -> (Self, bool); - /// Convert to an unsigned number /// /// A meaningless operation when implemented on an @@ -114,14 +105,6 @@ pub trait Unsigned: Int { /// Find the least common multiple of two numbers fn lcm(a: Self, b: Self) -> Self; - - fn is_signed(self) -> bool { - false - } - - fn to_unsigned(self) -> Self { - self - } } /// A Trait representing signed integer primitives @@ -135,18 +118,6 @@ macro_rules! impl_num { } } -macro_rules! impl_float { - ($( $Type: ty ),* ) => { - $( - impl Float for $Type { - fn is_neg(self) -> bool { - self < 0.0 - } - } - )* - } -} - macro_rules! impl_int { ($(($type: ty, $un_type: ty)),* ) => { $( @@ -163,29 +134,15 @@ macro_rules! impl_int { } fn is_neg(self) -> bool { - if self.is_signed() == false { - false - } else { - self < 0 - } + self < 0 } fn to_unsigned(self) -> $un_type { + let abs = <$type>::abs(self); // Converting from signed to unsigned should always be safe // when using the absolute value, especially since I'm converting // between the same bit size - <$un_type>::try_from(self).unwrap() - } - - fn left_overflowing_mul(self, rhs: Self) -> (Self, bool) { - let (res, overflow) = <$type>::overflowing_mul(self, rhs); - let res = if overflow { - <$type>::max_value() - res + 1 - } else { - res - }; - - (res, overflow) + <$un_type>::try_from(abs).unwrap() } fn left_overflowing_sub(self, rhs: Self) -> (Self, bool) { @@ -263,8 +220,7 @@ macro_rules! impl_signed { } } -impl_num!(i8, u8, i16, u16, f32, i32, u32, f64, i64, u64, i128, u128, isize, usize); -impl_float!(f32, f64); +impl_num!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); impl_int!( (i8, u8), (u8, u8), @@ -306,5 +262,6 @@ mod tests { assert_eq!(u16::lcm(2, 3), 6); assert_eq!(usize::lcm(15, 30), 30); assert_eq!(u128::lcm(1, 5), 5); + assert_eq!(0u8, u8::lcm(0, 0)); } } diff --git a/src/rational.rs b/src/rational.rs index d9ed1df..237ba0e 100644 --- a/src/rational.rs +++ b/src/rational.rs @@ -117,23 +117,21 @@ impl Frac { /// Determine the output sign given the two input signs fn get_sign(a: Self, b: Self, op: FracOp) -> Sign { - if op == FracOp::Addition { - return if a.sign == Positive && b.sign == Positive { - Positive - } else { - Negative - }; + let mut output = Sign::default(); + + if op == FracOp::Addition && !(a.sign == Positive && b.sign == Positive) { + output = Negative; } if a.sign != b.sign { - if op == FracOp::Subtraction && b.sign == Negative { + output = if op == FracOp::Subtraction && b.sign == Negative { Positive } else { Negative } - } else { - Positive } + + output } /// Convert the fraction to its simplest form @@ -189,12 +187,6 @@ where b.numer *= y; b.denom *= y; - debug_assert_eq!( - a.denom, b.denom, - "Denominators should be equal here. \n{:#?}\n{:#?}\n{:?}\n{:?}", - a, b, x, y - ); - a.numer.cmp(&b.numer) } } @@ -352,8 +344,17 @@ impl Neg for Frac { } } +#[cfg_attr(tarpaulin, skip)] #[cfg(test)] mod tests { + use super::*; + + #[test] + #[should_panic(expected = "Fraction can not have a zero denominator")] + fn zero_denom() { + Frac::raw(1u8, 0u8, Sign::default()); + } + #[test] fn macro_test() { let frac1 = frac!(1 / 3); @@ -366,5 +367,9 @@ mod tests { assert_eq!(frac!(3 / 2), frac!(1 1/2)); assert_eq!(frac!(3 / 1), frac!(3)); + + assert_eq!(-frac!(1/2), frac!(-1/2)); + assert_eq!(-frac!(1/2), frac!(1/-2)); + assert_eq!(frac!(1/2), frac!(-1/-2)); } } diff --git a/tests/fractions.rs b/tests/fractions.rs index d4bd343..2ef1ba2 100644 --- a/tests/fractions.rs +++ b/tests/fractions.rs @@ -1,3 +1,5 @@ +#![cfg_attr(tarpaulin, skip)] + use rusty_numbers::frac; #[test] @@ -33,6 +35,7 @@ fn sub_test() { #[test] fn cmp_test() { + assert!(frac!(1/2) <= frac!(1/2)); assert!(frac!(0) < frac!(1)); assert!(-frac!(5 / 3) < frac!(1 / 10_000)); assert!(frac!(1 / 10_000) > -frac!(10)); @@ -54,3 +57,32 @@ fn negative_mul_div() { assert_eq!(-frac!(1 / 12), frac!(1 / 3) * -frac!(1 / 4)); assert_eq!(frac!(1 / 12), -frac!(1 / 3) * -frac!(1 / 4)); } + +#[test] +#[should_panic(expected = "Fraction can not have a zero denominator")] +fn zero_denom() { + frac!(1 / 0); +} + +#[test] +fn op_assign() { + // Addition + let mut quart = frac!(1/4); + quart += frac!(1/4); + assert_eq!(frac!(1/2), quart); + + // Subtraction + let mut half = frac!(1/2); + half -= frac!(1/4); + assert_eq!(frac!(1/4), half); + + // Multiplication + let mut half = frac!(1/2); + half *= frac!(1/2); + assert_eq!(frac!(1/4), half); + + // Division + let mut quart = frac!(1/4); + quart /= frac!(4); + assert_eq!(frac!(1/16), quart); +}