Auto merge of #86930 - tspiteri:int_log10, r=kennytm
special case for integer log10 Now that #80918 has been merged, this PR provides a faster version of `log10`. The PR also adds some tests for values close to all powers of 10.
This commit is contained in:
commit
8b87e85394
5 changed files with 198 additions and 3 deletions
134
library/core/src/num/int_log10.rs
Normal file
134
library/core/src/num/int_log10.rs
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
mod unchecked {
|
||||
// 0 < val <= u8::MAX
|
||||
pub const fn u8(val: u8) -> u32 {
|
||||
if val >= 100 {
|
||||
2
|
||||
} else if val >= 10 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
// 0 < val <= u16::MAX
|
||||
pub const fn u16(val: u16) -> u32 {
|
||||
if val >= 10_000 {
|
||||
4
|
||||
} else if val >= 1000 {
|
||||
3
|
||||
} else if val >= 100 {
|
||||
2
|
||||
} else if val >= 10 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
// 0 < val < 100_000_000
|
||||
const fn less_than_8(mut val: u32) -> u32 {
|
||||
let mut log = 0;
|
||||
if val >= 10_000 {
|
||||
val /= 10_000;
|
||||
log += 4;
|
||||
}
|
||||
log + if val >= 1000 {
|
||||
3
|
||||
} else if val >= 100 {
|
||||
2
|
||||
} else if val >= 10 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
// 0 < val <= u32::MAX
|
||||
pub const fn u32(mut val: u32) -> u32 {
|
||||
let mut log = 0;
|
||||
if val >= 100_000_000 {
|
||||
val /= 100_000_000;
|
||||
log += 8;
|
||||
}
|
||||
log + less_than_8(val)
|
||||
}
|
||||
|
||||
// 0 < val < 10_000_000_000_000_000
|
||||
const fn less_than_16(mut val: u64) -> u32 {
|
||||
let mut log = 0;
|
||||
if val >= 100_000_000 {
|
||||
val /= 100_000_000;
|
||||
log += 8;
|
||||
}
|
||||
log + less_than_8(val as u32)
|
||||
}
|
||||
|
||||
// 0 < val <= u64::MAX
|
||||
pub const fn u64(mut val: u64) -> u32 {
|
||||
let mut log = 0;
|
||||
if val >= 10_000_000_000_000_000 {
|
||||
val /= 10_000_000_000_000_000;
|
||||
log += 16;
|
||||
}
|
||||
log + less_than_16(val)
|
||||
}
|
||||
|
||||
// 0 < val <= u128::MAX
|
||||
pub const fn u128(mut val: u128) -> u32 {
|
||||
let mut log = 0;
|
||||
if val >= 100_000_000_000_000_000_000_000_000_000_000 {
|
||||
val /= 100_000_000_000_000_000_000_000_000_000_000;
|
||||
log += 32;
|
||||
return log + less_than_8(val as u32);
|
||||
}
|
||||
if val >= 10_000_000_000_000_000 {
|
||||
val /= 10_000_000_000_000_000;
|
||||
log += 16;
|
||||
}
|
||||
log + less_than_16(val as u64)
|
||||
}
|
||||
|
||||
// 0 < val <= i8::MAX
|
||||
pub const fn i8(val: i8) -> u32 {
|
||||
u8(val as u8)
|
||||
}
|
||||
|
||||
// 0 < val <= i16::MAX
|
||||
pub const fn i16(val: i16) -> u32 {
|
||||
u16(val as u16)
|
||||
}
|
||||
|
||||
// 0 < val <= i32::MAX
|
||||
pub const fn i32(val: i32) -> u32 {
|
||||
u32(val as u32)
|
||||
}
|
||||
|
||||
// 0 < val <= i64::MAX
|
||||
pub const fn i64(val: i64) -> u32 {
|
||||
u64(val as u64)
|
||||
}
|
||||
|
||||
// 0 < val <= i128::MAX
|
||||
pub const fn i128(val: i128) -> u32 {
|
||||
u128(val as u128)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_checked {
|
||||
($T:ident) => {
|
||||
pub const fn $T(val: $T) -> Option<$T> {
|
||||
if val > 0 { Some(unchecked::$T(val) as $T) } else { None }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_checked! { u8 }
|
||||
impl_checked! { u16 }
|
||||
impl_checked! { u32 }
|
||||
impl_checked! { u64 }
|
||||
impl_checked! { u128 }
|
||||
impl_checked! { i8 }
|
||||
impl_checked! { i16 }
|
||||
impl_checked! { i32 }
|
||||
impl_checked! { i64 }
|
||||
impl_checked! { i128 }
|
||||
|
|
@ -1929,7 +1929,10 @@ macro_rules! int_impl {
|
|||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn checked_log10(self) -> Option<Self> {
|
||||
self.checked_log(10)
|
||||
match int_log10::$ActualT(self as $ActualT) {
|
||||
Some(s) => Some(s as Self),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the absolute value of `self`.
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ mod int_macros; // import int_impl!
|
|||
mod uint_macros; // import uint_impl!
|
||||
|
||||
mod error;
|
||||
mod int_log10;
|
||||
mod nonzero;
|
||||
mod wrapping;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
macro_rules! uint_impl {
|
||||
($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr,
|
||||
($SelfT:ty, $ActualT:ident, $BITS:expr, $MaxV:expr,
|
||||
$rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
|
||||
$reversed:expr, $le_bytes:expr, $be_bytes:expr,
|
||||
$to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
|
||||
|
|
@ -819,7 +819,10 @@ macro_rules! uint_impl {
|
|||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn checked_log10(self) -> Option<Self> {
|
||||
self.checked_log(10)
|
||||
match int_log10::$ActualT(self as $ActualT) {
|
||||
Some(s) => Some(s as Self),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checked negation. Computes `-self`, returning `None` unless `self ==
|
||||
|
|
|
|||
|
|
@ -97,3 +97,57 @@ fn checked_log10() {
|
|||
assert_eq!(i.checked_log10(), Some((i as f32).log10() as u16));
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! log10_loop {
|
||||
($T:ty, $log10_max:expr) => {
|
||||
assert_eq!(<$T>::MAX.log10(), $log10_max);
|
||||
for i in 0..=$log10_max {
|
||||
let p = (10 as $T).pow(i as u32);
|
||||
if p >= 10 {
|
||||
assert_eq!((p - 9).log10(), i - 1);
|
||||
assert_eq!((p - 1).log10(), i - 1);
|
||||
}
|
||||
assert_eq!(p.log10(), i);
|
||||
assert_eq!((p + 1).log10(), i);
|
||||
if p >= 10 {
|
||||
assert_eq!((p + 9).log10(), i);
|
||||
}
|
||||
|
||||
// also check `x.log(10)`
|
||||
if p >= 10 {
|
||||
assert_eq!((p - 9).log(10), i - 1);
|
||||
assert_eq!((p - 1).log(10), i - 1);
|
||||
}
|
||||
assert_eq!(p.log(10), i);
|
||||
assert_eq!((p + 1).log(10), i);
|
||||
if p >= 10 {
|
||||
assert_eq!((p + 9).log(10), i);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn log10_u8() {
|
||||
log10_loop! { u8, 2 }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn log10_u16() {
|
||||
log10_loop! { u16, 4 }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn log10_u32() {
|
||||
log10_loop! { u32, 9 }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn log10_u64() {
|
||||
log10_loop! { u64, 19 }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn log10_u128() {
|
||||
log10_loop! { u128, 38 }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue