Is there a way to reinterpret a Float64 to 2 Int32?

This is A way, but I find it doubtful it’s the best way, and possibly it’s buggy. I extended Elrod’s code to (his SIMD code doesn’t have the shift issue, but it (currently) ties you to x86, my code should work everywere):

other_half(x) = (reinterpret(Int, x) >> 32) % Int32

julia> @code_native other_half(x) # ok, I'm doubt the shift can be avoided.

This might be alternative code to consider:
julia> f(x) = (reinterpret(UInt64, x) & typemax(UInt32) << 32) % Int32

I have two concerns with your code. a) [x] assumes x is in memory? I guess the compiler is careful either way, but if your value is in a register it would force it stored in memory? b) It seems it depends on endianness, and the order you get is for little-endian. It could be reversed, in some theoretical (not yet supported) big-endian platform?

I used @code_native on your code, and it seems longer than I would want, and @code_lowered is way longer.

Similar for splitting Float32:

julia> both_half(x::Float32) = ((reinterpret(UInt32, x) >> 16), reinterpret(UInt32, x) % Int16)

Julia still does a shift, here by 16, and it should be avoidable, as x86 assembly has access to lower 16 bits, and higher 16 bits of the same register (but not higher 32-bits of 64 bit register without shifting), so Julia’s code generator could in theory do something slightly better (doesn’t not even on -O3). [I don’t see a way around it otherwise, except maybe with injecting LLVM code.] I’m assuming x86 register set and not SIMD, I just don’t recall, such likely might avoid generating a shift on x86 (in case Julia’s code generator tried to exploit such SIMD feature), even for 32-bit, and probably even ARM, without ARM would need a shift.

1 Like