Comment

Comment by cormacrelf

For 32 bit floats, you can skip the math and just test all of them. LLVM will vectorise and unroll this nicely.

    fn main() {
        let start = std::time::Instant::now();
        let total = (0..=u32::MAX)
            .filter(|&x| {
                let f = f32::from_bits(x);
                0. <= f && f <= 1.
            })
            .count();
        println!("total {total} in {:?}", start.elapsed());
    }

    total 1065353218 in 1.364751583s
Edit: Apparently if you move the sum to its own function it runs in 500ms. A bit temperamental.

Edit 2: it's the size of the sum accumulator that makes it slow. The version above is like `.fold(0usize, |a, _| a + 1)`. When I moved it to another function, I cast the return value to u32, so LLVM saw basically `.fold(0u32, |a, _| a + 1)` and could use u32 throughout. Godbolt says the usize version ends up with floats in xmm* registers on x86, which fit 4 32-bit floats, but the u32 version ends up with floats in ymm* registers (8 32-bit floats) and similar half-as-wide behaviour on ARM.

parent cormacrelf 3 years ago

Discussion

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton