Multiply by De Bruijn sequence and lookup index

Computing the base‑2 logarithm of an integer (more precisely: finding the index of the highest set bit) is a common operation in systems programming, graphics, data compression, and low‑level algorithms. While Rust provides methods like u32::leading_zeros(), sometimes you may want your own implementation—especially an approach that is branch‑free, fast, and works on all stable targets.

One elegant solution is the De Bruijn bit twiddling method, a classic technique from the world of high‑performance low‑level programming.

fn main() {
    let x = 1024u32;
    println!("log2(1024) = {}", log2_debruijn(x)); // Ausgabe: 10
    println!("log2(256) = {}", log2_debruijn(256)); // Ausgabe: 8
}

const MULTIPLY_DEBRUIJN_BIT_POSITION: [u32; 32] = [
     0,  9,  1, 10, 13, 21,  2, 29,
    11, 14, 16, 18, 22, 25,  3, 30,
     8, 12, 20, 15, 17, 19, 24,  7,
    23,  6, 26,  5, 28,  4, 31, 27,
];

fn log2_debruijn(mut v: u32) -> u32 {
    // propagate highest set bit
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;

    // multiply by De Bruijn sequence and lookup index
    let index = ((v.wrapping_mul(0x07C4ACDD)) >> 27) as usize;

    MULTIPLY_DEBRUIJN_BIT_POSITION[index]
}