Skip to content

Commit

Permalink
Merge #21
Browse files Browse the repository at this point in the history
21: Implement Pow r=cuviper a=clarcharr

Should be merged after #19, as this PR depends on that one. Fixes #20.

Will need to investigate compile time increases that this change causes.

Co-authored-by: Clar Charr <clar@charr.xyz>
Co-authored-by: Josh Stone <cuviper@gmail.com>
  • Loading branch information
3 people committed Jun 16, 2018
2 parents 1c9c6c9 + 602a17c commit 77518f7
Showing 1 changed file with 97 additions and 16 deletions.
113 changes: 97 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ use bigint::{BigInt, BigUint, Sign};

use integer::Integer;
use traits::float::FloatCore;
use traits::{FromPrimitive, PrimInt, Num, Signed, Zero, One, Bounded, Inv, NumCast, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv};
use traits::{Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, FromPrimitive, Inv, Num,
NumCast, One, Pow, Signed, Zero};

/// Represents the ratio between two numbers.
#[derive(Copy, Clone, Debug)]
Expand Down Expand Up @@ -233,19 +234,89 @@ impl<T: Clone + Integer> Ratio<T> {
}
}

impl<T: Clone + Integer + PrimInt> Ratio<T> {
impl<T: Clone + Integer + Pow<u32, Output = T>> Ratio<T> {
/// Raises the `Ratio` to the power of an exponent.
#[inline]
pub fn pow(&self, expon: i32) -> Ratio<T> {
match expon.cmp(&0) {
cmp::Ordering::Equal => One::one(),
cmp::Ordering::Less => self.recip().pow(-expon),
cmp::Ordering::Greater => {
Ratio::new_raw(self.numer.pow(expon as u32), self.denom.pow(expon as u32))
Pow::pow(self, expon)
}
}

macro_rules! pow_impl {
($exp: ty) => {
pow_impl!($exp, $exp);
};
($exp: ty, $unsigned: ty) => {
impl<T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<$exp> for Ratio<T> {
type Output = Ratio<T>;
#[inline]
fn pow(self, expon: $exp) -> Ratio<T> {
match expon.cmp(&0) {
cmp::Ordering::Equal => One::one(),
cmp::Ordering::Less => {
let expon = expon.wrapping_abs() as $unsigned;
Ratio::new_raw(
Pow::pow(self.denom, expon),
Pow::pow(self.numer, expon),
)
},
cmp::Ordering::Greater => {
Ratio::new_raw(
Pow::pow(self.numer, expon as $unsigned),
Pow::pow(self.denom, expon as $unsigned),
)
}
}
}
}
impl<'a, T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<$exp> for &'a Ratio<T> {
type Output = Ratio<T>;
#[inline]
fn pow(self, expon: $exp) -> Ratio<T> {
Pow::pow(self.clone(), expon)
}
}
impl<'a, T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<&'a $exp> for Ratio<T> {
type Output = Ratio<T>;
#[inline]
fn pow(self, expon: &'a $exp) -> Ratio<T> {
Pow::pow(self, *expon)
}
}
impl<'a, 'b, T: Clone + Integer + Pow<$unsigned, Output = T>> Pow<&'a $exp> for &'b Ratio<T> {
type Output = Ratio<T>;
#[inline]
fn pow(self, expon: &'a $exp) -> Ratio<T> {
Pow::pow(self.clone(), *expon)
}
}
};
}

// this is solely to make `pow_impl!` work
trait WrappingAbs: Sized {
fn wrapping_abs(self) -> Self {
self
}
}
impl WrappingAbs for u8 {}
impl WrappingAbs for u16 {}
impl WrappingAbs for u32 {}
impl WrappingAbs for u64 {}
impl WrappingAbs for usize {}

pow_impl!(i8, u8);
pow_impl!(i16, u16);
pow_impl!(i32, u32);
pow_impl!(i64, u64);
pow_impl!(isize, usize);
pow_impl!(u8);
pow_impl!(u16);
pow_impl!(u32);
pow_impl!(u64);
pow_impl!(usize);

// TODO: pow_impl!(BigUint) and pow_impl!(BigInt, BigUint)

#[cfg(feature = "bigint")]
impl Ratio<BigInt> {
Expand Down Expand Up @@ -1202,7 +1273,7 @@ mod test {
use core::str::FromStr;
use core::i32;
use core::f64;
use traits::{Zero, One, Signed, FromPrimitive};
use traits::{Zero, One, Signed, FromPrimitive, Pow};
use integer::Integer;

pub const _0: Rational = Ratio {
Expand Down Expand Up @@ -1659,14 +1730,24 @@ mod test {

#[test]
fn test_pow() {
assert_eq!(_1_2.pow(2), Ratio::new(1, 4));
assert_eq!(_1_2.pow(-2), Ratio::new(4, 1));
assert_eq!(_1.pow(1), _1);
assert_eq!(_NEG1_2.pow(2), _1_2.pow(2));
assert_eq!(_NEG1_2.pow(3), -_1_2.pow(3));
assert_eq!(_3_2.pow(0), _1);
assert_eq!(_3_2.pow(-1), _3_2.recip());
assert_eq!(_3_2.pow(3), Ratio::new(27, 8));
fn test(r: Rational, e: i32, expected: Rational) {
assert_eq!(r.pow(e), expected);
assert_eq!(Pow::pow(r, e), expected);
assert_eq!(Pow::pow(r, &e), expected);
assert_eq!(Pow::pow(&r, e), expected);
assert_eq!(Pow::pow(&r, &e), expected);
}

test(_1_2, 2, Ratio::new(1, 4));
test(_1_2, -2, Ratio::new(4, 1));
test(_1, 1, _1);
test(_1, i32::MAX, _1);
test(_1, i32::MIN, _1);
test(_NEG1_2, 2, _1_2.pow(2i32));
test(_NEG1_2, 3, -_1_2.pow(3i32));
test(_3_2, 0, _1);
test(_3_2, -1, _3_2.recip());
test(_3_2, 3, Ratio::new(27, 8));
}

#[test]
Expand Down

0 comments on commit 77518f7

Please sign in to comment.