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

I’m writing some manually vectorize some code (for computing `exp`), and I was looking for a way to view the memory as 2 int32s (if it helps, I only need the lower one). Is there a way to do this? The reason I want Int32 rather than int64 is because I want the integer stuff to work with avx2.

``````julia> x = 3.0
3.0

julia> reinterpret(Int32, [x])
2-element reinterpret(Int32, ::Array{Float64,1}):
0
1074266112
``````
3 Likes
``````julia> x = rand()
0.22542595261993403

julia> bitstring(x)
"0011111111001100110110101100000111110011000101100000110010110000"

julia> reinterpret(Int, x) % Int32
-216658768

julia> bitstring(ans)
"11110011000101100000110010110000"
``````

Similarly, you can:

``````julia> using VectorizationBase, SIMDPirates

julia> sx = SVec(ntuple(VectorizationBase.pick_vector_width_val(Float64)) do _ Core.VecElement(10randn(Float64)) end)
SVec{8,Float64}<11.591414148467251, -16.471476122659084, -5.030081855765106, -8.60206169897962, -17.824076876082163, -12.363521352234141, 1.0686657131481578, 7.031664824493625>

julia> reinterpret(SVec{length(sx),Int}, sx) % Int32
SVec{8,Int32}<-707518984, -1463834008, -953492670, 1851168085, -1279252055, 2021555350, 939867877, -1100576536>
``````

AVX2 doesn’t have instructions for SIMD

• Int64 multiplication
• Int64 -> Float64 conversion
• Float64 -> Int64 conversion

So you could use `Int32` if it helps you avoid these.
But reinterpreting between SIMD vectors of `Int64` and `Float64` is perfectly fine, because it doesn’t require any operations at all.

3 Likes

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.