diff --git a/library/core/src/num/imp/bignum.rs b/library/core/src/num/imp/bignum.rs index 9e930ed15a234..95046e96fc8f2 100644 --- a/library/core/src/num/imp/bignum.rs +++ b/library/core/src/num/imp/bignum.rs @@ -1,7 +1,7 @@ //! Custom arbitrary-precision number (bignum) implementation. //! //! This is designed to avoid the heap allocation at expense of stack memory. -//! The most used bignum type, `Big32x40`, is limited by 32 × 40 = 1,280 bits +//! The most used bignum type, `Big32x40` and `Big64x20` you can choose, is limited by 32 × 40 = 1,280 bits //! and will take at most 160 bytes of stack memory. This is more than enough //! for round-tripping all possible finite `f64` values. //! @@ -61,9 +61,10 @@ impl_full_ops! { u64: add(intrinsics::u64_add_with_overflow), mul/div(u128); } -/// Table of powers of 5 representable in digits. Specifically, the largest {u8, u16, u32} value +/// Table of powers of 5 representable in digits. Specifically, the largest {u8, u16, u32, u64} value /// that's a power of five, plus the corresponding exponent. Used in `mul_pow5`. -const SMALL_POW5: [(u64, usize); 3] = [(125, 3), (15625, 6), (1_220_703_125, 13)]; +const SMALL_POW5: [(u64, usize); 4] = + [(125, 3), (15625, 6), (1_220_703_125, 13), (7_450_580_596_923_828_125, 27)]; macro_rules! define_bignum { ($name:ident: type=$ty:ty, n=$n:expr) => { @@ -100,7 +101,7 @@ macro_rules! define_bignum { let mut sz = 0; while v > 0 { base[sz] = v as $ty; - v >>= <$ty>::BITS; + v = v.unbounded_shr(<$ty>::BITS); sz += 1; } $name { size: sz, base } @@ -382,11 +383,28 @@ macro_rules! define_bignum { }; } -/// The digit type for `Big32x40`. +/// the digit type for `Big32x40` pub type Digit32 = u32; +#[cfg(target_pointer_width = "32")] define_bignum!(Big32x40: type=Digit32, n=40); +/// The digit type for `Big64x20`. +pub type Digit64 = u64; + +#[cfg(target_pointer_width = "64")] +define_bignum!(Big64x20: type=Digit64, n=20); + +#[cfg(target_pointer_width = "32")] +pub type Big = Big32x40; +#[cfg(target_pointer_width = "64")] +pub type Big = Big64x20; + +#[cfg(target_pointer_width = "32")] +pub type Digit = Digit32; +#[cfg(target_pointer_width = "64")] +pub type Digit = Digit64; + // this one is used for testing only. #[doc(hidden)] pub mod tests { diff --git a/library/core/src/num/imp/flt2dec/strategy/dragon.rs b/library/core/src/num/imp/flt2dec/strategy/dragon.rs index de19ca6bb664d..4ae0d4b4ab0ba 100644 --- a/library/core/src/num/imp/flt2dec/strategy/dragon.rs +++ b/library/core/src/num/imp/flt2dec/strategy/dragon.rs @@ -9,24 +9,56 @@ use flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; use crate::cmp::Ordering; use crate::mem::MaybeUninit; -use crate::num::imp::bignum::{Big32x40 as Big, Digit32 as Digit}; +use crate::num::imp::bignum::{Big, Digit}; use crate::num::imp::flt2dec; static POW10: [Digit; 10] = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000]; // precalculated arrays of `Digit`s for 5^(2^n). +// FIXME(#162879): these tables have u64 and u32 versions, future versions may be generated by macro. +#[cfg(target_pointer_width = "32")] static POW5TO16: [Digit; 2] = [0x86f26fc1, 0x23]; +#[cfg(target_pointer_width = "64")] +static POW5TO16: [Digit; 1] = [0x2386f26fc1]; + +#[cfg(target_pointer_width = "32")] static POW5TO32: [Digit; 3] = [0x85acef81, 0x2d6d415b, 0x4ee]; +#[cfg(target_pointer_width = "64")] +static POW5TO32: [Digit; 2] = [0x2d6d415b85acef81, 0x4ee]; + +#[cfg(target_pointer_width = "32")] static POW5TO64: [Digit; 5] = [0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, 0xe93ff9f4, 0x184f03]; +#[cfg(target_pointer_width = "64")] +static POW5TO64: [Digit; 3] = [0x6e38ed64bf6a1f01, 0xe93ff9f4daa797ed, 0x184f03]; + +#[cfg(target_pointer_width = "32")] static POW5TO128: [Digit; 10] = [ 0x2e953e01, 0x3df9909, 0xf1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08, 0xbccdb0da, 0xa6337f19, 0xe91f2603, 0x24e, ]; +#[cfg(target_pointer_width = "64")] +static POW5TO128: [Digit; 5] = + [0x3df99092e953e01, 0x2374e42f0f1538fd, 0xc404dc08d3cff5ec, 0xa6337f19bccdb0da, 0x24ee91f2603]; + +#[cfg(target_pointer_width = "32")] static POW5TO256: [Digit; 19] = [ 0x982e7c01, 0xbed3875b, 0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70, 0xd595d80f, 0x26b2716e, 0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, 0xcc5573c0, 0x65f9ef17, 0x55bc28f2, 0x80dcc7f7, 0xf46eeddc, 0x5fdcefce, 0x553f7, ]; +#[cfg(target_pointer_width = "64")] +static POW5TO256: [Digit; 10] = [ + 0xbed3875b982e7c01, + 0x12152f87d8d99f72, + 0xcf4a6e706bde50c6, + 0x26b2716ed595d80f, + 0x1d153624adc666b0, + 0x63ff540e3c42d35a, + 0x65f9ef17cc5573c0, + 0x80dcc7f755bc28f2, + 0x5fdcefcef46eeddc, + 0x553f7, +]; #[doc(hidden)] pub fn mul_pow10(x: &mut Big, n: usize) -> &mut Big { diff --git a/library/coretests/tests/num/bignum.rs b/library/coretests/tests/num/bignum.rs index 2b4c30cc261cb..cabc88821a907 100644 --- a/library/coretests/tests/num/bignum.rs +++ b/library/coretests/tests/num/bignum.rs @@ -1,4 +1,4 @@ -use core::num::imp::bignum::Big32x40; +use core::num::imp::bignum::Big as BigFull; use core::num::imp::bignum::tests::Big8x3 as Big; #[test] @@ -216,27 +216,27 @@ fn test_bit_length() { } #[test] -fn test_bit_length_32x40() { +fn test_bit_length_big() { for i in 0..32 * 40 { // 010000...000 - assert_eq!(Big32x40::from_small(1).mul_pow2(i).bit_length(), i + 1); + assert_eq!(BigFull::from_small(1).mul_pow2(i).bit_length(), i + 1); } for i in 1..32 * 40 - 1 { // 010000...001 assert_eq!( - Big32x40::from_small(1).mul_pow2(i).add(&Big32x40::from_small(1)).bit_length(), + BigFull::from_small(1).mul_pow2(i).add(&BigFull::from_small(1)).bit_length(), i + 1 ); // 110000...000 - assert_eq!(Big32x40::from_small(3).mul_pow2(i).bit_length(), i + 2); + assert_eq!(BigFull::from_small(3).mul_pow2(i).bit_length(), i + 2); } - assert_eq!(Big32x40::from_small(0).bit_length(), 0); - assert_eq!(Big32x40::from_small(1).bit_length(), 1); - assert_eq!(Big32x40::from_small(5).bit_length(), 3); - assert_eq!(Big32x40::from_small(0x18).bit_length(), 5); - assert_eq!(Big32x40::from_u64(0x4073).bit_length(), 15); - assert_eq!(Big32x40::from_u64(0xffffff).bit_length(), 24); - assert_eq!(Big32x40::from_u64(0xffffffffffffffff).bit_length(), 64); + assert_eq!(BigFull::from_small(0).bit_length(), 0); + assert_eq!(BigFull::from_small(1).bit_length(), 1); + assert_eq!(BigFull::from_small(5).bit_length(), 3); + assert_eq!(BigFull::from_small(0x18).bit_length(), 5); + assert_eq!(BigFull::from_u64(0x4073).bit_length(), 15); + assert_eq!(BigFull::from_u64(0xffffff).bit_length(), 24); + assert_eq!(BigFull::from_u64(0xffffffffffffffff).bit_length(), 64); } #[test] diff --git a/library/coretests/tests/num/flt2dec/strategy/dragon.rs b/library/coretests/tests/num/flt2dec/strategy/dragon.rs index 886f50064a503..395f8e082e655 100644 --- a/library/coretests/tests/num/flt2dec/strategy/dragon.rs +++ b/library/coretests/tests/num/flt2dec/strategy/dragon.rs @@ -1,4 +1,4 @@ -use core::num::imp::bignum::Big32x40 as Big; +use core::num::imp::bignum::Big; use core::num::imp::flt2dec::strategy::dragon::*; use super::super::*;