From 5f2826b2e29077dc87d54bf5e7771624053a968f Mon Sep 17 00:00:00 2001 From: Isaac Holt Date: Tue, 31 Dec 2024 16:24:29 +0000 Subject: [PATCH] fix float add algorithm, tidy up a lot of code --- Cargo.toml | 2 +- TODO.txt | 21 +++- bench/benches/float.rs | 49 ++++++-- scripts/run_all_tests.sh | 2 +- src/bint/cast.rs | 147 ++++++++++------------ src/bint/checked.rs | 2 +- src/bint/cmp.rs | 56 +++------ src/bint/convert.rs | 39 +++--- src/bint/numtraits.rs | 176 +++++++++++++------------- src/bint/ops.rs | 94 ++++++-------- src/buint/cast.rs | 215 +++++++++++++++---------------- src/buint/checked.rs | 2 +- src/buint/cmp.rs | 57 ++++----- src/buint/convert.rs | 59 ++++----- src/buint/fmt.rs | 32 ----- src/buint/mask.rs | 18 +++ src/buint/mod.rs | 1 + src/buint/numtraits.rs | 9 -- src/buint/ops.rs | 131 +++++++++---------- src/buint/radix.rs | 5 - src/buint/saturating.rs | 51 ++++---- src/cast/float/mod.rs | 36 +++--- src/cast/mod.rs | 6 +- src/float/cmp.rs | 20 ++- src/float/numtraits.rs | 51 +++++++- src/float/ops/add.rs | 85 +++++++++++-- src/float/ops/mod.rs | 72 +++++++---- src/helpers.rs | 11 +- src/int/checked.rs | 8 -- src/int/numtraits.rs | 264 +++++++++++++++++---------------------- src/int/ops.rs | 214 +++++++++++++------------------ src/nightly.rs | 32 ----- src/test/macros.rs | 32 +++++ src/test/types.rs | 62 ++++++--- 34 files changed, 1022 insertions(+), 1039 deletions(-) create mode 100644 src/buint/mask.rs diff --git a/Cargo.toml b/Cargo.toml index 2d1f1b4..dcdc6c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,4 +49,4 @@ opt-level = 3 # maximum optimisation level for faster runtime, but slower compil all-features = true [lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(test_int_bits, values("64", "128"))'] } \ No newline at end of file +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(test_int_bits, values("8", "16", "32", "64", "128"))'] } \ No newline at end of file diff --git a/TODO.txt b/TODO.txt index 4a19359..ae98d6f 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,7 +1,4 @@ Floats: -* Conversions from and to: - * primitive floats - * bnum floats * FromStr trait: REMEMBER: the num_traits crate has a general from_str_radix method for floats, could use if stuck * Display, debug, upper exp, lower exp traits * Transcendental functions: @@ -66,13 +63,16 @@ Floats: * FloatToInt trait * From/TryFrom trait for ints, other floats * Float type aliases from IEEE standard: f16, f32, f64, f80, f128. (Include f32 and f64 as allows const methods which aren't available on the primitives) -* Serde * Rand: * gen_range stuff -* num_traits::{Bounded, Float, FloatConst, FloatCore, AsPrimitive, FromPrimitive, ToPrimitive, ConstZero, ConstOne, One, Zero, FromBytes, ToBytes, Inv, MulAdd, MulAddAssign, Pow, Signed, Euclid, Num} +* num_traits::{Bounded, Float, FloatConst, FloatCore, AsPrimitive, FromPrimitive, ToPrimitive, FromBytes, ToBytes, Inv, MulAdd, MulAddAssign, Pow, Signed, Euclid, Num} * Division algorithm which doesn't need where clause Ints: +* big idea: could only use u8 digits, but for calculations (if this is faster than just using BUintD8 and isn't much slower than using larger digits), use u64s, e.g. when iterating, iterate in batches of 8, use u64::from_ne_bytes/u64::from_le_bytes - this is a transmute so should be very small overhead (this might sacrifice some code readability) +* unsigned_signed_diff methods +* isqrt methods +* unbounded shr, shl methods * Use new Rust const capabilities to write more idiomatic code (e.g. we don't need the option_expect! macro anymore). Note though that maybe we should wait a bit to keep the MSRV not too recent * Faster mulitplication algorithm for larger integers * Faster division algorithms for larger integers @@ -83,4 +83,13 @@ Other stuff: * Think about removing BTryFrom and just implementing TryFrom (no From for now), then can use CastFrom/As trait for Result-less conversions * Replace bitors, bitands, shifts, masks etc. with more efficient implementations (e.g. using set_bit, flip_bit, one-less-than-power-of-two methods, methods for efficiently generating masks/getting certain range of bits of integer) * Consider putting floats and signed integers behind optional features (which are enabled by default) -* Add 16 bit and 32 bit width types to the test widths, so test u16, u32, f16, f32 as well (just make the digit sizes that are too wide not do anything for those tests) \ No newline at end of file +* Add 16 bit and 32 bit width types to the test widths, so test u16, u32, f16, f32 as well (just make the digit sizes that are too wide not do anything for those tests) +* Consider removing implementation of AsPrimitive for primitive ints +* Consider removing Add and Div impls +* Rewrite README +* consider removing parse_str_radix method, not really necessary now Option::expect and unwrap are const +* consider raising issue in num_traits crate about PrimInt dependency on NumCast +* consider using Rust's ParseIntError and TryFromIntError instead of own types, would have to do this by deliberating doing a calculation resulting in error (e.g. u8::from_str_radix(" ", 10)). this might be not be very good practice though, and would have to do for ParseFloatError eventually as well, which could be trickier to do this way +* consider splitting off allow-based methods into gated "alloc" feature +* work out and add assertions about sizes of e.g. int widths (should be <= u32::MAX), and float mantissa and exponent widths, etc. +* include list of difference with primitives in README, e.g. overflow_checks not detected yet, serde implementation different, memory layout different (always little endian - although maybe this could be changed? probably not a good idea though) \ No newline at end of file diff --git a/bench/benches/float.rs b/bench/benches/float.rs index 8d2bd2e..7e7cd4c 100644 --- a/bench/benches/float.rs +++ b/bench/benches/float.rs @@ -7,17 +7,24 @@ const SAMPLE_SIZE: usize = 10000; use bnum::Float; -type F64 = Float<8, 52>; +type F256 = Float<32, 236>; +type F128 = Float<32, 236>; +type F64 = Float<8, 48>; type F32 = Float<4, 23>; +type U256 = bnum::BUintD8<32>; +type U64 = bnum::BUintD8<8>; + fn bench_fibs(c: &mut Criterion) { let mut group = c.benchmark_group("round"); let mut rng = rand::rngs::StdRng::seed_from_u64(0); let inputs = (0..SAMPLE_SIZE) - .map(|_| rng.gen::()) - .map(|a| a.to_bits()) - .map(|a| (f64::from_bits(a), F64::from_bits(a.into()))); + .map(|_| rng.gen::<(u64, u64)>()) + .map(|(a, b)| ( + (f64::from_bits(a >> 1), f64::from_bits(b >> 1)), + (F64::from_bits((a >> 1).into()), F64::from_bits((b >> 1).into())) + )); let (prim_inputs, big_inputs) = unzip::unzip2(inputs); // group.bench_with_input(BenchmarkId::new("Recursive", "new"), &big_inputs, |b, inputs| b.iter(|| { @@ -26,17 +33,41 @@ fn bench_fibs(c: &mut Criterion) { // } // })); group.bench_with_input(BenchmarkId::new("Iterative", "old"), &big_inputs, |b, inputs| b.iter(|| { - inputs.iter().cloned().for_each(|a| { - let _ = black_box(a).trunc(); + inputs.iter().cloned().for_each(|(a, b)| { + let _ = black_box(a) + black_box(b); }) })); group.bench_with_input(BenchmarkId::new("Iterative", "prim"), &prim_inputs, |b, inputs| b.iter(|| { - inputs.iter().cloned().for_each(|a| { - let _ = black_box(a).trunc(); + inputs.iter().cloned().for_each(|(a, b)| { + let _ = black_box(a) + black_box(b); + }) + })); + group.finish(); +} + + +fn bench_add(c: &mut Criterion) { + let mut group = c.benchmark_group("round"); + let mut rng = rand::rngs::StdRng::seed_from_u64(0); + let big_inputs = (0..SAMPLE_SIZE) + .map(|_| rng.gen::<(U64, U64)>()) + .map(|(a, b)| ( + (F64::from_bits((a >> 1)), F64::from_bits((b >> 1))) + )); + let big_inputs: Vec<_> = big_inputs.collect(); + + // group.bench_with_input(BenchmarkId::new("Recursive", "new"), &big_inputs, |b, inputs| b.iter(|| { + // for a in inputs.iter().cloned() { + // let _ = black_box(a).floor(); + // } + // })); + group.bench_with_input(BenchmarkId::new("Iterative", "old"), &big_inputs, |b, inputs| b.iter(|| { + inputs.iter().cloned().for_each(|(a, b)| { + let _ = black_box(black_box(a) + black_box(b)); }) })); group.finish(); } -criterion_group!(benches, bench_fibs); +criterion_group!(benches, bench_add); criterion_main!(benches); \ No newline at end of file diff --git a/scripts/run_all_tests.sh b/scripts/run_all_tests.sh index e9c0a5d..7e8b1b2 100644 --- a/scripts/run_all_tests.sh +++ b/scripts/run_all_tests.sh @@ -20,7 +20,7 @@ run_test () { for flags in "" "--all-features" do echo "\n${CYAN_COLOR}info${RESET_FORMAT}: running tests with flags '$flags'..." - for bits in 64 128 + for bits in 8 16 32 64 128 do run_test $bits $flags done diff --git a/src/bint/cast.rs b/src/bint/cast.rs index 12d44b2..0a7ca25 100644 --- a/src/bint/cast.rs +++ b/src/bint/cast.rs @@ -1,22 +1,20 @@ macro_rules! bint_as { ($BInt: ident, $Digit: ident; $($int: ty), *) => { $( - impl_const! { - impl const CastFrom<$BInt> for $int { - #[inline] - fn cast_from(from: $BInt) -> Self { - if from.is_negative() { - let digits = from.bits.digits; - let mut out = !0; - let mut i = 0; - while i << digit::$Digit::BIT_SHIFT < <$int>::BITS as usize && i < N { - out &= !((!digits[i]) as $int << (i << digit::$Digit::BIT_SHIFT)); - i += 1; - } - out - } else { - <$int>::cast_from(from.bits) + impl CastFrom<$BInt> for $int { + #[inline] + fn cast_from(from: $BInt) -> Self { + if from.is_negative() { + let digits = from.bits.digits; + let mut out = !0; + let mut i = 0; + while i << digit::$Digit::BIT_SHIFT < <$int>::BITS as usize && i < N { + out &= !((!digits[i]) as $int << (i << digit::$Digit::BIT_SHIFT)); + i += 1; } + out + } else { + <$int>::cast_from(from.bits) } } } @@ -26,14 +24,14 @@ macro_rules! bint_as { macro_rules! as_bint { ($BInt: ident, $BUint: ident; $($ty: ty), *) => { - $(impl_const! { - impl const CastFrom<$ty> for $BInt { + $( + impl CastFrom<$ty> for $BInt { #[inline] fn cast_from(from: $ty) -> Self { Self::from_bits($BUint::cast_from(from)) } } - })* + )* } } @@ -65,7 +63,6 @@ pub(crate) use bint_cast_from_float; use crate::cast::CastFrom; use crate::digit; -use crate::nightly::impl_const; macro_rules! cast { ($BUint: ident, $BInt: ident, $Digit: ident) => { @@ -97,21 +94,17 @@ macro_rules! cast { as_bint!($BInt, $BUint; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, bool, char); - impl_const! { - impl const CastFrom<$BUint> for $BInt { - #[inline] - fn cast_from(from: $BUint) -> Self { - Self::from_bits($BUint::cast_from(from)) - } + impl CastFrom<$BUint> for $BInt { + #[inline] + fn cast_from(from: $BUint) -> Self { + Self::from_bits($BUint::cast_from(from)) } } - impl_const! { - impl const CastFrom<$BInt> for $BInt { - #[inline] - fn cast_from(from: $BInt) -> Self { - Self::from_bits($BUint::cast_from(from)) - } + impl CastFrom<$BInt> for $BInt { + #[inline] + fn cast_from(from: $BInt) -> Self { + Self::from_bits($BUint::cast_from(from)) } } @@ -138,62 +131,58 @@ crate::macro_impl!(cast); macro_rules! bint_as_different_digit_bigint { ($BUint: ident, $BInt: ident, $Digit: ident; $(($OtherBInt: ident, $OtherDigit: ident)), *) => { $( - crate::nightly::const_impl! { - impl const crate::cast::CastFrom<$OtherBInt> for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: $OtherBInt) -> Self { - if !from.is_negative() || M * $OtherDigit::BITS as usize >= N * $Digit::BITS as usize { // $OtherBInt::BITS <= $Int::BITS - Self::cast_from(from.to_bits()) + impl crate::cast::CastFrom<$OtherBInt> for $BUint { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: $OtherBInt) -> Self { + if !from.is_negative() || M * $OtherDigit::BITS as usize >= N * $Digit::BITS as usize { // $OtherBInt::BITS <= $Int::BITS + Self::cast_from(from.to_bits()) + } else { + let mut out = Self::MAX; + if $Digit::BITS < $OtherDigit::BITS { + const DIVIDE_COUNT: usize = ($OtherDigit::BITS / $Digit::BITS) as usize; + let stop_index: usize = if <$OtherBInt>::BITS > <$BUint>::BITS { + N + } else { + M * DIVIDE_COUNT + }; + let mut i = 0; + while i < stop_index { + let wider_digit = from.bits.digits[i / DIVIDE_COUNT]; + let mini_shift = i % DIVIDE_COUNT; + let digit = (wider_digit >> (mini_shift << digit::$Digit::BIT_SHIFT)) as $Digit; + out.digits[i] = digit; + i += 1; + } } else { - let mut out = Self::MAX; - if $Digit::BITS < $OtherDigit::BITS { - const DIVIDE_COUNT: usize = ($OtherDigit::BITS / $Digit::BITS) as usize; - let stop_index: usize = if <$OtherBInt>::BITS > <$BUint>::BITS { - N - } else { - M * DIVIDE_COUNT - }; - let mut i = 0; - while i < stop_index { - let wider_digit = from.bits.digits[i / DIVIDE_COUNT]; - let mini_shift = i % DIVIDE_COUNT; - let digit = (wider_digit >> (mini_shift << digit::$Digit::BIT_SHIFT)) as $Digit; - out.digits[i] = digit; - i += 1; - } + const DIVIDE_COUNT: usize = ($Digit::BITS / $OtherDigit::BITS) as usize; + let stop_index: usize = if <$OtherBInt>::BITS > <$BUint>::BITS { + N * DIVIDE_COUNT } else { - const DIVIDE_COUNT: usize = ($Digit::BITS / $OtherDigit::BITS) as usize; - let stop_index: usize = if <$OtherBInt>::BITS > <$BUint>::BITS { - N * DIVIDE_COUNT - } else { - M - }; - let mut current_digit: $Digit = $Digit::MAX; - let mut i = 0; - while i < stop_index { - let mini_shift = i % DIVIDE_COUNT; - current_digit &= !((!from.bits.digits[i] as $Digit) << (mini_shift << digit::$OtherDigit::BIT_SHIFT)); - if mini_shift == DIVIDE_COUNT - 1 || i == stop_index - 1 { - out.digits[i / DIVIDE_COUNT] = current_digit; - current_digit = $Digit::MAX; - } - i += 1; + M + }; + let mut current_digit: $Digit = $Digit::MAX; + let mut i = 0; + while i < stop_index { + let mini_shift = i % DIVIDE_COUNT; + current_digit &= !((!from.bits.digits[i] as $Digit) << (mini_shift << digit::$OtherDigit::BIT_SHIFT)); + if mini_shift == DIVIDE_COUNT - 1 || i == stop_index - 1 { + out.digits[i / DIVIDE_COUNT] = current_digit; + current_digit = $Digit::MAX; } + i += 1; } - out } + out } } } - - crate::nightly::const_impl! { - impl const crate::cast::CastFrom<$OtherBInt> for $BInt { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: $OtherBInt) -> Self { - Self::from_bits($BUint::::cast_from(from)) - } + + impl crate::cast::CastFrom<$OtherBInt> for $BInt { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: $OtherBInt) -> Self { + Self::from_bits($BUint::::cast_from(from)) } } )* diff --git a/src/bint/checked.rs b/src/bint/checked.rs index 934182c..f30a49d 100644 --- a/src/bint/checked.rs +++ b/src/bint/checked.rs @@ -14,7 +14,7 @@ macro_rules! checked_ilog { } use crate::doc; -use crate::int::checked::tuple_to_option; +use crate::helpers::tuple_to_option; use crate::ExpType; macro_rules! checked { diff --git a/src/bint/cmp.rs b/src/bint/cmp.rs index baa5cd2..467923e 100644 --- a/src/bint/cmp.rs +++ b/src/bint/cmp.rs @@ -1,49 +1,33 @@ -use crate::nightly::impl_const; use core::cmp::{Ord, Ordering, PartialOrd}; macro_rules! cmp { ($BUint: ident, $BInt: ident, $Digit: ident) => { - // impl_const! { - // impl const PartialEq for $BInt { - // #[inline] - // fn eq(&self, other: &Self) -> bool { - // Self::eq(self, other) - // } - // } - // } - - // impl Eq for $BInt {} - - impl_const! { - impl const PartialOrd for $BInt { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } + impl PartialOrd for $BInt { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) } } - impl_const! { - impl const Ord for $BInt { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - Self::cmp(self, other) - } + impl Ord for $BInt { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + Self::cmp(self, other) + } - #[inline] - fn max(self, other: Self) -> Self { - Self::max(self, other) - } + #[inline] + fn max(self, other: Self) -> Self { + Self::max(self, other) + } - #[inline] - fn min(self, other: Self) -> Self { - Self::min(self, other) - } + #[inline] + fn min(self, other: Self) -> Self { + Self::min(self, other) + } - #[inline] - fn clamp(self, min: Self, max: Self) -> Self { - Self::clamp(self, min, max) - } + #[inline] + fn clamp(self, min: Self, max: Self) -> Self { + Self::clamp(self, min, max) } } diff --git a/src/bint/convert.rs b/src/bint/convert.rs index 7062d22..c9d93e8 100644 --- a/src/bint/convert.rs +++ b/src/bint/convert.rs @@ -1,7 +1,7 @@ macro_rules! from_int { ($BInt: ident, $Digit: ident; $($int: tt),*) => { - $(impl_const! { - impl const From<$int> for $BInt { + $( + impl From<$int> for $BInt { #[inline] fn from(int: $int) -> Self { let mut out = if int.is_negative() { @@ -18,28 +18,28 @@ macro_rules! from_int { out } } - })* + )* } } macro_rules! from_uint { ($BInt: ident, $BUint: ident; $($from: tt), *) => { - $(impl_const! { - impl const From<$from> for $BInt { + $( + impl From<$from> for $BInt { #[inline] fn from(int: $from) -> Self { let out = Self::from_bits($BUint::from(int)); out } } - })* + )* } } macro_rules! int_try_from_bint { { $BInt: ident, $Digit: ident; $($int: ty), * } => { - $(crate::nightly::impl_const! { - impl const TryFrom<$BInt> for $int { + $( + impl TryFrom<$BInt> for $int { type Error = TryFromIntError; fn try_from(int: $BInt) -> Result<$int, Self::Error> { @@ -94,14 +94,14 @@ macro_rules! int_try_from_bint { Ok(out) } } - })* + )* }; } macro_rules! uint_try_from_bint { ($BInt: ident; $($uint: ty), *) => { - $(crate::nightly::impl_const! { - impl const TryFrom<$BInt> for $uint { + $( + impl TryFrom<$BInt> for $uint { type Error = TryFromIntError; #[inline] @@ -113,14 +113,13 @@ macro_rules! uint_try_from_bint { } } } - })* + )* }; } use crate::cast::CastFrom; use crate::digit; use crate::errors::{ParseIntError, TryFromIntError}; -use crate::nightly::impl_const; use core::str::FromStr; macro_rules! convert { @@ -138,12 +137,10 @@ macro_rules! convert { from_uint!($BInt, $BUint; u8, u16, u32, u64, u128, usize); - impl_const! { - impl const From for $BInt { - #[inline] - fn from(small: bool) -> Self { - Self::cast_from(small) - } + impl From for $BInt { + #[inline] + fn from(small: bool) -> Self { + Self::cast_from(small) } } @@ -175,7 +172,7 @@ macro_rules! convert { test::test_btryfrom!(itest; UTESTD8, UTESTD16, UTESTD32, UTESTD64, TestUint1, TestUint2, TestUint3, TestUint4, TestUint5, TestUint6, TestUint7, TestUint8, TestUint9, TestUint10, ITESTD8, ITESTD16, ITESTD32, ITESTD64, TestInt1, TestInt2, TestInt3, TestInt4, TestInt5, TestInt6, TestInt7, TestInt8, TestInt9, TestInt10); - #[cfg(not(test_int_bits = "64"))] + #[cfg(test_int_bits = "128")] test::test_from! { function: ::try_from, from_types: (i8, i16, i32, i64, i128, u8, u16, u32, u64, bool, usize, isize) @@ -189,7 +186,7 @@ macro_rules! convert { test::test_into! { function: ::try_into, - into_types: (u8, u16, u32, u64, usize, u128, i8, i16, i32, i64, i128, isize) + into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize) } } } diff --git a/src/bint/numtraits.rs b/src/bint/numtraits.rs index 4fe3733..ceed64d 100644 --- a/src/bint/numtraits.rs +++ b/src/bint/numtraits.rs @@ -190,86 +190,82 @@ macro_rules! numtraits { from_float!($BUint; from_f64, f64); } - //crate::nightly::impl_const! { - impl Integer for $BInt { - #[inline] - fn div_floor(&self, other: &Self) -> Self { - *self / *other - } + impl Integer for $BInt { + #[inline] + fn div_floor(&self, other: &Self) -> Self { + *self / *other + } - #[inline] - fn mod_floor(&self, other: &Self) -> Self { - *self % *other - } + #[inline] + fn mod_floor(&self, other: &Self) -> Self { + *self % *other + } - #[inline] - fn gcd(&self, other: &Self) -> Self { - let gcd = self.unsigned_abs().gcd(&other.unsigned_abs()); - let out = Self::from_bits(gcd); - out.abs() - } + #[inline] + fn gcd(&self, other: &Self) -> Self { + let gcd = self.unsigned_abs().gcd(&other.unsigned_abs()); + let out = Self::from_bits(gcd); + out.abs() + } - #[inline] - fn lcm(&self, other: &Self) -> Self { - if self.is_zero() || other.is_zero() { - Self::ZERO - } else { - self.div_floor(&self.gcd(other)) * *other - } + #[inline] + fn lcm(&self, other: &Self) -> Self { + if self.is_zero() || other.is_zero() { + Self::ZERO + } else { + self.div_floor(&self.gcd(other)) * *other } + } - #[inline] - fn divides(&self, other: &Self) -> bool { - self.is_multiple_of(other) - } + #[inline] + fn divides(&self, other: &Self) -> bool { + self.is_multiple_of(other) + } - #[inline] - fn is_multiple_of(&self, other: &Self) -> bool { - self.mod_floor(other).is_zero() - } + #[inline] + fn is_multiple_of(&self, other: &Self) -> bool { + self.mod_floor(other).is_zero() + } - #[inline] - fn is_even(&self) -> bool { - self.bits.is_even() - } + #[inline] + fn is_even(&self) -> bool { + self.bits.is_even() + } - #[inline] - fn is_odd(&self) -> bool { - self.bits.is_odd() - } + #[inline] + fn is_odd(&self) -> bool { + self.bits.is_odd() + } - #[inline] - fn div_rem(&self, other: &Self) -> (Self, Self) { - (self.div_floor(other), self.mod_floor(other)) - } + #[inline] + fn div_rem(&self, other: &Self) -> (Self, Self) { + (self.div_floor(other), self.mod_floor(other)) } - //} + } - //crate::nightly::impl_const! { - impl PrimInt for $BInt { - crate::int::numtraits::prim_int_methods!(); + impl PrimInt for $BInt { + crate::int::numtraits::prim_int_methods!(); - #[inline] - fn signed_shl(self, n: u32) -> Self { - self << n - } + #[inline] + fn signed_shl(self, n: u32) -> Self { + self << n + } - #[inline] - fn signed_shr(self, n: u32) -> Self { - self >> n - } + #[inline] + fn signed_shr(self, n: u32) -> Self { + self >> n + } - #[inline] - fn unsigned_shl(self, n: u32) -> Self { - self << n - } + #[inline] + fn unsigned_shl(self, n: u32) -> Self { + self << n + } - #[inline] - fn unsigned_shr(self, n: u32) -> Self { - Self::from_bits(self.to_bits() >> n) - } + #[inline] + fn unsigned_shr(self, n: u32) -> Self { + Self::from_bits(self.to_bits() >> n) } - //} + } impl Roots for $BInt { #[inline] @@ -312,7 +308,6 @@ macro_rules! numtraits { } } - //crate::nightly::impl_const! { impl ToPrimitive for $BInt { to_uint! { to_u8 -> u8, @@ -343,40 +338,37 @@ macro_rules! numtraits { Some(self.as_()) } } - //} - //crate::nightly::impl_const! { - impl Signed for $BInt { - #[inline] - fn abs(&self) -> Self { - Self::abs(*self) - } + impl Signed for $BInt { + #[inline] + fn abs(&self) -> Self { + Self::abs(*self) + } - #[inline] - fn abs_sub(&self, other: &Self) -> Self { - if *self <= *other { - Self::ZERO - } else { - *self - *other - } + #[inline] + fn abs_sub(&self, other: &Self) -> Self { + if *self <= *other { + Self::ZERO + } else { + *self - *other } + } - #[inline] - fn signum(&self) -> Self { - Self::signum(*self) - } + #[inline] + fn signum(&self) -> Self { + Self::signum(*self) + } - #[inline] - fn is_positive(&self) -> bool { - Self::is_positive(*self) - } + #[inline] + fn is_positive(&self) -> bool { + Self::is_positive(*self) + } - #[inline] - fn is_negative(&self) -> bool { - self.signed_digit().is_negative() - } + #[inline] + fn is_negative(&self) -> bool { + self.signed_digit().is_negative() } - //} + } #[cfg(test)] paste::paste! { diff --git a/src/bint/ops.rs b/src/bint/ops.rs index 7121db0..d792bf4 100644 --- a/src/bint/ops.rs +++ b/src/bint/ops.rs @@ -6,90 +6,74 @@ use core::ops::{ macro_rules! ops { ($BUint: ident, $BInt: ident, $Digit: ident) => { - crate::nightly::impl_const! { - impl const Neg for $BInt { - type Output = Self; + impl Neg for $BInt { + type Output = Self; - #[inline] - fn neg(self) -> Self { - Self::neg(self) - } + #[inline] + fn neg(self) -> Self { + Self::neg(self) } } - crate::nightly::impl_const! { - impl const Neg for &$BInt { - type Output = $BInt; + impl Neg for &$BInt { + type Output = $BInt; - #[inline] - fn neg(self) -> $BInt { - $BInt::neg(*self) - } + #[inline] + fn neg(self) -> $BInt { + $BInt::neg(*self) } } - crate::nightly::impl_const! { - impl const BitAnd for $BInt { - type Output = Self; + impl BitAnd for $BInt { + type Output = Self; - #[inline] - fn bitand(self, rhs: Self) -> Self { - Self::bitand(self, rhs) - } + #[inline] + fn bitand(self, rhs: Self) -> Self { + Self::bitand(self, rhs) } } - crate::nightly::impl_const! { - impl const BitOr for $BInt { - type Output = Self; + impl BitOr for $BInt { + type Output = Self; - #[inline] - fn bitor(self, rhs: Self) -> Self { - Self::bitor(self, rhs) - } + #[inline] + fn bitor(self, rhs: Self) -> Self { + Self::bitor(self, rhs) } } - crate::nightly::impl_const! { - impl const BitXor for $BInt { - type Output = Self; + impl BitXor for $BInt { + type Output = Self; - #[inline] - fn bitxor(self, rhs: Self) -> Self { - Self::bitxor(self, rhs) - } + #[inline] + fn bitxor(self, rhs: Self) -> Self { + Self::bitxor(self, rhs) } } - crate::nightly::impl_const! { - impl const Div for $BInt { - type Output = Self; + impl Div for $BInt { + type Output = Self; - #[inline] - fn div(self, rhs: Self) -> Self { - Self::div(self, rhs) - } + #[inline] + fn div(self, rhs: Self) -> Self { + Self::div(self, rhs) } } - crate::nightly::impl_const! { - impl const Not for $BInt { - type Output = Self; + impl Not for $BInt { + type Output = Self; - fn not(self) -> Self { - Self::not(self) - } + fn not(self) -> Self { + Self::not(self) } } - crate::nightly::impl_const! { - impl const Rem for $BInt { - type Output = Self; + impl Rem for $BInt { + type Output = Self; - #[inline] - fn rem(self, rhs: Self) -> Self { - Self::rem(self, rhs) - } + #[inline] + fn rem(self, rhs: Self) -> Self { + Self::rem(self, rhs) } } diff --git a/src/buint/cast.rs b/src/buint/cast.rs index 9af8348..8c1b9e3 100644 --- a/src/buint/cast.rs +++ b/src/buint/cast.rs @@ -22,8 +22,8 @@ decode_float!(decode_f64, f64, u64); macro_rules! buint_as_int { ($BUint: ident, $Digit: ident; $($int: ty), *) => { - $(impl_const! { - impl const CastFrom<$BUint> for $int { + $( + impl CastFrom<$BUint> for $int { #[must_use = doc::must_use_op!()] #[inline] fn cast_from(from: $BUint) -> Self { @@ -36,7 +36,7 @@ macro_rules! buint_as_int { out } } - })* + )* }; } @@ -54,8 +54,8 @@ macro_rules! buint_as_float { macro_rules! as_buint { ($BUint: ident, $Digit: ident; $($ty: ty), *) => { - $(crate::nightly::const_impl! { - impl const CastFrom<$ty> for $BUint { + $( + impl CastFrom<$ty> for $BUint { #[must_use = doc::must_use_op!()] #[inline] fn cast_from(mut from: $ty) -> Self { @@ -79,20 +79,18 @@ macro_rules! as_buint { out } } - })* + )* }; } use crate::cast::CastFrom; use crate::doc; -use crate::nightly::impl_const; -// use core::mem::MaybeUninit; - use crate::ExpType; use crate::cast::float::{FloatMantissa, CastUintFromFloatHelper, CastFloatFromUintHelper}; macro_rules! cast { ($BUint: ident, $BInt: ident, $Digit: ident) => { + #[cfg(feature = "float")] impl FloatMantissa for $BUint { const ZERO: Self = Self::ZERO; const ONE: Self = Self::ONE; @@ -127,30 +125,27 @@ macro_rules! cast { } impl $BUint { - crate::nightly::const_fn! { - #[inline] - const fn cast_up(self, digit: $Digit) -> $BUint { - let mut digits = [digit; M]; - let mut i = M - N; - while i < M { - let index = i - (M - N); - digits[index] = self.digits[index]; - i += 1; - } - $BUint::from_digits(digits) + #[inline] + const fn cast_up(self, digit: $Digit) -> $BUint { + let mut digits = [digit; M]; + let mut i = M - N; + while i < M { + let index = i - (M - N); + digits[index] = self.digits[index]; + i += 1; } + $BUint::from_digits(digits) } - crate::nightly::const_fn! { - #[inline] - const fn cast_down(self) -> $BUint { - let mut out = $BUint::ZERO; - let mut i = 0; - while i < M { - out.digits[i] = self.digits[i]; - i += 1; - } - out + + #[inline] + const fn cast_down(self) -> $BUint { + let mut out = $BUint::ZERO; + let mut i = 0; + while i < M { + out.digits[i] = self.digits[i]; + i += 1; } + out } } @@ -161,59 +156,51 @@ macro_rules! cast { as_buint!($BUint, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); - impl_const! { - impl const CastFrom for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: bool) -> Self { - if from { - Self::ONE - } else { - Self::ZERO - } + impl CastFrom for $BUint { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: bool) -> Self { + if from { + Self::ONE + } else { + Self::ZERO } } } - impl_const! { - impl const CastFrom for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: char) -> Self { - Self::cast_from(from as u32) - } + impl CastFrom for $BUint { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: char) -> Self { + Self::cast_from(from as u32) } } - impl_const! { - impl const CastFrom<$BUint> for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: $BUint) -> Self { - if M < N { - from.cast_up(0) - } else { - from.cast_down() - } + impl CastFrom<$BUint> for $BUint { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: $BUint) -> Self { + if M < N { + from.cast_up(0) + } else { + from.cast_down() } } } - impl_const! { - impl const CastFrom<$BInt> for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: $BInt) -> Self { - if M < N { - let padding_digit = if from.is_negative() { - $Digit::MAX - } else { - 0 - }; - from.to_bits().cast_up(padding_digit) + impl CastFrom<$BInt> for $BUint { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: $BInt) -> Self { + if M < N { + let padding_digit = if from.is_negative() { + $Digit::MAX } else { - from.to_bits().cast_down() - } + 0 + }; + from.to_bits().cast_up(padding_digit) + } else { + from.to_bits().cast_down() } } } @@ -249,58 +236,54 @@ crate::macro_impl!(cast); macro_rules! buint_as_different_digit_bigint { ($BUint: ident, $BInt: ident, $Digit: ident; $(($OtherBUint: ident, $OtherDigit: ident)), *) => { $( - crate::nightly::const_impl! { - impl const crate::cast::CastFrom<$OtherBUint> for $BUint { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: $OtherBUint) -> Self { - let mut out = Self::ZERO; - if $Digit::BITS < $OtherDigit::BITS { - const DIVIDE_COUNT: usize = ($OtherDigit::BITS / $Digit::BITS) as usize; - let stop_index: usize = if <$OtherBUint>::BITS > <$BUint>::BITS { - N - } else { - M * DIVIDE_COUNT - }; - let mut i = 0; - while i < stop_index { - let wider_digit = from.digits[i / DIVIDE_COUNT]; - let mini_shift = i % DIVIDE_COUNT; - let digit = (wider_digit >> (mini_shift << digit::$Digit::BIT_SHIFT)) as $Digit; - out.digits[i] = digit; - i += 1; - } + impl crate::cast::CastFrom<$OtherBUint> for $BUint { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: $OtherBUint) -> Self { + let mut out = Self::ZERO; + if $Digit::BITS < $OtherDigit::BITS { + const DIVIDE_COUNT: usize = ($OtherDigit::BITS / $Digit::BITS) as usize; + let stop_index: usize = if <$OtherBUint>::BITS > <$BUint>::BITS { + N } else { - const DIVIDE_COUNT: usize = ($Digit::BITS / $OtherDigit::BITS) as usize; - let stop_index: usize = if <$OtherBUint>::BITS > <$BUint>::BITS { - N * DIVIDE_COUNT - } else { - M - }; - let mut current_digit: $Digit = 0; - let mut i = 0; - while i < stop_index { - let mini_shift = i % DIVIDE_COUNT; - current_digit |= (from.digits[i] as $Digit) << (mini_shift << digit::$OtherDigit::BIT_SHIFT); - if mini_shift == DIVIDE_COUNT - 1 || i == stop_index - 1 { - out.digits[i / DIVIDE_COUNT] = current_digit; - current_digit = 0; - } - i += 1; + M * DIVIDE_COUNT + }; + let mut i = 0; + while i < stop_index { + let wider_digit = from.digits[i / DIVIDE_COUNT]; + let mini_shift = i % DIVIDE_COUNT; + let digit = (wider_digit >> (mini_shift << digit::$Digit::BIT_SHIFT)) as $Digit; + out.digits[i] = digit; + i += 1; + } + } else { + const DIVIDE_COUNT: usize = ($Digit::BITS / $OtherDigit::BITS) as usize; + let stop_index: usize = if <$OtherBUint>::BITS > <$BUint>::BITS { + N * DIVIDE_COUNT + } else { + M + }; + let mut current_digit: $Digit = 0; + let mut i = 0; + while i < stop_index { + let mini_shift = i % DIVIDE_COUNT; + current_digit |= (from.digits[i] as $Digit) << (mini_shift << digit::$OtherDigit::BIT_SHIFT); + if mini_shift == DIVIDE_COUNT - 1 || i == stop_index - 1 { + out.digits[i / DIVIDE_COUNT] = current_digit; + current_digit = 0; } + i += 1; } - out } + out } } - crate::nightly::const_impl! { - impl const crate::cast::CastFrom<$OtherBUint> for $BInt { - #[must_use = doc::must_use_op!()] - #[inline] - fn cast_from(from: $OtherBUint) -> Self { - Self::from_bits($BUint::cast_from(from)) - } + impl crate::cast::CastFrom<$OtherBUint> for $BInt { + #[must_use = doc::must_use_op!()] + #[inline] + fn cast_from(from: $OtherBUint) -> Self { + Self::from_bits($BUint::cast_from(from)) } } )* diff --git a/src/buint/checked.rs b/src/buint/checked.rs index 260dd11..06daca0 100644 --- a/src/buint/checked.rs +++ b/src/buint/checked.rs @@ -1,7 +1,7 @@ use crate::digit; use crate::doc; use crate::errors::div_zero; -use crate::int::checked::tuple_to_option; +use crate::helpers::tuple_to_option; use crate::ExpType; macro_rules! checked { diff --git a/src/buint/cmp.rs b/src/buint/cmp.rs index 3a46916..da21cf4 100644 --- a/src/buint/cmp.rs +++ b/src/buint/cmp.rs @@ -1,51 +1,36 @@ -use crate::nightly::impl_const; use core::cmp::{Ord, Ordering, PartialOrd}; macro_rules! cmp { ($BUint: ident, $BInt: ident, $Digit: ident) => { - // impl_const! { - // impl const PartialEq for $BUint { - // #[inline] - // fn eq(&self, other: &Self) -> bool { - // Self::eq(self, other) - // } - // } - // } - - // impl Eq for $BUint {} - - impl_const! { - impl const PartialOrd for $BUint { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } + impl PartialOrd for $BUint { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) } } - impl_const! { - impl const Ord for $BUint { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - Self::cmp(self, other) - } + impl Ord for $BUint { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + Self::cmp(self, other) + } - #[inline] - fn max(self, other: Self) -> Self { - Self::max(self, other) - } + #[inline] + fn max(self, other: Self) -> Self { + Self::max(self, other) + } - #[inline] - fn min(self, other: Self) -> Self { - Self::min(self, other) - } + #[inline] + fn min(self, other: Self) -> Self { + Self::min(self, other) + } - #[inline] - fn clamp(self, min: Self, max: Self) -> Self { - Self::clamp(self, min, max) - } + #[inline] + fn clamp(self, min: Self, max: Self) -> Self { + Self::clamp(self, min, max) } } + #[cfg(test)] paste::paste! { mod [<$Digit _digit_tests>] { diff --git a/src/buint/convert.rs b/src/buint/convert.rs index b934315..7f5f4c7 100644 --- a/src/buint/convert.rs +++ b/src/buint/convert.rs @@ -1,7 +1,7 @@ macro_rules! from_uint { ($BUint: ident, $Digit: ident; $($uint: tt),*) => { - $(impl_const! { - impl const From<$uint> for $BUint { + $( + impl From<$uint> for $BUint { #[inline] fn from(int: $uint) -> Self { const UINT_BITS: usize = $uint::BITS as usize; @@ -17,14 +17,14 @@ macro_rules! from_uint { out } } - })* + )* } } macro_rules! try_from_iint { ($BUint: ident; $($int: tt -> $uint: tt),*) => { - $(impl_const! { - impl const TryFrom<$int> for $BUint { + $( + impl TryFrom<$int> for $BUint { type Error = TryFromIntError; #[inline] @@ -36,14 +36,14 @@ macro_rules! try_from_iint { Ok(Self::from(bits)) } } - })* + )* } } macro_rules! try_from_buint { ($BUint: ident, $Digit: ident; $($int: ty), *) => { - $(crate::nightly::impl_const! { - impl const TryFrom<$BUint> for $int { + $( + impl TryFrom<$BUint> for $int { type Error = TryFromIntError; #[inline] @@ -84,7 +84,7 @@ macro_rules! try_from_buint { Ok(out) } } - })* + )* }; } @@ -188,25 +188,20 @@ macro_rules! mixed_try_from { use crate::cast::CastFrom; use crate::errors::TryFromIntError; -use crate::nightly::impl_const; macro_rules! convert { ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl_const! { - impl const From for $BUint { - #[inline] - fn from(small: bool) -> Self { - Self::cast_from(small) - } + impl From for $BUint { + #[inline] + fn from(small: bool) -> Self { + Self::cast_from(small) } } - impl_const! { - impl const From for $BUint { - #[inline] - fn from(c: char) -> Self { - Self::cast_from(c) - } + impl From for $BUint { + #[inline] + fn from(c: char) -> Self { + Self::cast_from(c) } } @@ -218,21 +213,17 @@ macro_rules! convert { mixed_try_from!($BUint, $BInt); - impl_const! { - impl const From<[$Digit; N]> for $BUint { - #[inline] - fn from(digits: [$Digit; N]) -> Self { - Self::from_digits(digits) - } + impl From<[$Digit; N]> for $BUint { + #[inline] + fn from(digits: [$Digit; N]) -> Self { + Self::from_digits(digits) } } - impl_const! { - impl const From<$BUint> for [$Digit; N] { - #[inline] - fn from(uint: $BUint) -> Self { - uint.digits - } + impl From<$BUint> for [$Digit; N] { + #[inline] + fn from(uint: $BUint) -> Self { + uint.digits } } diff --git a/src/buint/fmt.rs b/src/buint/fmt.rs index 136aedd..8ba8d56 100644 --- a/src/buint/fmt.rs +++ b/src/buint/fmt.rs @@ -48,38 +48,6 @@ macro_rules! fmt { } impl Display for $BUint { - /*#[inline] - fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { - if self.is_zero() { - return f.pad_integral(true, "", "0"); - } - fn digit_to_byte(d: $Digit) -> u8 { - match d { - 0 => 0 + 48, - 1 => 1 + 48, - 2 => 2 + 48, - 3 => 3 + 48, - 4 => 4 + 48, - 5 => 5 + 48, - 6 => 6 + 48, - 7 => 7 + 48, - 8 => 8 + 48, - 9 => 9 + 48, - _ => unreachable!(), - } - } - let mut v: alloc::vec::Vec = alloc::vec::Vec::new(); - let mut u = *self; - while !u.is_zero() { - let (q, r) = u.div_rem_digit(10); - v.push(digit_to_byte(r)); - u = q; - } - v.reverse(); - let s = unsafe { String::from_utf8_unchecked(v) }; - //s.push(digit_to_char(u.digits[0])); - f.pad_integral(true, "", &s) - }*/ #[inline] fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { f.pad_integral(true, "", &self.to_str_radix(10)) diff --git a/src/buint/mask.rs b/src/buint/mask.rs new file mode 100644 index 0000000..fa20d8f --- /dev/null +++ b/src/buint/mask.rs @@ -0,0 +1,18 @@ +// macro_rules! mask { +// ($BUint: ident, $BInt: ident, $Digit: ident) => { +// impl $BUint { +// #[inline] +// pub(crate) const fn least_significant_n_bits(self, n: ExpType) -> Self { +// let mut mask = Self::ZERO; +// let mut digit_index = n as usize >> digit::$Digit::BIT_SHIFT; +// let mut i = 0; +// while i < digit_index { +// mask.digits[i] = $Digit::MAX; +// i += 1; +// } + +// self.bitand(mask) +// } +// } +// }; +// } \ No newline at end of file diff --git a/src/buint/mod.rs b/src/buint/mod.rs index 02b0724..b79e989 100644 --- a/src/buint/mod.rs +++ b/src/buint/mod.rs @@ -740,6 +740,7 @@ mod convert; mod div; mod endian; mod fmt; +mod mask; mod mul; #[cfg(feature = "numtraits")] mod numtraits; diff --git a/src/buint/numtraits.rs b/src/buint/numtraits.rs index b408895..3d3fba5 100644 --- a/src/buint/numtraits.rs +++ b/src/buint/numtraits.rs @@ -50,7 +50,6 @@ pub const fn u64_bits(u: u64) -> ExpType { 64 - u.leading_zeros() as ExpType } use crate::buint::cast::{decode_f32, decode_f64}; -//use crate::nightly::impl_const; use crate::ExpType; use num_integer::{Integer, Roots}; use num_traits::{ @@ -97,7 +96,6 @@ macro_rules! numtraits { }; } - //impl_const! { impl FromPrimitive for $BUint { #[inline] fn from_u64(int: u64) -> Option { @@ -157,9 +155,7 @@ macro_rules! numtraits { from_float!(from_f32, f32, decode_f32, u32_bits); from_float!(from_f64, f64, decode_f64, u64_bits); } - //} - //impl_const! { impl Integer for $BUint { #[inline] fn div_floor(&self, other: &Self) -> Self { @@ -244,9 +240,7 @@ macro_rules! numtraits { Self::div_rem(*self, *rhs) } } - //} - //impl_const! { impl PrimInt for $BUint { crate::int::numtraits::prim_int_methods!(); @@ -270,7 +264,6 @@ macro_rules! numtraits { self >> n } } - //} macro_rules! check_zero_or_one { ($self: ident) => { @@ -396,7 +389,6 @@ macro_rules! numtraits { } } - //impl_const! { impl ToPrimitive for $BUint { to_int! { $Digit; @@ -425,7 +417,6 @@ macro_rules! numtraits { Some(self.as_()) } } - //} impl Unsigned for $BUint {} diff --git a/src/buint/ops.rs b/src/buint/ops.rs index bd1833c..8b5942b 100644 --- a/src/buint/ops.rs +++ b/src/buint/ops.rs @@ -1,5 +1,4 @@ use crate::digit; -use crate::nightly::impl_const; use crate::ExpType; use core::ops::{ Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, @@ -8,113 +7,95 @@ use core::ops::{ macro_rules! ops { ($BUint: ident, $BInt: ident, $Digit: ident) => { - impl_const! { - impl const Add<$Digit> for $BUint { - type Output = Self; - - #[inline] - fn add(self, rhs: $Digit) -> Self { - let mut out = self; - let result = digit::$Digit::carrying_add(out.digits[0], rhs, false); - out.digits[0] = result.0; - let mut carry = result.1; - let mut i = 1; - while i < N && carry { - let result = out.digits[i].overflowing_add(1); - out.digits[i] = result.0; - carry = result.1; - i += 1; - } - out + impl Add<$Digit> for $BUint { + type Output = Self; + + #[inline] + fn add(self, rhs: $Digit) -> Self { + let mut out = self; + let result = digit::$Digit::carrying_add(out.digits[0], rhs, false); + out.digits[0] = result.0; + let mut carry = result.1; + let mut i = 1; + while i < N && carry { + let result = out.digits[i].overflowing_add(1); + out.digits[i] = result.0; + carry = result.1; + i += 1; } + out } } - impl_const! { - impl const BitAnd for $BUint { - type Output = Self; + impl BitAnd for $BUint { + type Output = Self; - #[inline] - fn bitand(self, rhs: Self) -> Self { - Self::bitand(self, rhs) - } + #[inline] + fn bitand(self, rhs: Self) -> Self { + Self::bitand(self, rhs) } } - impl_const! { - impl const BitOr for $BUint { - type Output = Self; + impl BitOr for $BUint { + type Output = Self; - #[inline] - fn bitor(self, rhs: Self) -> Self { - Self::bitor(self, rhs) - } + #[inline] + fn bitor(self, rhs: Self) -> Self { + Self::bitor(self, rhs) } } - impl_const! { - impl const BitXor for $BUint { - type Output = Self; + impl BitXor for $BUint { + type Output = Self; - #[inline] - fn bitxor(self, rhs: Self) -> Self { - Self::bitxor(self, rhs) - } + #[inline] + fn bitxor(self, rhs: Self) -> Self { + Self::bitxor(self, rhs) } } - impl_const! { - impl const Div for $BUint { - type Output = Self; + impl Div for $BUint { + type Output = Self; - #[inline] - fn div(self, rhs: Self) -> Self { - Self::div(self, rhs) - } + #[inline] + fn div(self, rhs: Self) -> Self { + Self::div(self, rhs) } } - impl_const! { - impl const Div<$Digit> for $BUint { - type Output = Self; + impl Div<$Digit> for $BUint { + type Output = Self; - #[inline] - fn div(self, rhs: $Digit) -> Self { - self.div_rem_digit(rhs).0 - } + #[inline] + fn div(self, rhs: $Digit) -> Self { + self.div_rem_digit(rhs).0 } } - impl_const! { - impl const Not for $BUint { - type Output = Self; + impl Not for $BUint { + type Output = Self; - #[inline] - fn not(self) -> Self { - Self::not(self) - } + #[inline] + fn not(self) -> Self { + Self::not(self) } } - impl_const! { - impl const Rem for $BUint { - type Output = Self; + impl Rem for $BUint { + type Output = Self; - #[inline] - fn rem(self, rhs: Self) -> Self { - Self::rem(self, rhs) - } + #[inline] + fn rem(self, rhs: Self) -> Self { + Self::rem(self, rhs) } } - impl_const! { - impl const Rem<$Digit> for $BUint { - type Output = $Digit; + impl Rem<$Digit> for $BUint { + type Output = $Digit; - #[inline] - fn rem(self, rhs: $Digit) -> $Digit { - self.div_rem_digit(rhs).1 - } + #[inline] + fn rem(self, rhs: $Digit) -> $Digit { + self.div_rem_digit(rhs).1 } } diff --git a/src/buint/radix.rs b/src/buint/radix.rs index f9f5561..f8a8b88 100644 --- a/src/buint/radix.rs +++ b/src/buint/radix.rs @@ -628,11 +628,6 @@ macro_rules! radix { quickcheck_from_to_radix!(utest, radix_le, 256); quickcheck_from_to_radix!(utest, str_radix, 36); - // #[test] - // fn parse_str_radix() { - // assert_eq!(UTEST::parse_str_radix()) - // } - #[test] #[should_panic(expected = "attempt to parse integer from empty string")] fn parse_str_radix_empty() { diff --git a/src/buint/saturating.rs b/src/buint/saturating.rs index 2509014..afb86fd 100644 --- a/src/buint/saturating.rs +++ b/src/buint/saturating.rs @@ -69,35 +69,30 @@ macro_rules! saturating { Self::saturate_up(self.overflowing_pow(exp)) } } - - #[cfg(test)] - paste::paste! { - mod [<$Digit _digit_tests>] { - use crate::test::{test_bignum, types::*}; - use crate::test::types::big_types::$Digit::*; - - test_bignum! { - function: ::saturating_add(a: utest, b: utest) - } - test_bignum! { - function: ::saturating_add_signed(a: utest, b: itest) - } - test_bignum! { - function: ::saturating_sub(a: utest, b: utest) - } - test_bignum! { - function: ::saturating_mul(a: utest, b: utest) - } - test_bignum! { - function: ::saturating_div(a: utest, b: utest), - skip: b == 0 - } - test_bignum! { - function: ::saturating_pow(a: utest, b: u16) - } - } - } }; } +#[cfg(test)] +crate::test::all_digit_tests! { + test_bignum! { + function: ::saturating_add(a: utest, b: utest) + } + test_bignum! { + function: ::saturating_add_signed(a: utest, b: itest) + } + test_bignum! { + function: ::saturating_sub(a: utest, b: utest) + } + test_bignum! { + function: ::saturating_mul(a: utest, b: utest) + } + test_bignum! { + function: ::saturating_div(a: utest, b: utest), + skip: b == 0 + } + test_bignum! { + function: ::saturating_pow(a: utest, b: u16) + } +} + crate::macro_impl!(saturating); diff --git a/src/cast/float/mod.rs b/src/cast/float/mod.rs index 63a3279..ba01223 100644 --- a/src/cast/float/mod.rs +++ b/src/cast/float/mod.rs @@ -21,27 +21,25 @@ pub trait FloatMantissa: Sized + Shl + Shr { $( - crate::nightly::const_impl! { - impl const FloatMantissa for $uint { - const ZERO: Self = 0; - const ONE: Self = 1; - const TWO: Self = 2; - const MAX: Self = Self::MAX; - - #[inline] - fn leading_zeros(self) -> ExpType { - Self::leading_zeros(self) as ExpType - } + impl FloatMantissa for $uint { + const ZERO: Self = 0; + const ONE: Self = 1; + const TWO: Self = 2; + const MAX: Self = Self::MAX; + + #[inline] + fn leading_zeros(self) -> ExpType { + Self::leading_zeros(self) as ExpType + } - #[inline] - fn checked_shr(self, n: ExpType) -> Option { - Self::checked_shr(self, n as u32) - } + #[inline] + fn checked_shr(self, n: ExpType) -> Option { + Self::checked_shr(self, n as u32) + } - #[inline] - fn is_power_of_two(self) -> bool { - Self::is_power_of_two(self) - } + #[inline] + fn is_power_of_two(self) -> bool { + Self::is_power_of_two(self) } } )* diff --git a/src/cast/mod.rs b/src/cast/mod.rs index 23fc44d..4dc7a98 100644 --- a/src/cast/mod.rs +++ b/src/cast/mod.rs @@ -128,14 +128,14 @@ as_trait!(); macro_rules! primitive_cast_impl { ($from: ty as [$($ty: ty), *]) => { - $(crate::nightly::const_impl! { - impl const CastFrom<$from> for $ty { + $( + impl CastFrom<$from> for $ty { #[inline] fn cast_from(from: $from) -> Self { from as Self } } - })* + )* }; } diff --git a/src/float/cmp.rs b/src/float/cmp.rs index a2d0abc..95bbc65 100644 --- a/src/float/cmp.rs +++ b/src/float/cmp.rs @@ -86,21 +86,17 @@ impl Float { } } -crate::nightly::impl_const! { - impl const PartialEq for Float { - #[inline] - fn eq(&self, other: &Self) -> bool { - Self::eq(&self, other) - } +impl PartialEq for Float { + #[inline] + fn eq(&self, other: &Self) -> bool { + Self::eq(&self, other) } } -crate::nightly::impl_const! { - impl const PartialOrd for Float { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Self::partial_cmp(&self, other) - } +impl PartialOrd for Float { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Self::partial_cmp(&self, other) } } diff --git a/src/float/numtraits.rs b/src/float/numtraits.rs index 0d3bcea..f7e412a 100644 --- a/src/float/numtraits.rs +++ b/src/float/numtraits.rs @@ -1,5 +1,6 @@ use super::Float; -use num_traits::{Bounded, ConstZero, ConstOne, One, Zero, Signed, Euclid}; +use num_traits::{Bounded, ConstZero, ConstOne, One, Zero, AsPrimitive, float::TotalOrder}; +use crate::cast::CastFrom; impl Bounded for Float { #[inline] @@ -74,4 +75,50 @@ impl One for Float { // fn signum(&self) -> Self { // Self::signum(*self) // } -// } \ No newline at end of file +// } + +macro_rules! impl_as_primitive { + ($($primitive: ty), *) => { + $( + impl AsPrimitive<$primitive> for Float { + #[inline] + fn as_(self) -> $primitive { + <$primitive>::cast_from(self) + } + } + + impl AsPrimitive> for $primitive { + #[inline] + fn as_(self) -> Float { + Float::cast_from(self) + } + } + )* + }; +} + +impl_as_primitive!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64); + +impl TotalOrder for Float { + #[inline] + fn total_cmp(&self, other: &Self) -> core::cmp::Ordering { + Self::total_cmp(&self, other) + } +} + +#[cfg(test)] +mod tests { + use crate::test::test_bignum; + use crate::test::types::{ftest, FTEST}; + use super::*; + + test_bignum! { + function: ::is_zero(a: ref &ftest) + } + test_bignum! { + function: ::is_one(a: ref &ftest) + } + test_bignum! { + function: ::total_cmp(a: ref &ftest, b: ref &ftest) + } +} \ No newline at end of file diff --git a/src/float/ops/add.rs b/src/float/ops/add.rs index 720d01b..82c3958 100644 --- a/src/float/ops/add.rs +++ b/src/float/ops/add.rs @@ -2,10 +2,76 @@ use core::num::FpCategory; use crate::{float::UnsignedFloatExponent, BUintD8, ExpType}; use super::Float; -// TODO: quickcheck tests are very occasionally failing, need to fix this function impl Float { #[inline] pub(super) fn add_internal(self, rhs: Self, negative: bool) -> Self { + let (a, b) = if rhs.abs().total_cmp(&self.abs()) == core::cmp::Ordering::Greater { + // If b has is larger than a, swap a and b so that a has the larger exponent + (rhs, self) + } else { + (self, rhs) + }; + let (_, a_exp, a_mant) = a.into_normalised_signed_parts(); + let (_, b_exp, b_mant) = b.into_normalised_signed_parts(); + let exp_diff = (a_exp - b_exp) as UnsignedFloatExponent; // guaranteed to be non-negative since a >= b + + // If the shift causes an overflow, the b_mant is too small so is set to 0 + let (exp, mant) = if UnsignedFloatExponent::BITS - exp_diff.leading_zeros() <= ExpType::BITS { // number of bits needed to store exp_diff is less than bit width of ExpType, so can cast + let exp_diff = exp_diff as ExpType; + match b_mant.checked_shr(exp_diff) { // shift b_mant so it is aligned (in terms of exponents) with a_mant, so we can add them + Some(shifted) => { + if exp_diff == 0 { + let mut mant = a_mant + shifted; // result must have overflowed, since both shifted and a_mant have bit at index Self::MB set to 1 + let round_up = mant.digits[0] & 0b11 == 0b11; // round by ties-to-even + mant = mant >> 1; + if round_up { + mant += BUintD8::ONE; // note this cannot overflow now, since if there was round up, then the last bit of the sum is one, meaning that a_mant and shifted can't both be their maximum value (which would be required for overflow here) + } + (a_exp + 1, mant) + } else { + let mut mant = a_mant + shifted; + let discarded_bits = b_mant & (BUintD8::MAX >> (BUintD8::::BITS - exp_diff)); + if mant.bit(Self::MB + 1) { // overflow occurred + let mut shifted_mant: BUintD8 = mant >> 1; + let gte_half = mant.is_odd(); // if discarded bits are at least a half + let round_up = gte_half && !(discarded_bits.is_zero() && shifted_mant.is_even()); // round by ties-to-even + if round_up { + shifted_mant += BUintD8::ONE; + } + (a_exp + 1, shifted_mant) + } else { // no overflow yet, but still need to check for overflow when performing ties-to-even rounding + let round_up = discarded_bits.bit(exp_diff - 1) && !(discarded_bits.is_power_of_two() && mant.is_even()); // round according to ties-to-even. exp_diff - 1 will be non-negative, since if exp_diff = 0, then we would have had the overflow condition earlier + if round_up { + mant += BUintD8::ONE; + } + if mant.bit(Self::MB + 1) { // overflow occurred + debug_assert!(mant.is_even()); // since overflow occurred and we added one, the result must be even + (a_exp + 1, mant >> 1) // don't need to worry about checking for round up here, as mantissa is even, so when right shifted by 1, the discarded bits will be less than half (i.e. no round up) + } else { + (a_exp, mant) + } + } + } + }, + None => (a_exp, a_mant), // no round up since the type holding b_mant has bit-width <= exp_diff, and b_mant has bit-width strictly smaller than the type's bit-width (since we enforce the float exponent to be at least one bit wide) + } + } else { + // we can't even cast exp_diff to ExpType, so it would be right-shifted to 0, and no round up since b_mant can't ever be the full width of ExpType::MAX (since we enforce all bnum types to have bit width <= ExpType::MAX, and we enforce that the float exponent takes at least one bit) + (a_exp, a_mant) + }; + if exp >= Self::MAX_EXP { + debug_assert!(exp.eq(&Self::MAX_EXP)); // shouldn't be possible for exponent to have exceeded maximum exponent + return if negative { + Self::NEG_INFINITY + } else { + Self::INFINITY + }; + } + Self::from_normalised_signed_parts(negative, exp, mant) + } + + #[inline] + pub(super) fn add_internal_old(self, rhs: Self, negative: bool) -> Self { let (a, b) = if rhs.abs().gt(&self.abs()) { // If b has a larger exponent than a, swap a and b so that a has the larger exponent (rhs, self) @@ -29,7 +95,6 @@ impl Float { } else { BUintD8::ZERO }; - if sticky_bit { b_mant |= BUintD8::ONE; // round up } @@ -38,22 +103,22 @@ impl Float { let overflow = !(mant >> (MB + 3)).is_zero(); if !overflow { - if mant & BUintD8::from_digit(0b11) == BUintD8::from_digit(0b11) - || mant & BUintD8::from_digit(0b110) == BUintD8::from_digit(0b110) + if mant.digits[0] & 0b11 == 0b11 + || mant.digits[0] & 0b110 == 0b110 { - mant += BUintD8::FOUR; + mant += BUintD8::FOUR; // += 0b100 if !(mant >> (MB + 3)).is_zero() { mant >>= 1 as ExpType; a_exp += 1; } } } else { - match (mant & BUintD8::from_digit(0b111)).digits()[0] { + match mant.digits[0] & 0b111 { 0b111 | 0b110 | 0b101 => { - mant += BUintD8::EIGHT; + mant += BUintD8::EIGHT; // 0b1000 } 0b100 => { - if mant & BUintD8::from_digit(0b1000) == BUintD8::from_digit(0b1000) { + if mant.digits[0] & 0b1000 == 0b1000 { mant += BUintD8::EIGHT; // 0b1000 } } @@ -91,7 +156,7 @@ impl Float { (FpCategory::Nan, _) => self, (_, FpCategory::Nan) => rhs, (FpCategory::Infinite, FpCategory::Infinite) => { - if self_negative ^ rhs_negative { + if self_negative != rhs_negative { Self::NAN } else { self @@ -107,7 +172,7 @@ impl Float { } } (_, _) => { - if self_negative ^ rhs_negative { + if self_negative != rhs_negative { self.sub_internal(rhs, self_negative) } else { let r = self.add_internal(rhs, self_negative); diff --git a/src/float/ops/mod.rs b/src/float/ops/mod.rs index 73a88cd..a1fd770 100644 --- a/src/float/ops/mod.rs +++ b/src/float/ops/mod.rs @@ -1,6 +1,6 @@ use super::Float; use core::iter::{Iterator, Product, Sum}; -use core::ops::{Add, Div, Mul, Neg, Rem, Sub}; +use core::ops::{Add, Div, Mul, Neg, Rem, Sub, AddAssign, SubAssign, MulAssign, RemAssign}; mod add; mod sub; @@ -8,25 +8,35 @@ mod mul; mod div; mod rem; -impl Add for Float { - type Output = Self; +macro_rules! impl_assign_op { + ($AssignTrait: ident, $assign_fn: ident, $op_fn: ident) => { + impl $AssignTrait for Float { + #[inline] + fn $assign_fn(&mut self, rhs: Self) { + *self = self.$op_fn(rhs); + } + } - #[inline] - fn add(self, rhs: Self) -> Self { - Self::add(self, rhs) - } + impl $AssignTrait<&Self> for Float { + #[inline] + fn $assign_fn(&mut self, rhs: &Self) { + *self = self.$op_fn(*rhs); + } + } + }; } -impl Sub for Float { +impl Add for Float { type Output = Self; #[inline] - fn sub(self, rhs: Self) -> Self { - Self::sub(self, rhs) + fn add(self, rhs: Self) -> Self { + Self::add(self, rhs) } } crate::int::ops::op_ref_impl!(Add> for Float, add); +impl_assign_op!(AddAssign, add_assign, add); impl Sum for Float { #[inline] @@ -42,7 +52,17 @@ impl<'a, const W: usize, const MB: usize> Sum<&'a Self> for Float { } } +impl Sub for Float { + type Output = Self; + + #[inline] + fn sub(self, rhs: Self) -> Self { + Self::sub(self, rhs) + } +} + crate::int::ops::op_ref_impl!(Sub> for Float, sub); +impl_assign_op!(SubAssign, sub_assign, sub); impl Mul for Float { type Output = Self; @@ -53,6 +73,8 @@ impl Mul for Float { } } +crate::int::ops::op_ref_impl!(Mul> for Float, mul); + impl Product for Float where [(); W * 2]:, @@ -86,6 +108,7 @@ where } // crate::int::ops::op_ref_impl!(Div> for Float, div); +// impl_assign_op!(DivAssign, div_assign, div); impl Rem for Float { type Output = Self; @@ -97,26 +120,23 @@ impl Rem for Float { } crate::int::ops::op_ref_impl!(Rem> for Float, rem); +impl_assign_op!(RemAssign, rem_assign, rem); -crate::nightly::impl_const! { - impl const Neg for Float { - type Output = Self; +impl Neg for Float { + type Output = Self; - #[inline] - fn neg(self) -> Self { - Self::neg(self) - } + #[inline] + fn neg(self) -> Self { + Self::neg(self) } } -crate::nightly::impl_const! { - impl const Neg for &Float { - type Output = Float; +impl Neg for &Float { + type Output = Float; - #[inline] - fn neg(self) -> Float { - (*self).neg() - } + #[inline] + fn neg(self) -> Float { + (*self).neg() } } @@ -127,7 +147,9 @@ mod tests { use crate::test::types::{ftest, FTEST}; test_bignum! { - function: ::add(a: ftest, b: ftest) + function: ::add(a: ftest, b: ftest), + skip: a.is_sign_negative() != b.is_sign_negative(), + cases: [(1.3952888382785755e33, 1.466527384898436e33)] } test_bignum! { function: ::sub(a: ftest, b: ftest) diff --git a/src/helpers.rs b/src/helpers.rs index 1886c56..09f7ceb 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -27,7 +27,6 @@ macro_rules! impl_bits_for_uint { impl_bits_for_uint!(u8, u16, u32, u64, u128, usize); -#[cfg(feature = "float")] macro_rules! impl_bits_for_buint { ($BUint: ident, $BInt: ident, $Digit: ident) => { impl crate::helpers::Bits for $BUint { @@ -46,7 +45,6 @@ macro_rules! impl_bits_for_buint { }; } -#[cfg(feature = "float")] crate::macro_impl!(impl_bits_for_buint); pub trait Zero: Sized + PartialEq { @@ -104,3 +102,12 @@ macro_rules! impl_one_for_buint { } crate::macro_impl!(impl_one_for_buint); + +#[inline] +pub const fn tuple_to_option((int, overflow): (T, bool)) -> Option { + if overflow { + None + } else { + Some(int) + } +} diff --git a/src/int/checked.rs b/src/int/checked.rs index af20ba0..e69de29 100644 --- a/src/int/checked.rs +++ b/src/int/checked.rs @@ -1,8 +0,0 @@ -#[inline] -pub const fn tuple_to_option((int, overflow): (T, bool)) -> Option { - if overflow { - None - } else { - Some(int) - } -} diff --git a/src/int/numtraits.rs b/src/int/numtraits.rs index d2645c0..7fd7a74 100644 --- a/src/int/numtraits.rs +++ b/src/int/numtraits.rs @@ -1,28 +1,26 @@ -macro_rules! as_primitive_impl { +macro_rules! impl_as_primitive_big_num_for_primitive { ($Int: ident; $($ty: ty), *) => { $( impl AsPrimitive<$ty> for $Int { #[inline] fn as_(self) -> $ty { - <$ty as crate::cast::CastFrom>::cast_from(self) + <$ty>::cast_from(self) } } )* } } -pub(crate) use as_primitive_impl; +pub(crate) use impl_as_primitive_big_num_for_primitive; macro_rules! num_trait_impl { ($Int: ident, $tr: ident, $method: ident, $ret: ty) => { - //crate::nightly::impl_const! { impl $tr for $Int { #[inline] fn $method(&self, rhs: &Self) -> $ret { Self::$method(*self, *rhs) } } - //} }; } @@ -31,14 +29,12 @@ pub(crate) use num_trait_impl; macro_rules! as_bigint_impl { ([$($ty: ty), *] as $Big: ident) => { $( - //crate::nightly::impl_const! { - impl AsPrimitive<$Big> for $ty { - #[inline] - fn as_(self) -> $Big { - $Big::cast_from(self) - } + impl AsPrimitive<$Big> for $ty { + #[inline] + fn as_(self) -> $Big { + $Big::cast_from(self) } - //} + } )* } } @@ -47,19 +43,17 @@ pub(crate) use as_bigint_impl; macro_rules! impls { ($Int: ident, $BUint: ident, $BInt: ident, $Digit: ident) => { - //crate::nightly::impl_const! { - impl Bounded for $Int { - #[inline] - fn min_value() -> Self { - Self::MIN - } + impl Bounded for $Int { + #[inline] + fn min_value() -> Self { + Self::MIN + } - #[inline] - fn max_value() -> Self { - Self::MAX - } + #[inline] + fn max_value() -> Self { + Self::MAX } - //} + } num_trait_impl!($Int, CheckedAdd, checked_add, Option); num_trait_impl!($Int, CheckedDiv, checked_div, Option); @@ -75,32 +69,26 @@ macro_rules! impls { num_trait_impl!($Int, WrappingMul, wrapping_mul, Self); num_trait_impl!($Int, WrappingSub, wrapping_sub, Self); - //crate::nightly::impl_const! { - impl CheckedNeg for $Int { - #[inline] - fn checked_neg(&self) -> Option { - Self::checked_neg(*self) - } + impl CheckedNeg for $Int { + #[inline] + fn checked_neg(&self) -> Option { + Self::checked_neg(*self) } - //} + } - //crate::nightly::impl_const! { - impl CheckedShl for $Int { - #[inline] - fn checked_shl(&self, rhs: u32) -> Option { - Self::checked_shl(*self, rhs as ExpType) - } + impl CheckedShl for $Int { + #[inline] + fn checked_shl(&self, rhs: u32) -> Option { + Self::checked_shl(*self, rhs as ExpType) } - //} + } - //crate::nightly::impl_const! { - impl CheckedShr for $Int { - #[inline] - fn checked_shr(&self, rhs: u32) -> Option { - Self::checked_shr(*self, rhs as ExpType) - } + impl CheckedShr for $Int { + #[inline] + fn checked_shr(&self, rhs: u32) -> Option { + Self::checked_shr(*self, rhs as ExpType) } - //} + } impl CheckedEuclid for $Int { #[inline] @@ -126,79 +114,65 @@ macro_rules! impls { } } - //crate::nightly::impl_const! { - impl WrappingNeg for $Int { - #[inline] - fn wrapping_neg(&self) -> Self { - Self::wrapping_neg(*self) - } + impl WrappingNeg for $Int { + #[inline] + fn wrapping_neg(&self) -> Self { + Self::wrapping_neg(*self) } - //} + } - //crate::nightly::impl_const! { - impl WrappingShl for $Int { - #[inline] - fn wrapping_shl(&self, rhs: u32) -> Self { - Self::wrapping_shl(*self, rhs as ExpType) - } + impl WrappingShl for $Int { + #[inline] + fn wrapping_shl(&self, rhs: u32) -> Self { + Self::wrapping_shl(*self, rhs as ExpType) } - //} + } - //crate::nightly::impl_const! { - impl WrappingShr for $Int { - #[inline] - fn wrapping_shr(&self, rhs: u32) -> Self { - Self::wrapping_shr(*self, rhs as ExpType) - } + impl WrappingShr for $Int { + #[inline] + fn wrapping_shr(&self, rhs: u32) -> Self { + Self::wrapping_shr(*self, rhs as ExpType) } - //} + } - //crate::nightly::impl_const! { - impl Pow for $Int { - type Output = Self; + impl Pow for $Int { + type Output = Self; - #[inline] - fn pow(self, exp: ExpType) -> Self { - Self::pow(self, exp) - } + #[inline] + fn pow(self, exp: ExpType) -> Self { + Self::pow(self, exp) } - //} + } - //crate::nightly::impl_const! { - impl Saturating for $Int { - #[inline] - fn saturating_add(self, rhs: Self) -> Self { - Self::saturating_add(self, rhs) - } + impl Saturating for $Int { + #[inline] + fn saturating_add(self, rhs: Self) -> Self { + Self::saturating_add(self, rhs) + } - #[inline] - fn saturating_sub(self, rhs: Self) -> Self { - Self::saturating_sub(self, rhs) - } + #[inline] + fn saturating_sub(self, rhs: Self) -> Self { + Self::saturating_sub(self, rhs) } - //} + } - crate::int::numtraits::as_primitive_impl!($Int; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64); + crate::int::numtraits::impl_as_primitive_big_num_for_primitive!($Int; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64); crate::int::numtraits::as_bigint_impl!([u8, u16, u32, usize, u64, u128, i8, i16, i32, isize, i64, i128, char, bool, f32, f64] as $Int); - //crate::nightly::impl_const! { - impl AsPrimitive<$BUint> for $Int { - #[inline] - fn as_(self) -> crate::$BUint { - crate::$BUint::::cast_from(self) - } + impl AsPrimitive<$BUint> for $Int { + #[inline] + fn as_(self) -> crate::$BUint { + crate::$BUint::::cast_from(self) } - //} + } - //crate::nightly::impl_const! { - impl AsPrimitive<$BInt> for $Int { - #[inline] - fn as_(self) -> crate::$BInt { - crate::$BInt::::cast_from(self) - } + impl AsPrimitive<$BInt> for $Int { + #[inline] + fn as_(self) -> crate::$BInt { + crate::$BInt::::cast_from(self) } - //} + } // #[cfg(feature = "nightly")] // #[doc = crate::doc::requires_feature!("nightly")] @@ -220,7 +194,7 @@ macro_rules! impls { // Self::to_ne_bytes(*self) // } // } - + // #[cfg(feature = "nightly")] // #[doc = crate::doc::requires_feature!("nightly")] // impl ToBytes for $Int { @@ -242,25 +216,21 @@ macro_rules! impls { // } // } - //crate::nightly::impl_const! { - impl MulAdd for $Int { - type Output = Self; + impl MulAdd for $Int { + type Output = Self; - #[inline] - fn mul_add(self, a: Self, b: Self) -> Self { - (self * a) + b - } + #[inline] + fn mul_add(self, a: Self, b: Self) -> Self { + (self * a) + b } - //} + } - //crate::nightly::impl_const! { - impl MulAddAssign for $Int { - #[inline] - fn mul_add_assign(&mut self, a: Self, b: Self) { - *self = self.mul_add(a, b); - } + impl MulAddAssign for $Int { + #[inline] + fn mul_add_assign(&mut self, a: Self, b: Self) { + *self = self.mul_add(a, b); } - //} + } impl Num for $Int { type FromStrRadixErr = crate::errors::ParseIntError; @@ -271,49 +241,43 @@ macro_rules! impls { } } - //crate::nightly::impl_const! { - impl num_traits::NumCast for $Int { - fn from(_n: T) -> Option { - panic!(concat!(crate::errors::err_prefix!(), "`num_traits::NumCast` trait is not supported for ", stringify!($Int))) - } + impl num_traits::NumCast for $Int { + fn from(_n: T) -> Option { + panic!(concat!(crate::errors::err_prefix!(), "`num_traits::NumCast` trait is not supported for ", stringify!($Int))) } - //} - - //crate::nightly::impl_const! { - impl One for $Int { - #[inline] - fn one() -> Self { - Self::ONE - } + } - #[inline] - fn is_one(&self) -> bool { - Self::is_one(&self) - } + impl One for $Int { + #[inline] + fn one() -> Self { + Self::ONE } - impl ConstOne for $Int { - const ONE: Self = Self::ONE; + #[inline] + fn is_one(&self) -> bool { + Self::is_one(&self) } - //} + } - //crate::nightly::impl_const! { - impl Zero for $Int { - #[inline] - fn zero() -> Self { - Self::ZERO - } + impl ConstOne for $Int { + const ONE: Self = Self::ONE; + } - #[inline] - fn is_zero(&self) -> bool { - Self::is_zero(&self) - } + impl Zero for $Int { + #[inline] + fn zero() -> Self { + Self::ZERO } - impl ConstZero for $Int { - const ZERO: Self = Self::ZERO; + #[inline] + fn is_zero(&self) -> bool { + Self::is_zero(&self) } - //} + } + + impl ConstZero for $Int { + const ZERO: Self = Self::ZERO; + } } } @@ -397,7 +361,7 @@ macro_rules! tests { use super::*; use num_traits::PrimInt; use crate::test::{test_bignum, TestConvert}; - + crate::test::test_into! { function: <$int as AsPrimitive>::as_, into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64) @@ -512,7 +476,7 @@ macro_rules! tests { assert_eq!(<$int>::max_value(), TestConvert::into([<$int:upper>]::max_value())); } } - + test_bignum! { function: <$int>::sqrt(a: ref &$int), skip: { diff --git a/src/int/ops.rs b/src/int/ops.rs index c660e3d..9521d00 100644 --- a/src/int/ops.rs +++ b/src/int/ops.rs @@ -1,35 +1,29 @@ macro_rules! op_ref_impl { ($tr: ident <$rhs: ty> for $Struct: ident <$($C: ident),+>, $method: ident) => { - crate::nightly::impl_const! { - impl<$(const $C: usize),+> const $tr<&$rhs> for $Struct <$($C),+> { - type Output = $Struct <$($C),+>; + impl<$(const $C: usize),+> $tr<&$rhs> for $Struct <$($C),+> { + type Output = $Struct <$($C),+>; - #[inline] - fn $method(self, rhs: &$rhs) -> Self::Output { - $tr::<$rhs>::$method(self, *rhs) - } + #[inline] + fn $method(self, rhs: &$rhs) -> Self::Output { + $tr::<$rhs>::$method(self, *rhs) } } - crate::nightly::impl_const! { - impl<$(const $C: usize),+> const $tr<&$rhs> for &$Struct <$($C),+> { - type Output = $Struct <$($C),+>; + impl<$(const $C: usize),+> $tr<&$rhs> for &$Struct <$($C),+> { + type Output = $Struct <$($C),+>; - #[inline] - fn $method(self, rhs: &$rhs) -> Self::Output { - $tr::<$rhs>::$method(*self, *rhs) - } + #[inline] + fn $method(self, rhs: &$rhs) -> Self::Output { + $tr::<$rhs>::$method(*self, *rhs) } } - crate::nightly::impl_const! { - impl<$(const $C: usize),+> const $tr<$rhs> for &$Struct <$($C),+> { - type Output = $Struct <$($C),+>; + impl<$(const $C: usize),+> $tr<$rhs> for &$Struct <$($C),+> { + type Output = $Struct <$($C),+>; - #[inline] - fn $method(self, rhs: $rhs) -> Self::Output { - $tr::<$rhs>::$method(*self, rhs) - } + #[inline] + fn $method(self, rhs: $rhs) -> Self::Output { + $tr::<$rhs>::$method(*self, rhs) } } } @@ -38,21 +32,17 @@ pub(crate) use op_ref_impl; macro_rules! assign_op_impl { ($OpTrait: ident, $AssignTrait: ident<$rhs: ty> for $Struct: ident, $assign: ident, $op: ident) => { - crate::nightly::impl_const! { - impl const $AssignTrait<$rhs> for $Struct { - #[inline] - fn $assign(&mut self, rhs: $rhs) { - *self = $OpTrait::$op(*self, rhs); - } + impl $AssignTrait<$rhs> for $Struct { + #[inline] + fn $assign(&mut self, rhs: $rhs) { + *self = $OpTrait::$op(*self, rhs); } } - crate::nightly::impl_const! { - impl const $AssignTrait<&$rhs> for $Struct { - #[inline] - fn $assign(&mut self, rhs: &$rhs) { - self.$assign(*rhs); - } + impl $AssignTrait<&$rhs> for $Struct { + #[inline] + fn $assign(&mut self, rhs: &$rhs) { + self.$assign(*rhs); } } @@ -63,8 +53,8 @@ pub(crate) use assign_op_impl; macro_rules! shift_impl { ($Struct: ident, $tr: tt, $method: ident, $assign_tr: tt, $assign_method: ident, $($rhs: ty), *) => { - $(crate::nightly::impl_const! { - impl const $tr<$rhs> for $Struct { + $( + impl $tr<$rhs> for $Struct { type Output = Self; #[inline] @@ -72,15 +62,15 @@ macro_rules! shift_impl { self.$method(rhs as crate::ExpType) } } - })* + )* } } pub(crate) use shift_impl; macro_rules! try_shift_impl { ($Struct: ident, $BUint: ident, $BInt: ident; $tr: tt, $method: ident, $assign_tr: tt, $assign_method: ident, $err: expr, $($rhs: ty), *) => { - $(crate::nightly::impl_const! { - impl const $tr<$rhs> for $Struct { + $( + impl $tr<$rhs> for $Struct { type Output = Self; #[inline] @@ -94,74 +84,62 @@ macro_rules! try_shift_impl { self.$method(rhs) } } - })* + )* } } pub(crate) use try_shift_impl; macro_rules! shift_self_impl { ($Struct: ident, $BUint: ident, $BInt: ident; $tr: tt<$rhs: tt>, $method: ident, $assign_tr: tt, $assign_method: ident, $err: expr) => { - crate::nightly::impl_const! { - impl const $tr<$rhs> for $Struct { - type Output = Self; - - #[inline] - fn $method(self, rhs: $rhs) -> Self { - use crate::ExpType; - let rhs: ExpType = crate::errors::result_expect!(ExpType::try_from(rhs), crate::errors::err_msg!($err)); - self.$method(rhs) - } + impl $tr<$rhs> for $Struct { + type Output = Self; + + #[inline] + fn $method(self, rhs: $rhs) -> Self { + use crate::ExpType; + let rhs: ExpType = crate::errors::result_expect!(ExpType::try_from(rhs), crate::errors::err_msg!($err)); + self.$method(rhs) } } - crate::nightly::impl_const! { - impl const $tr<&$rhs> for $Struct { - type Output = $Struct; + impl $tr<&$rhs> for $Struct { + type Output = $Struct; - #[inline] - fn $method(self, rhs: &$rhs) -> Self::Output { - $tr::<$rhs>::$method(self, *rhs) - } + #[inline] + fn $method(self, rhs: &$rhs) -> Self::Output { + $tr::<$rhs>::$method(self, *rhs) } } - crate::nightly::impl_const! { - impl const $tr<&$rhs> for &$Struct { - type Output = $Struct; + impl $tr<&$rhs> for &$Struct { + type Output = $Struct; - #[inline] - fn $method(self, rhs: &$rhs) -> Self::Output { - $tr::<$rhs>::$method(*self, *rhs) - } + #[inline] + fn $method(self, rhs: &$rhs) -> Self::Output { + $tr::<$rhs>::$method(*self, *rhs) } } - crate::nightly::impl_const! { - impl const $tr<$rhs> for &$Struct { - type Output = $Struct; + impl $tr<$rhs> for &$Struct { + type Output = $Struct; - #[inline] - fn $method(self, rhs: $rhs) -> Self::Output { - $tr::<$rhs>::$method(*self, rhs) - } + #[inline] + fn $method(self, rhs: $rhs) -> Self::Output { + $tr::<$rhs>::$method(*self, rhs) } } - crate::nightly::impl_const! { - impl const $assign_tr<$rhs> for $Struct { - #[inline] - fn $assign_method(&mut self, rhs: $rhs) { - *self = $tr::<$rhs>::$method(*self, rhs); - } + impl $assign_tr<$rhs> for $Struct { + #[inline] + fn $assign_method(&mut self, rhs: $rhs) { + *self = $tr::<$rhs>::$method(*self, rhs); } } - crate::nightly::impl_const! { - impl const $assign_tr<&$rhs> for $Struct { - #[inline] - fn $assign_method(&mut self, rhs: &$rhs) { - (*self).$assign_method(*rhs); - } + impl $assign_tr<&$rhs> for $Struct { + #[inline] + fn $assign_method(&mut self, rhs: &$rhs) { + (*self).$assign_method(*rhs); } } } @@ -330,71 +308,59 @@ pub(crate) use trait_fillers; macro_rules! impls { ($Struct: ident, $BUint: ident, $BInt: ident) => { - crate::nightly::impl_const! { - impl const Add for $Struct { - type Output = Self; + impl Add for $Struct { + type Output = Self; - #[inline] - fn add(self, rhs: Self) -> Self { - Self::add(self, rhs) - } + #[inline] + fn add(self, rhs: Self) -> Self { + Self::add(self, rhs) } } - crate::nightly::impl_const! { - impl const Mul for $Struct { - type Output = Self; + impl Mul for $Struct { + type Output = Self; - #[inline] - fn mul(self, rhs: Self) -> Self { - Self::mul(self, rhs) - } + #[inline] + fn mul(self, rhs: Self) -> Self { + Self::mul(self, rhs) } } - crate::nightly::impl_const! { - impl const Not for &$Struct { - type Output = $Struct; + impl Not for &$Struct { + type Output = $Struct; - #[inline] - fn not(self) -> $Struct { - (*self).not() // TODO: maybe use separate impl for this as well - } + #[inline] + fn not(self) -> $Struct { + (*self).not() // TODO: maybe use separate impl for this as well } } - crate::nightly::impl_const! { - impl const Shl for $Struct { - type Output = Self; + impl Shl for $Struct { + type Output = Self; - #[inline] - fn shl(self, rhs: ExpType) -> Self { - Self::shl(self, rhs) - } + #[inline] + fn shl(self, rhs: ExpType) -> Self { + Self::shl(self, rhs) } } - crate::nightly::impl_const! { - impl const Shr for $Struct { - type Output = Self; + impl Shr for $Struct { + type Output = Self; - #[inline] - fn shr(self, rhs: ExpType) -> Self { - Self::shr(self, rhs) - } + #[inline] + fn shr(self, rhs: ExpType) -> Self { + Self::shr(self, rhs) } } crate::int::ops::all_shift_impls!($Struct, $BUint, $BInt); - crate::nightly::impl_const! { - impl const Sub for $Struct { - type Output = Self; + impl Sub for $Struct { + type Output = Self; - #[inline] - fn sub(self, rhs: Self) -> Self { - Self::sub(self, rhs) - } + #[inline] + fn sub(self, rhs: Self) -> Self { + Self::sub(self, rhs) } } diff --git a/src/nightly.rs b/src/nightly.rs index da2d4fa..0f653c7 100644 --- a/src/nightly.rs +++ b/src/nightly.rs @@ -32,38 +32,6 @@ macro_rules! const_fns { pub(crate) use const_fns; -#[cfg(feature = "nightly")] -macro_rules! impl_const { - { impl $(<$(const $C: ident : $ty: ty), +>)? const $($tt: tt) + } => { - impl $(<$(const $C: $ty), +>)? $($tt) + - } -} - -#[cfg(not(feature = "nightly"))] -macro_rules! impl_const { - { impl $(<$(const $C: ident : $ty: ty), +>)? const $($tt: tt) + } => { - impl $(<$(const $C: $ty), +>)? $($tt) + - } -} - -pub(crate) use impl_const; - -#[cfg(feature = "nightly")] -macro_rules! const_impl { - { impl $(<$(const $C: ident : $ty: ty), +>)? const $($tt: tt) + } => { - impl $(<$(const $C: $ty), +>)? $($tt) + - } -} - -#[cfg(not(feature = "nightly"))] -macro_rules! const_impl { - { impl $(<$(const $C: ident : $ty: ty), +>)? const $($tt: tt) + } => { - impl $(<$(const $C: $ty), +>)? $($tt) + - } -} - -pub(crate) use const_impl; - macro_rules! option_try { ($e: expr) => { match $e { diff --git a/src/test/macros.rs b/src/test/macros.rs index 6d32962..507f287 100644 --- a/src/test/macros.rs +++ b/src/test/macros.rs @@ -243,3 +243,35 @@ macro_rules! quickcheck_from_str { } pub(crate) use quickcheck_from_str; + +macro_rules! digit_tests { + { use $Digit: ident digit; $($test_content: tt)* } => { + paste::paste! { + mod [<$Digit _digit_tests>] { + use crate::test::{test_bignum, types::*}; + use crate::test::types::big_types::$Digit::*; + + $($test_content)* + } + } + }; +} + +pub(crate) use digit_tests; + +macro_rules! all_digit_tests { + { $($test_content: tt)* } => { + crate::test::digit_tests! { use u8 digit; $($test_content)* } + + #[cfg(not(test_int_bits = "8"))] + crate::test::digit_tests! { use u16 digit; $($test_content)* } + + #[cfg(not(any(test_int_bits = "8", test_int_bits = "16")))] + crate::test::digit_tests! { use u32 digit; $($test_content)* } + + #[cfg(not(any(test_int_bits = "8", test_int_bits = "16", test_int_bits = "32")))] + crate::test::digit_tests! { use u64 digit; $($test_content)* } + } +} + +pub(crate) use all_digit_tests; \ No newline at end of file diff --git a/src/test/types.rs b/src/test/types.rs index 2c01469..fb5d255 100644 --- a/src/test/types.rs +++ b/src/test/types.rs @@ -20,46 +20,78 @@ pub mod big_types { }; } - #[cfg(test_int_bits = "64")] - big_types_modules!(64); + #[cfg(test_int_bits = "16")] + big_types_modules!(16); + + #[cfg(test_int_bits = "32")] + big_types_modules!(32); - #[cfg(not(test_int_bits = "64"))] + #[cfg(test_int_bits = "128")] big_types_modules!(128); + + #[cfg(not(any(test_int_bits = "16", test_int_bits = "32", test_int_bits = "128")))] + big_types_modules!(64); } -#[cfg(test_int_bits = "64")] +#[cfg(test_int_bits = "16")] mod small_types { #[allow(non_camel_case_types)] pub type utest = u64; #[allow(non_camel_case_types)] pub type itest = i64; + + #[cfg(feature = "float")] + #[allow(non_camel_case_types)] + pub type ftest = f16; +} + +#[cfg(test_int_bits = "32")] +mod small_types { + #[allow(non_camel_case_types)] + pub type utest = u64; + + #[allow(non_camel_case_types)] + pub type itest = i64; + + #[cfg(feature = "float")] + #[allow(non_camel_case_types)] + pub type ftest = f32; } -#[cfg(not(test_int_bits = "64"))] +#[cfg(test_int_bits = "128")] mod small_types { #[allow(non_camel_case_types)] pub type utest = u128; #[allow(non_camel_case_types)] pub type itest = i128; + + #[cfg(feature = "float")] + #[allow(non_camel_case_types)] + pub type ftest = f128; } -pub use core::primitive::*; -pub use small_types::*; +#[cfg(not(any(test_int_bits = "16", test_int_bits = "32", test_int_bits = "128")))] // default is 64 +mod small_types { + #[allow(non_camel_case_types)] + pub type utest = u64; -#[cfg(test_int_bits = "64")] -#[allow(non_camel_case_types)] -pub type ftest = f64; + #[allow(non_camel_case_types)] + pub type itest = i64; -#[cfg(not(test_int_bits = "64"))] -#[allow(non_camel_case_types)] -pub type ftest = f32; + #[cfg(feature = "float")] + #[allow(non_camel_case_types)] + pub type ftest = f64; +} + +pub use core::primitive::*; +pub use small_types::*; #[cfg(feature = "float")] -#[cfg(test_int_bits = "64")] +#[cfg(not(test_int_bits = "32"))] pub type FTEST = crate::float::Float<8, 52>; #[cfg(feature = "float")] -#[cfg(not(test_int_bits = "64"))] +#[cfg(test_int_bits = "32")] pub type FTEST = crate::float::Float<4, 23>; \ No newline at end of file