我试图在rust中获得int
的长度(以十进制解释时的位数)。我找到了一种方法来做到这一点,但是我正在寻找来自原始本身的方法。这是我的文件:
let num = 90.to_string();
println!("num: {}", num.chars().count())
// num: 2
我正在看https://docs.rs/digits/0.3.3/digits/struct.Digits.html#method.length。这是一个好的候选人吗?我如何使用它?还是有其他的板条箱可以帮我?
用更少的类型转换的一行是我正在寻找的理想解决方案。
您可以循环并检查在该数字变为个位数之前可以将其除以10的次数。或者在另一个方向上(因为除法比乘法慢),检查10*10*...*10
相乘的频率,直到达到数字:
fn length(n: u32, base: u32) -> u32 {
let mut power = base;
let mut count = 1;
while n >= power {
count += 1;
if let Some(new_power) = power.checked_mul(base) {
power = new_power;
} else {
break;
}
}
count
}
从rust 1.67开始,可以使用:
n.checked_ilog10().unwrap_or(0) + 1
下面是不需要字符串或浮点数的一行代码:
println!("num: {}", successors(Some(n), |&n| (n >= 10).then(|| n / 10)).count());
它只是计算初始数除以10得到0的次数。
编辑:这个答案的第一个版本使用iterate
来自(优秀和强烈推荐)itertools
crate,但@trentcl指出successors
来自stdlib做同样的事情。作为参考,下面是使用iterate
的版本:
println!("num: {}", iterate(n, |&n| n / 10).take_while(|&n| n > 0).count().max(1));
这里有一个(几乎)比字符串转换更快的一行代码,使用std::iter:
let some_int = 9834;
let decimal_places = (0..).take_while(|i| 10u64.pow(*i) <= some_int).count();
下面的第一种方法依赖于以下公式,其中a
和b
是对数底。
log<a>( x ) = log<b>( x ) / log<b>( a )
log<a>( x ) = log<2>( x ) / log<2>( a ) // Substituting 2 for `b`.
下面的函数可用于求2的幂的基数的位数。这种方法非常快。
fn num_digits_base_pow2(n: u64, b: u32) -> u32
{
(63 - n.leading_zeros()) / (31 - b.leading_zeros()) + 1
}
对n
(我们想要表示的数字)和b
(基数)的位进行计数,以找到它们的log2下限值。然后,这些值的调整比率给出了期望基数中的天花板对数值。
对于查找任意进制的位数的通用方法,以下内容应该足够了。
fn num_digits(n: u64, b: u32) -> u32
{
(n as f64).log(b as f64).ceil() as u32
}
如果num已签名:
let digits = (num.abs() as f64 + 0.1).log10().ceil() as u32;
数字的一个很好的性质,总是很好记住的是,在进制$n$中写一个数字$x$所需的位数实际上是$lceil log_n(x + 1) rceil$。
因此,可以简单地编写以下函数(注意从u32
到f32
的转换,因为整数没有日志函数):
fn length(n: u32, base: u32) -> u32 {
let n = (n+1) as f32;
n.log(base as f32).ceil() as u32
}
你可以很容易地将它用于负数。对于浮点数,这可能有点(即很多)更棘手。
考虑Daniel关于使用f32引入的病理情况的评论,请注意,在夜间Rust中,整数具有对数方法。(请注意,在我看来,这些都是实现的细节,你应该更多地关注于理解算法而不是实现。):
#![feature(int_log)]
fn length(n: u32, base: u32) -> u32 {
n.log(base) + 1
}