Is there some generally used way to split 8-bytes number into two 4-byte ones and then combine these two back to 8-bytes all with minimal efforts?
How split 8bytes number into two 4-bytes and combine back
integer,parameter::k=4
integer(k) v
integer U,L
v = 17_k + ishft(27_k, 32)
print*,v
U = ishft(v, -32)
L = iand(v, Z'00000000ffffffff')
v = int(L,k) + ishft(int(U,k),32)
print*,L,U
print*,v
Thanks Paul, great, that kind of binary trickery I was exactly hoping for.
Dan, You can always use EQUIVALENCE, or TRANSFER if you are a modern Fortran dude!
Modern Fortran dudes should care about EQUIVALENCE being obsolete in F2018 😃
Paul,
Something is strange here. Let's take integer*8 numbers v larger than approximately 2 billion. After splitting them into pair of U and L and then combining back, these numbers are not getting back into itself
Where i am wrong?
integer,parameter::k=4
integer(k) v
integer U,L
v = 2222222222_4
print*, v
U = ishft(v, -32)
L = iand(v, Z'00000000ffffffff')
print*,L,U
! getting v back
v = int(L,k) + ishft(int(U,k),32)
print*,v
end
By the way how will look this code for v being integer4 and U and L integer2 ?
'v = int(L,k)' does not do what you want, but equivalencing v to L,U would.
integer,parameter::k=4
integer(4) v
integer U,L
common /aa/ L, U
equivalence (v,L)
v = 2222222222_4
print*, v
print*,L,U
U = 0
print*,v
print*,L,U
end
Reminds me of the problem using LOC (aaa) with 32-bit and 3GB memory. I had to write an integer*8 function JLOC to replace calling LOC.
Looks like Paul's code either has an error or its functions have a bug or something is incorrectly used somewhere.
Anyone spotting the error in all that bits manipulations?
For the Integer*4 v the code modified as below works fine
integer,parameter::k=3
integer v
integer U,L
111 READ(*,*) v
U = ishft(v, -16)
L = iand(v, Z'0000ffff')
print*,L,U
! getting v back
v = int(L,k) + ishft(int(U,k),16)
print*,v
goto 111
end
That allows to use v < 2 billion. But that limitation on v is a bit too small.
So may be arbitrary precision between INTEGER4 and INTEGER8 will work? Because out of the box the U and L these v numbers generate have to be smaller than ~20 million (to be precise - below numbers represented by number of bytes in mantissa of REAL4 numbers) as i need then to convert integer U and L to real4 u and l
UPDATE, despite errors with 8byte integers, with smaller v integers like 5 and 6 bytes this still works OK
I think this will work for me: V will be restricted to ~1015 from 1e9 and paraphrasing Bill Gates 'The 1015 will fit to everyone until AI and Big Data come'
integer,parameter::k=4
integer(4) v
integer U,L
111 READ(*,*) v
U = ishft(v, -24)
L = iand(v, Z'000000ffffff')
print*,L,U
! getting v back
v = int(L,k) + ishft(int(U,k),24)
print*,v
goto 111
end
/* V is how many cells or particles you allow in your numerical codes. Of course with integer*8 you can get 10^18 but this will require to increase file sizes twice
All Fortran integers are signed, so for INTEGER4 values greater than 2147483647, U and L must be changed to INTEGER8.
integer,parameter::k=4
integer(k)::v,U,L
v = 2222222222_k
U = ishft(v, -32)
L = iand(v, Z'00000000ffffffff')
v = int(L,k) + ishft(int(U,k),32)
print*,L,U,v
end
Thanks. But still failing with one more 2...
integer,parameter::k=4
integer(k)::v,U,L
v = 22222222222_k
U = ishft(v, -32)
L = iand(v, Z'00000000ffffffff')
v = int(L,k) + ishft(int(U,k),32)
print*,L,U,v
end
integer,parameter::k=selected_int_kind(18)
integer(k)::v,U,L
v = 22222222222_k
U = ishft(v, -32)
L = iand(v, Z'00000000ffffffff'_k)
v = ior(L,ishft(U,32))
print*,L,U,v
end
Looks like this works! Thanks Paul