some log10 optimizations

This commit is contained in:
Trevor Spiteri 2020-04-13 04:27:36 +02:00
parent a32b56ab43
commit b0f6deab9e
1 changed files with 71 additions and 24 deletions

View File

@ -99,6 +99,26 @@ fn int_part_log10_less_than_8(mut i: u32) -> i32 {
}
}
fn frac_part_log10_greater_equal_m8(mut i: u32) -> i32 {
const MAX: u32 = u32::max_value();
debug_assert!(i > MAX / 100_000_000);
let mut log = 0;
if i <= MAX / 10_000 {
i *= 10_000;
log += -4;
}
log + if i > MAX / 10 {
-1
} else if i > MAX / 100 {
-2
} else if i > MAX / 1000 {
-3
} else {
debug_assert!(i > MAX / 10_000);
-4
}
}
impl IntFracLog10 for u32 {
fn int_part_log10(mut self) -> i32 {
let mut log = 0;
@ -116,20 +136,7 @@ impl IntFracLog10 for u32 {
self *= 100_000_000;
log += -8;
}
if self <= MAX / 10_000 {
self *= 10_000;
log += -4;
}
log + if self > MAX / 10 {
-1
} else if self > MAX / 100 {
-2
} else if self > MAX / 1000 {
-3
} else {
debug_assert!(self > MAX / 10_000);
-4
}
log + frac_part_log10_greater_equal_m8(self)
}
}
@ -145,6 +152,34 @@ fn int_part_log10_less_than_16(mut i: u64) -> i32 {
log + int_part_log10_less_than_8(i as u32)
}
// This is only used by u128::frac_part_log10, not by
// u64::frac_part_log10 where we can actually skip the two initial
// comparisons when we already have log = -16.
#[inline]
fn frac_part_log10_greater_equal_m16(mut i: u64) -> i32 {
const MAX: u64 = u64::max_value();
debug_assert!(i > MAX / 10_000_000_000_000_000);
let mut log = 0;
if i <= MAX / 100_000_000 {
i *= 100_000_000;
log += -8;
}
if i <= MAX / 10_000 {
i *= 10_000;
log += -4;
}
log + if i > MAX / 10 {
-1
} else if i > MAX / 100 {
-2
} else if i > MAX / 1000 {
-3
} else {
debug_assert!(i > MAX / 10_000);
-4
}
}
impl IntFracLog10 for u64 {
fn int_part_log10(mut self) -> i32 {
let mut log = 0;
@ -159,16 +194,22 @@ impl IntFracLog10 for u64 {
const MAX: u64 = u64::max_value();
let mut log = 0;
if self <= MAX / 10_000_000_000_000_000 {
log += -16;
// After this, self >= 10^16 > MAX / 10^4 == 1.84 × 10^15.
self *= 10_000_000_000_000_000;
}
if self <= MAX / 100_000_000 {
log += -8;
self *= 100_000_000;
}
if self <= MAX / 10_000 {
log += -4;
self *= 10_000;
log += -16;
} else {
if self <= MAX / 100_000_000 {
self *= 100_000_000;
log += -8;
}
if self <= MAX / 10_000 {
self *= 10_000;
log += -4;
}
if log <= -12 {
// At this point log can only go down by a further 8.
return log + frac_part_log10_greater_equal_m8((self >> 32) as u32);
}
}
log + if self > MAX / 10 {
-1
@ -202,8 +243,10 @@ impl IntFracLog10 for u128 {
const MAX: u128 = u128::max_value();
let mut log = 0;
if self <= MAX / 100_000_000_000_000_000_000_000_000_000_000 {
log += -32;
self *= 100_000_000_000_000_000_000_000_000_000_000;
log += -32;
// At this point log can only go down by a further 7.
return log + frac_part_log10_greater_equal_m8((self >> 96) as u32);
}
if self <= MAX / 10_000_000_000_000_000 {
log += -16;
@ -213,6 +256,10 @@ impl IntFracLog10 for u128 {
log += -8;
self *= 100_000_000;
}
if log <= -24 {
// At this point log can only go down by a further 15.
return log + frac_part_log10_greater_equal_m16((self >> 64) as u64);
}
if self <= MAX / 10_000 {
log += -4;
self *= 10_000;