Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions library/core/src/num/imp/bignum.rs
Original file line number Diff line number Diff line change
@@ -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.
//!
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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 }
Expand Down Expand Up @@ -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;
Comment thread
clarfonthey marked this conversation as resolved.

#[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 {
Expand Down
34 changes: 33 additions & 1 deletion library/core/src/num/imp/flt2dec/strategy/dragon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Comment thread
clarfonthey marked this conversation as resolved.
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 {
Expand Down
24 changes: 12 additions & 12 deletions library/coretests/tests/num/bignum.rs
Original file line number Diff line number Diff line change
@@ -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]
Expand Down Expand Up @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion library/coretests/tests/num/flt2dec/strategy/dragon.rs
Original file line number Diff line number Diff line change
@@ -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::*;
Expand Down
Loading