Skip to content

Commit

Permalink
add strict methods, midpoint methods
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacholt100 committed Sep 20, 2024
1 parent 52dcea2 commit 6d7c7a7
Show file tree
Hide file tree
Showing 19 changed files with 464 additions and 85 deletions.
8 changes: 7 additions & 1 deletion changes/v0.12.0
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
- Add optional borsh support
- Add `digits_mut` method to unsigned integers.
- `As` and `CastFrom` traits no longer const, as const trait support removed from latest nightly.
- `As` and `CastFrom` traits no longer const, as const trait support removed from latest nightly.
- `cast_signed` method for unsigned integers.
- `cast_unsigned` method for signed integers.
- `midpoint` method for unsigned integers.
- `carrying_add` and `borrowing_sub` methods for signed integers.
- strict methods added.
- added `(bnum) ` prefix to error messages that were lacking it.
20 changes: 20 additions & 0 deletions src/bint/bigint_helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
macro_rules! bigint_helpers {
($BUint: ident, $BInt: ident, $Digit: ident) => {
#[doc = doc::bigint_helpers::impl_desc!()]
impl<const N: usize> $BInt<N> {
crate::int::bigint_helpers::impls!(I);
}

#[cfg(test)]
paste::paste! {
mod [<$Digit _digit_tests>] {
use crate::test::types::big_types::$Digit::*;
crate::int::bigint_helpers::tests!(itest);
}
}
};
}

use crate::doc;

crate::macro_impl!(bigint_helpers);
2 changes: 1 addition & 1 deletion src/bint/const_trait_fillers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ macro_rules! const_trait_fillers {
#[inline]
pub const fn neg(self) -> Self {
#[cfg(debug_assertions)]
return crate::errors::option_expect!(self.checked_neg(), crate::errors::err_msg!("attempt to negate with overflow"));
return self.strict_neg();

#[cfg(not(debug_assertions))]
self.wrapping_neg()
Expand Down
34 changes: 30 additions & 4 deletions src/bint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ macro_rules! ilog {
}
}

#[cfg(debug_assertions)]
use crate::errors::option_expect;
// #[cfg(debug_assertions)]
// use crate::errors::option_expect;

use crate::digit;
use crate::ExpType;
Expand Down Expand Up @@ -106,6 +106,13 @@ macro_rules! mod_impl {
self.bits.trailing_ones()
}

#[doc = doc::cast_unsigned!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn cast_unsigned(self) -> $BUint<N> {
self.to_bits()
}

#[doc = doc::rotate_left!(I 256, "i")]
#[must_use = doc::must_use_op!()]
#[inline]
Expand Down Expand Up @@ -150,7 +157,7 @@ macro_rules! mod_impl {
#[inline]
pub const fn pow(self, exp: ExpType) -> Self {
#[cfg(debug_assertions)]
return option_expect!(self.checked_pow(exp), errors::err_msg!("attempt to calculate power with overflow"));
return self.strict_pow(exp);

#[cfg(not(debug_assertions))]
self.wrapping_pow(exp)
Expand All @@ -177,7 +184,7 @@ macro_rules! mod_impl {
#[inline]
pub const fn abs(self) -> Self {
#[cfg(debug_assertions)]
return option_expect!(self.checked_abs(), errors::err_msg!("attempt to negate with overflow"));
return self.strict_abs();

#[cfg(not(debug_assertions))]
match self.checked_abs() {
Expand Down Expand Up @@ -230,6 +237,20 @@ macro_rules! mod_impl {
!self.is_negative() &&self.bits.is_power_of_two()
}

#[doc = doc::midpoint!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn midpoint(self, rhs: Self) -> Self {
let m = Self::from_bits(self.to_bits().midpoint(rhs.to_bits()));
if self.is_negative() == rhs.is_negative() {
// signs agree. in the positive case, we can just compute as if they were unsigned. in the negative case, we compute as if unsigned, and the result is 2^(type bits) too large, but this is 0 (modulo 2^(type bits)) so does not affect the bits
m
} else {
// result is 2^(type bits - 1) too large, so subtract 2^(type bits - 1) by applying xor
m.bitxor(Self::MIN)
}
}

ilog!(ilog, base: Self);
ilog!(ilog2);
ilog!(ilog10);
Expand Down Expand Up @@ -427,6 +448,9 @@ macro_rules! mod_impl {
test_bignum! {
function: <itest>::is_negative(a: itest)
}
test_bignum! {
function: <itest>::cast_unsigned(a: itest)
}

#[test]
fn bit() {
Expand Down Expand Up @@ -490,6 +514,7 @@ macro_rules! mod_impl {

crate::macro_impl!(mod_impl);

mod bigint_helpers;
pub mod cast;
mod checked;
mod cmp;
Expand All @@ -504,5 +529,6 @@ mod ops;
mod overflowing;
mod radix;
mod saturating;
mod strict;
mod unchecked;
mod wrapping;
63 changes: 63 additions & 0 deletions src/bint/strict.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
macro_rules! strict {
($BUint: ident, $BInt: ident, $Digit: ident) => {
#[doc = doc::strict::impl_desc!()]
impl<const N: usize> $BInt<N> {
crate::int::strict::impls!(I);

#[doc = doc::strict::strict_abs!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn strict_abs(self) -> Self {
crate::errors::option_expect!(
self.checked_abs(),
crate::errors::err_msg!("attempt to negate with overflow")
)
}

#[doc = doc::strict::strict_add_unsigned!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn strict_add_unsigned(self, rhs: $BUint<N>) -> Self {
crate::errors::option_expect!(
self.checked_add_unsigned(rhs),
crate::errors::err_msg!("attempt to add with overflow")
)
}

#[doc = doc::strict::strict_sub_unsigned!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn strict_sub_unsigned(self, rhs: $BUint<N>) -> Self {
crate::errors::option_expect!(
self.checked_sub_unsigned(rhs),
crate::errors::err_msg!("attempt to subtract with overflow")
)
}
}

#[cfg(test)]
paste::paste! {
mod [<$Digit _digit_tests>] {
use crate::test::types::big_types::$Digit::*;
crate::int::strict::tests!(itest);

test_bignum! {
function: <itest>::strict_abs(a: itest),
skip: a.checked_abs().is_none()
}
test_bignum! {
function: <itest>::strict_add_unsigned(a: itest, b: utest),
skip: a.checked_add_unsigned(b).is_none()
}
test_bignum! {
function: <itest>::strict_sub_unsigned(a: itest, b: utest),
skip: a.checked_sub_unsigned(b).is_none()
}
}
}
};
}

use crate::doc;

crate::macro_impl!(strict);
45 changes: 4 additions & 41 deletions src/buint/bigint_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,9 @@ use crate::doc;

macro_rules! bigint_helpers {
($BUint: ident, $BInt: ident, $Digit: ident) => {
#[doc = doc::bigint_helpers::impl_desc!()]
impl<const N: usize> $BUint<N> {
#[doc = doc::bigint_helpers::carrying_add!(U)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
let (s1, o1) = self.overflowing_add(rhs);
if carry {
let (s2, o2) = s1.overflowing_add(Self::ONE);
(s2, o1 || o2)
} else {
(s1, o1)
}
}

#[doc = doc::bigint_helpers::borrowing_sub!(U)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
let (s1, o1) = self.overflowing_sub(rhs);
if borrow {
let (s2, o2) = s1.overflowing_sub(Self::ONE);
(s2, o1 || o2)
} else {
(s1, o1)
}
}
crate::int::bigint_helpers::impls!(U);

#[doc = doc::bigint_helpers::widening_mul!(U)]
#[must_use = doc::must_use_op!()]
Expand Down Expand Up @@ -84,26 +61,12 @@ macro_rules! bigint_helpers {
#[cfg(test)]
paste::paste! {
mod [<$Digit _digit_tests>] {
use crate::test::{test_bignum, types::*};
// use crate::test::{test_bignum, types::*};
use crate::test::types::big_types::$Digit::*;

type U64 = crate::$BUint::<{64 / $Digit::BITS as usize}>;

test_bignum! {
function: <utest>::carrying_add(a: utest, rhs: utest, carry: bool),
cases: [
(utest::MAX, 1u8, true),
(utest::MAX, 1u8, false)
]
}

test_bignum! {
function: <utest>::borrowing_sub(a: utest, rhs: utest, carry: bool),
cases: [
(0u8, 1u8, false),
(0u8, 1u8, true)
]
}
crate::int::bigint_helpers::tests!(utest);

test_bignum! {
function: <u64>::widening_mul(a: u64, b: u64),
Expand Down
27 changes: 21 additions & 6 deletions src/buint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ macro_rules! mod_impl {
ones
}

#[doc = doc::cast_signed!(U)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn cast_signed(self) -> $BInt<N> {
$BInt::<N>::from_bits(self)
}

#[inline]
const unsafe fn rotate_digits_left(self, n: usize) -> Self {
let mut out = Self::ZERO;
Expand Down Expand Up @@ -238,10 +245,8 @@ macro_rules! mod_impl {
#[inline]
pub const fn pow(self, exp: ExpType) -> Self {
#[cfg(debug_assertions)]
return option_expect!(
self.checked_pow(exp),
errors::err_msg!("attempt to calculate power with overflow")
);
return self.strict_pow(exp);

#[cfg(not(debug_assertions))]
self.wrapping_pow(exp)
}
Expand Down Expand Up @@ -298,6 +303,13 @@ macro_rules! mod_impl {
self.wrapping_next_power_of_two()
}

#[doc = doc::midpoint!(U)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn midpoint(self, rhs: Self) -> Self {
(self.bitxor(rhs).shr(1)).add(self.bitand(rhs))
}

#[doc = doc::ilog2!(U)]
#[must_use = doc::must_use_op!()]
#[inline]
Expand Down Expand Up @@ -637,10 +649,12 @@ macro_rules! mod_impl {
function: <utest>::next_power_of_two(a: utest),
skip: debug_skip!(a.checked_next_power_of_two().is_none())
}

test_bignum! {
function: <utest>::is_power_of_two(a: utest)
}
test_bignum! {
function: <utest>::cast_signed(a: utest)
}

#[test]
fn digits() {
Expand Down Expand Up @@ -709,7 +723,7 @@ macro_rules! mod_impl {
};
}

crate::main_impl!(mod_impl);
crate::macro_impl!(mod_impl);

pub mod float_as;
mod bigint_helpers;
Expand All @@ -728,5 +742,6 @@ mod ops;
mod overflowing;
mod radix;
mod saturating;
mod strict;
mod unchecked;
mod wrapping;
36 changes: 36 additions & 0 deletions src/buint/strict.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
macro_rules! strict {
($BUint: ident, $BInt: ident, $Digit: ident) => {
#[doc = doc::strict::impl_desc!()]
impl<const N: usize> $BUint<N> {
crate::int::strict::impls!(U);

#[doc = doc::strict::strict_add_signed!(U)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn strict_add_signed(self, rhs: $BInt<N>) -> Self {
crate::errors::option_expect!(
self.checked_add_signed(rhs),
crate::errors::err_msg!("attempt to add with overflow")
)
}
}

#[cfg(test)]
paste::paste! {
mod [<$Digit _digit_tests>] {
use crate::test::types::big_types::$Digit::*;

crate::int::strict::tests!(utest);

test_bignum! {
function: <utest>::strict_add_signed(a: utest, b: itest),
skip: a.checked_add_signed(b).is_none()
}
}
}
};
}

use crate::doc;

crate::macro_impl!(strict);
10 changes: 9 additions & 1 deletion src/buint/unchecked.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
macro_rules! unchecked {
($BUint: ident, $BInt: ident, $Digit: ident) => {
crate::int::unchecked::impls!($BUint, I);
crate::int::unchecked::impls!($BUint, U);

#[cfg(test)]
paste::paste! {
mod [<$Digit _digit_tests>] {
use crate::test::types::big_types::$Digit::*;
crate::int::unchecked::tests!(utest);
}
}
};
}

Expand Down
8 changes: 8 additions & 0 deletions src/doc/bigint_helpers.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
use crate::doc;

macro_rules! impl_desc {
() => {
"Bigint helper methods: common functions used to implement big integer arithmetic."
};
}

pub(crate) use impl_desc;

doc::link_doc_comment!(carrying_add, borrowing_sub, widening_mul, carrying_mul);
Loading

0 comments on commit 6d7c7a7

Please sign in to comment.