4 ms·
Which is actually a useful feature in some obscure optimizations, like this fast (approximate) square root: float half_r=r*0.5F; union { float y;
by SomeCallMeTim 11y ago
Which is actually a useful feature in some obscure optimizations, like this fast (approximate) square root:
float half_r=r*0.5F;
union
{
float y;
int32_t i;
};
y=r;
i=0x5f375a86-(i>>1);
y=y*(1.5F-(half_r*y*y));
return y;
- Scaevolus 11y agoThat hasn't been an optimization for 15 years now. Fast approximate inverse square root is a builtin operation on most FPUs-- on x86, it's RSQRTSS, which tends to be the same cost as a floating point multiply. (for Haswell, it has a 5 cycle latency, and 1 cycle reciprocal throughput)
- SomeCallMeTim 11y agoInteresting, though not useful unless there's a good way to access it from portable C/C++. An __asm__ section or equivalent would work, but would only be useful on a particular CPU -- and different compilers use different syntax for embedding assembly, so that's not ideal either. But where I'd more likely use that optimization at this point is on Arm or ATmega processors. ARM doesn't seem to have an approximate inverse square root, based on a quick check, and ATmega are frequently still stuck with software floating point, so I'd hardly say that the optimization is dead.
- JoshTriplett 11y agoIf you want to reinterpret a float as an integer or vice versa, you can do that easily enough with Rust's unsafe functions: fn approx_invsqrt(r : f32) -> f32 { let y : f32 = unsafe { let i : i32 = std::mem::transmute(r); std::mem::transmute(0x5f375a86 - (i>>1)) }; return y*(1.5-(0.5*r*y*y)); } fn main() { println!("approx_invsqrt(2.0) = {}", approx_invsqrt(2.0)); } Result: approx_invsqrt(2.0) = 0.70693
- kzrdude 11y agoAnd Rust specifies their floats to be IEEE 754, so it always works (endianness may apply though).
- JoshTriplett 11y agoSeems reasonably safe to assume that i32 and f32 have the same endianness.