Skip to content

Commit

Permalink
Complete 'Round' trait implementation of 'Fraction' generic struct
Browse files Browse the repository at this point in the history
  • Loading branch information
lycantropos committed Jun 20, 2023
1 parent e99e95c commit 1578e0b
Showing 1 changed file with 75 additions and 17 deletions.
92 changes: 75 additions & 17 deletions src/fraction/round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@ use crate::big_int::BigInt;

use super::types::Fraction;

impl<Digit, const DIGIT_BITNESS: usize> Round
for Fraction<BigInt<Digit, DIGIT_BITNESS>>
impl<'a, Digit, const DIGIT_BITNESS: usize> Round
for &'a Fraction<BigInt<Digit, DIGIT_BITNESS>>
where
for<'a> &'a BigInt<Digit, DIGIT_BITNESS>: Parity + Signed,
for<'a> BigInt<Digit, DIGIT_BITNESS>: Add<Output = BigInt<Digit, DIGIT_BITNESS>>
+ CheckedDivRemEuclid<
&'a BigInt<Digit, DIGIT_BITNESS>,
Output = Option<(
BigInt<Digit, DIGIT_BITNESS>,
BigInt<Digit, DIGIT_BITNESS>,
)>,
> + One
&'a BigInt<Digit, DIGIT_BITNESS>: CheckedDivRemEuclid<
Output = Option<(
BigInt<Digit, DIGIT_BITNESS>,
BigInt<Digit, DIGIT_BITNESS>,
)>,
>,
BigInt<Digit, DIGIT_BITNESS>: Add<Output = BigInt<Digit, DIGIT_BITNESS>>
+ One
+ Ord
+ Shl<usize, Output = BigInt<Digit, DIGIT_BITNESS>>,
for<'b> &'b BigInt<Digit, DIGIT_BITNESS>: Parity + Signed,
{
type Output = BigInt<Digit, DIGIT_BITNESS>;

Expand Down Expand Up @@ -54,17 +54,17 @@ where
}

impl<Digit, const DIGIT_BITNESS: usize> Round
for &Fraction<BigInt<Digit, DIGIT_BITNESS>>
for Fraction<BigInt<Digit, DIGIT_BITNESS>>
where
for<'a> &'a BigInt<Digit, DIGIT_BITNESS>: CheckedDivRemEuclid<
for<'a> &'a BigInt<Digit, DIGIT_BITNESS>: Parity + Signed,
for<'a> BigInt<Digit, DIGIT_BITNESS>: Add<Output = BigInt<Digit, DIGIT_BITNESS>>
+ CheckedDivRemEuclid<
&'a BigInt<Digit, DIGIT_BITNESS>,
Output = Option<(
BigInt<Digit, DIGIT_BITNESS>,
BigInt<Digit, DIGIT_BITNESS>,
)>,
> + Parity
+ Signed,
for<'a> BigInt<Digit, DIGIT_BITNESS>: Add<Output = BigInt<Digit, DIGIT_BITNESS>>
+ One
> + One
+ Ord
+ Shl<usize, Output = BigInt<Digit, DIGIT_BITNESS>>,
{
Expand Down Expand Up @@ -99,6 +99,36 @@ where

macro_rules! signed_integer_fraction_round_impl {
($($integer:ty)*) => ($(
impl Round for &Fraction<$integer> {
type Output = $integer;

fn round(self, tie_breaking: TieBreaking) -> Self::Output {
let (quotient, remainder) = unsafe {
self.numerator
.checked_div_rem_euclid(self.denominator)
.unwrap_unchecked()
};
match (remainder << 1).cmp(&self.denominator) {
Ordering::Equal => {
if match tie_breaking {
TieBreaking::AwayFromZero => {
!quotient.is_negative()
}
TieBreaking::ToEven => quotient.is_odd(),
TieBreaking::ToOdd => quotient.is_even(),
TieBreaking::TowardZero => quotient.is_negative(),
} {
quotient + 1
} else {
quotient
}
}
Ordering::Greater => quotient + 1,
Ordering::Less => quotient,
}
}
}

impl Round for Fraction<$integer> {
type Output = $integer;

Expand Down Expand Up @@ -135,6 +165,34 @@ signed_integer_fraction_round_impl!(i8 i16 i32 i64 i128 isize);

macro_rules! unsigned_integer_fraction_round_impl {
($($integer:ty)*) => ($(
impl Round for &Fraction<$integer> {
type Output = $integer;

fn round(self, tie_breaking: TieBreaking) -> Self::Output {
let (quotient, remainder) = unsafe {
self.numerator
.checked_div_rem_euclid(self.denominator)
.unwrap_unchecked()
};
match (remainder << 1).cmp(&self.denominator) {
Ordering::Equal => {
if match tie_breaking {
TieBreaking::AwayFromZero => true,
TieBreaking::ToEven => quotient.is_odd(),
TieBreaking::ToOdd => quotient.is_even(),
TieBreaking::TowardZero => false,
} {
quotient + 1
} else {
quotient
}
}
Ordering::Greater => quotient + 1,
Ordering::Less => quotient,
}
}
}

impl Round for Fraction<$integer> {
type Output = $integer;

Expand Down

0 comments on commit 1578e0b

Please sign in to comment.