我想在 Rust 中计算以下内容:
Python 等效项:
math.ceil(math.log(b+1, 2))
我努力了:
a+1.log2() 
(a+1).log2() 
但我得到了错误use of unstable library feature 'int_log'。我不想使用不稳定的库功能。如果可能的话,在没有任何外部板条箱的情况下计算 log2 最简单的方法是什么?
Mic*_*son 12
如果这对时间至关重要,那么您可以利用数据类型的知识来加快速度。
如果输入是正整数(假设 a u64),则几乎log2(x)是最后一个非 1 位的索引,您可以使用 来确定。事实上正是x的最后一个非1位的索引。这给出了:(游乐场)u64::leading_zeroslog2(x+1)
pub fn main() {
    for a in 0..10u64 {
        let v = (a as f32 + 1.).log2().ceil();
        let w = u64::BITS - a.leading_zeros();
        println!("{} {} {}", a, v, w);
    }
}
输出
0 0 0
1 1 1
2 2 2
3 2 2
4 3 3
5 3 3
6 3 3
7 3 3
8 4 4
9 4 4
处理有符号数字(如 )的符号位时需要多加小心i64。
如果您的数字是浮点值,您仍然可以使用一些技巧来加快速度,特别是如果您不愿意处理 NaN、Inf 和非规范化数字。
特别是,对于 f64,“正常”数字的位模式是 52 位“小数”、11 位尾数和 1 位符号位。调用尾数的 11 位,e浮点数的值为(sign)*(1+fraction/2^52)*2^(e-1023)
所以log2(x) = log2(1+fraction/2^52) + (e-1023)。
部分e-1023为整数,其余为0<=log2(1+fraction/2^52)<1,当 时为零fraction==0。所以ceil(log2(x)) = if fraction==0 {e-1023} else {e-1022}。
这给了我们这个:
pub fn main() {
    for a in -20..20i64 {
        let f = (a as f64)/4.0 + 1.0;
        let v = f.log2().ceil();
        let b: u64 = f.to_bits();
        let s = (b >> 63) & 1;
        let e = (b >> 52) & ((1<<11)-1);
        let frac = b & ((1<<52) -1);
        let z = if frac==0 { e as i64 - 1023 } else { e as i64 -1022 };
        println!("{:0.2} {:064b} : {:01b} {:011b} {:052b} {} {}", f, b, s, e, frac, z, v);
    }
}
其输出(在修剪掉位表示之后)
...
-0.75 ... -2 -2
-0.50 ... -1 -1
-0.25 ... 0 -0
 0.00 ... 0 0
 0.25 ... 1 1
 0.50 ... 1 1
 0.75 ... 1 1
 1.00 ... 1 1
 1.25 ... 2 2
 1.50 ... 2 2
 1.75 ... 2 2
 2.00 ... 2 2
...
同样,只有当 1+a 是普通数时,这才成立。如果需要,您需要添加条件来处理这些情况。(除非您确定不需要,否则您应该这样做)。
类似的技巧可用于 u32 和 f32 类型。
Rust 非常注重整数和浮点数之间的区别。您不能只输入一个整数并期望它自动转换。.始终在浮动末尾添加一个。
似乎您试图对整数调用该函数。尝试这个:
尝试这个:
(1.).log2().ceil()
或者
(a as f32 + 1.).log2().ceil()
如果您希望最终结果为整数,可以as i32在最后使用。如果您想要双精度浮点数,请替换f32为f64.
参考:
https://doc.rust-lang.org/std/primitive.f32.html#method.ceil
https://doc.rust-lang.org/std/primitive.f32.html#method.log2