Rust 中 Log2 的计算单元

cpi*_*pix 1 rust

我想在 Rust 中计算以下内容:

Python 等效项:

math.ceil(math.log(b+1, 2))
Run Code Online (Sandbox Code Playgroud)

ceil(log_2 n+1)

我努力了:

a+1.log2() 
(a+1).log2() 
Run Code Online (Sandbox Code Playgroud)

但我得到了错误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);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出

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
Run Code Online (Sandbox Code Playgroud)

处理有符号数字(如 )的符号位时需要多加小心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);
    }
}
Run Code Online (Sandbox Code Playgroud)

其输出(在修剪掉位表示之后)

...
-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
...
Run Code Online (Sandbox Code Playgroud)

同样,只有当 1+a 是普通数时,这才成立。如果需要,您需要添加条件来处理这些情况。(除非您确定不需要,否则您应该这样做)。

类似的技巧可用于 u32 和 f32 类型。


mou*_*ail 5

Rust 非常注重整数和浮点数之间的区别。您不能只输入一个整数并期望它自动转换。.始终在浮动末尾添加一个。

似乎您试图对整数调用该函数。尝试这个:

尝试这个:

(1.).log2().ceil()
Run Code Online (Sandbox Code Playgroud)

或者

(a as f32 + 1.).log2().ceil()
Run Code Online (Sandbox Code Playgroud)

如果您希望最终结果为整数,可以as i32在最后使用。如果您想要双精度浮点数,请替换f32f64.

参考:

https://doc.rust-lang.org/std/primitive.f32.html#method.ceil

https://doc.rust-lang.org/std/primitive.f32.html#method.log2

  • 我认为 `f32::from`/`f32::try_from` 更可取,因为它们指示转换是否保证成功。另一方面,“as”似乎总是成功,但也可能不会成功(例如,如果“a”是“u64”)。我的印象是,如果他们可以重做一遍,“as”将仅适用于原始指针和少数其他类型,但不适用于整数基元。 (2认同)