Skip to content

Commit

Permalink
Add AbsOrd impls and NumOrd impls
Browse files Browse the repository at this point in the history
  • Loading branch information
cmpute committed Jan 11, 2024
1 parent 7181b12 commit d421660
Show file tree
Hide file tree
Showing 12 changed files with 208 additions and 136 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ homepage = "https://github.com/cmpute/dashu"
documentation = "https://docs.rs/dashu"
readme = "README.md"
license = "MIT OR Apache-2.0"
rust-version = "1.64"
rust-version = "1.61"

[package.metadata.docs.rs]
all-features = true
Expand Down
2 changes: 1 addition & 1 deletion base/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repository = "https://github.com/cmpute/dashu"
homepage = "https://github.com/cmpute/dashu"
documentation = "https://docs.rs/dashu-base"
readme = "README.md"
rust-version = "1.64"
rust-version = "1.61"

[package.metadata.docs.rs]
all-features = true
Expand Down
2 changes: 0 additions & 2 deletions base/src/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ pub trait UnsignedAbs {
fn unsigned_abs(self) -> Self::Output;
}

// TODO(next): implement abs_eq, abs_cmp among UBig/IBig/FBig/RBig

/// Check whether the magnitude of this number is equal the magnitude of the other number
///
/// # Examples
Expand Down
3 changes: 2 additions & 1 deletion float/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
- Add `Repr::from_static_words` to support the `static_fbig!` and `static_dbig!` macros.
- Add `FBig::from_repr_const` to support create an `FBig` instance from repr in const context.
- Add conversion from `f32`/`f64` to `Repr<2>`.
- Add `NumOrd` implementations between `FBig` and primitive integers / floats.
- Implement `NumOrd` between `FBig` and primitive integers / floats.
- Implement `AbsOrd` between `FBig` and `UBig`/`IBig`

### Change

Expand Down
2 changes: 1 addition & 1 deletion float/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repository = "https://github.com/cmpute/dashu"
homepage = "https://github.com/cmpute/dashu"
documentation = "https://docs.rs/dashu-float"
readme = "README.md"
rust-version = "1.64"
rust-version = "1.61"

[package.metadata.docs.rs]
all-features = true
Expand Down
118 changes: 116 additions & 2 deletions float/src/cmp.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
use core::cmp::Ordering;

use dashu_base::{AbsOrd, Sign};
use dashu_base::{AbsOrd, EstimatedLog2, Sign};
use dashu_int::{IBig, UBig};

use crate::{fbig::FBig, repr::Repr, repr::Word, round::Round, utils::shl_digits};
use crate::{
fbig::FBig,
repr::Repr,
repr::Word,
round::Round,
utils::{shl_digits, shl_digits_in_place},
};

impl<R1: Round, R2: Round, const B: Word> PartialEq<FBig<R2, B>> for FBig<R1, B> {
#[inline]
Expand Down Expand Up @@ -171,3 +178,110 @@ impl<R: Round, const B: Word> AbsOrd for FBig<R, B> {
)
}
}

pub(crate) fn repr_cmp_ubig<const B: Word, const ABS: bool>(lhs: &Repr<B>, rhs: &UBig) -> Ordering {
// case 1: compare with inf
if lhs.is_infinite() {
return if lhs.exponent > 0 || ABS {
Ordering::Greater
} else {
Ordering::Less
};
}

// case 2: compare sign
if !ABS && lhs.significand.sign() == Sign::Negative {
return Ordering::Less;
}

// case 3: compare log2 estimations
let (lhs_lo, lhs_hi) = lhs.log2_bounds();
let (rhs_lo, rhs_hi) = rhs.log2_bounds();
if lhs_lo > rhs_hi {
return Ordering::Greater;
}
if lhs_hi < rhs_lo {
return Ordering::Less;
}

// case 4: compare the exact values
let mut rhs: IBig = rhs.clone().into();
if lhs.exponent < 0 {
shl_digits_in_place::<B>(&mut rhs, (-lhs.exponent) as usize);
lhs.significand.cmp(&rhs)
} else {
shl_digits::<B>(&lhs.significand, lhs.exponent as usize).cmp(&rhs)
}
}

pub(crate) fn repr_cmp_ibig<const B: Word, const ABS: bool>(lhs: &Repr<B>, rhs: &IBig) -> Ordering {
// case 1: compare with inf
if lhs.is_infinite() {
return if lhs.exponent > 0 || ABS {
Ordering::Greater
} else {
Ordering::Less
};
}

// case 2: compare sign
let sign = if ABS {
Sign::Positive
} else {
match (lhs.significand.sign(), rhs.sign()) {
(Sign::Positive, Sign::Positive) => Sign::Positive,
(Sign::Positive, Sign::Negative) => return Ordering::Greater,
(Sign::Negative, Sign::Positive) => return Ordering::Less,
(Sign::Negative, Sign::Negative) => Sign::Negative,
}
};

// case 3: compare log2 estimations
let (lhs_lo, lhs_hi) = lhs.log2_bounds();
let (rhs_lo, rhs_hi) = rhs.log2_bounds();
if lhs_lo > rhs_hi {
return sign * Ordering::Greater;
}
if lhs_hi < rhs_lo {
return sign * Ordering::Less;
}

// case 4: compare the exact values
if lhs.exponent < 0 {
lhs.significand
.cmp(&shl_digits::<B>(rhs, (-lhs.exponent) as usize))
} else {
shl_digits::<B>(&lhs.significand, lhs.exponent as usize).cmp(rhs)
}
}

macro_rules! impl_abs_ord_with_method {
($T:ty, $method:ident) => {
impl<const B: Word> AbsOrd<$T> for Repr<B> {
#[inline]
fn abs_cmp(&self, other: &$T) -> Ordering {
$method::<B, true>(self, other)
}
}
impl<const B: Word> AbsOrd<Repr<B>> for $T {
#[inline]
fn abs_cmp(&self, other: &Repr<B>) -> Ordering {
$method::<B, true>(other, self).reverse()
}
}
impl<R: Round, const B: Word> AbsOrd<$T> for FBig<R, B> {
#[inline]
fn abs_cmp(&self, other: &$T) -> Ordering {
$method::<B, true>(&self.repr, other)
}
}
impl<R: Round, const B: Word> AbsOrd<FBig<R, B>> for $T {
#[inline]
fn abs_cmp(&self, other: &FBig<R, B>) -> Ordering {
$method::<B, true>(&other.repr, self).reverse()
}
}
};
}
impl_abs_ord_with_method!(UBig, repr_cmp_ubig);
impl_abs_ord_with_method!(IBig, repr_cmp_ibig);
Loading

0 comments on commit d421660

Please sign in to comment.