Skip to content

Commit 0951fd1

Browse files
committed
Add disguised-fast-path optimisation + tests
1 parent 4680af7 commit 0951fd1

File tree

3 files changed

+41
-6
lines changed

3 files changed

+41
-6
lines changed

src/float.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub trait Float:
3131
const MAX_EXPONENT_ROUND_TO_EVEN: i32;
3232
const MIN_EXPONENT_FAST_PATH: i64;
3333
const MAX_EXPONENT_FAST_PATH: i64;
34+
const MAX_EXPONENT_DISGUISED_FAST_PATH: i64;
3435
const MINIMUM_EXPONENT: i32;
3536
const INFINITE_POWER: i32;
3637
const SIGN_INDEX: usize;
@@ -56,6 +57,7 @@ impl Float for f32 {
5657
const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10;
5758
const MIN_EXPONENT_FAST_PATH: i64 = -10; // assuming FLT_EVAL_METHOD = 0
5859
const MAX_EXPONENT_FAST_PATH: i64 = 10;
60+
const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 17;
5961
const MINIMUM_EXPONENT: i32 = -127;
6062
const INFINITE_POWER: i32 = 0xFF;
6163
const SIGN_INDEX: usize = 31;
@@ -90,6 +92,7 @@ impl Float for f64 {
9092
const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23;
9193
const MIN_EXPONENT_FAST_PATH: i64 = -22; // assuming FLT_EVAL_METHOD = 0
9294
const MAX_EXPONENT_FAST_PATH: i64 = 22;
95+
const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 37;
9396
const MINIMUM_EXPONENT: i32 = -1023;
9497
const INFINITE_POWER: i32 = 0x7FF;
9598
const SIGN_INDEX: usize = 63;

src/number.rs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,25 @@ use crate::float::Float;
33

44
const MIN_19DIGIT_INT: u64 = 100_0000_0000_0000_0000;
55

6+
pub const INT_POW10: [u64; 16] = [
7+
1,
8+
10,
9+
100,
10+
1000,
11+
10000,
12+
100000,
13+
1000000,
14+
10000000,
15+
100000000,
16+
1000000000,
17+
10000000000,
18+
100000000000,
19+
1000000000000,
20+
10000000000000,
21+
100000000000000,
22+
1000000000000000,
23+
];
24+
625
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
726
pub struct Number {
827
pub exponent: i64,
@@ -15,20 +34,31 @@ impl Number {
1534
#[inline]
1635
fn is_fast_path<F: Float>(&self) -> bool {
1736
F::MIN_EXPONENT_FAST_PATH <= self.exponent
18-
&& self.exponent <= F::MAX_EXPONENT_FAST_PATH
37+
&& self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH
1938
&& self.mantissa <= F::MAX_MANTISSA_FAST_PATH
2039
&& !self.many_digits
2140
}
2241

2342
#[inline]
2443
pub fn try_fast_path<F: Float>(&self) -> Option<F> {
2544
if self.is_fast_path::<F>() {
26-
let mut value = F::from_u64(self.mantissa);
27-
if self.exponent < 0 {
28-
value = value / F::pow10_fast_path((-self.exponent) as _);
45+
let mut value = if self.exponent <= F::MAX_EXPONENT_FAST_PATH {
46+
// normal fast path
47+
let value = F::from_u64(self.mantissa);
48+
if self.exponent < 0 {
49+
value / F::pow10_fast_path((-self.exponent) as _)
50+
} else {
51+
value * F::pow10_fast_path(self.exponent as _)
52+
}
2953
} else {
30-
value = value * F::pow10_fast_path(self.exponent as _);
31-
}
54+
// disguised fast path
55+
let shift = self.exponent - F::MAX_EXPONENT_FAST_PATH;
56+
let mantissa = self.mantissa.checked_mul(INT_POW10[shift as usize])?;
57+
if mantissa > F::MAX_MANTISSA_FAST_PATH {
58+
return None;
59+
}
60+
F::from_u64(mantissa) * F::pow10_fast_path(F::MAX_EXPONENT_FAST_PATH as _)
61+
};
3262
if self.negative {
3363
value = -value;
3464
}

tests/test_basic.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ fn test_f64_general() {
277277
check_f64!(4503599627370497.5);
278278
check_f64!(45035996.273704995);
279279
check_f64!(45035996.273704985);
280+
check_f64!(1.2345e30);
280281
}
281282

282283
#[test]
@@ -402,6 +403,7 @@ fn test_f32_basic() {
402403
0.000000000000000000000000000000000000011754942106924410754870294448492873488270\
403404
52428745893333857174530571588870475618904265502351336181163787841796875"
404405
);
406+
check_f32!(1.2345e15);
405407
}
406408

407409
#[test]

0 commit comments

Comments
 (0)