How can I assign the boz-literal-constant Z'FEDCBA09' or any other bit-pattern with the most-significant bit equal to 1 to an integer?
The standard states:
INT(A[,KIND]): IfAis a boz-literal-constant, the value of the result is the value whose bit sequence according to the model in 16.3 is the same as that of A as modified by padding or truncation according to 16.3.3. The interpretation of a bit sequence whose most significant bit is 1 is processor dependent.source: Fortran 2018 Standard
So the following assignments might fail (assume integer is default 32 bit):
program boz
implicit none
integer :: x1 = int(Z'FEDCBA09')
integer :: x2 = int(Z'FFFFFFFF')
integer :: x3
data x3/Z'FFFFFFFF'/
end program
Using gfortran, this will only work when adding -fno-range-check but this introduces extra unwanted effects:
-fno-range-check: Disable range checking on results of simplification of constant expressions during compilation. For example, GNU Fortran will give an error at compile time when simplifyinga = 1. / 0.With this option, no error will be given and a will be assigned the value +Infinity. If an expression evaluates to a value outside of the relevant range of[-HUGE():HUGE()], then the expression will be replaced by-Infor+Infas appropriate. Similarly,DATA i/Z'FFFFFFFF'/will result in an integer overflow on most systems, but with-fno-range-checkthe value will "wrap around" andiwill be initialized to-1instead.source: GNU Compiler Collection, gfortran manual
I attempted the following, which works fine but still not 100%
integer(kind=INT32) :: x1 = transfer(real(Z'FEDCBA09',kind=REAL32),1_INT32)
integer(kind=INT32) :: x1 = transfer(real(Z'FFFFFFFF',kind=REAL32),1_INT32)
The latter case fails with gfortran as it complains that Z'FFFFFFFF' represents NaN.
Using IOR(0,Z'FEDCBA09') also fails as it converts the boz-literal using INT
Question: How can you robustly assign a bit pattern using a boz-literal-constant? That is to say, independent of the used compiler (GNU, SUN, PGI, NAG, ...).
Answer: The most robust answer is currently given by Jim Rodes in this comment:
x = ior(ishft(int(Z'FEDC'),bit_size(x)/2),int(Z'BA09'))
This will work on any compiler and does not require any other data-type to be successful.
The need for -fno-range-check has been removed in what will be gfortran 10.1 when it is released. In 10.1, the bit patterns you have specified will be treated as if they are 32-bit unsigned integers and twos-complement wrap-around semantics are enforced.
Your first code snippet with a print statement added
program boz
implicit none
integer :: x1 = int(Z'FEDCBA09')
integer :: x2 = int(Z'FFFFFFFF')
integer :: x3
data x3/Z'FFFFFFFF'/
print *, x1, x2, x3
end program
yields
$ gfortran -o z file.f90
$ ./z
-19088887 -1 -1
and does not require the -fno-range-check option. The same goes for the proposed transfer method:
program boz
use iso_fortran_env
implicit none
integer(kind=INT32) :: x1 = &
& transfer(real(Z'FEDCBA09',kind=REAL32),1_INT32)
integer(kind=INT32) :: x2 = &
& transfer(real(Z'FFFFFFFF',kind=REAL32),1_INT32)
print '(I0,1X,Z8.8)', x1, x1
print '(I0,1X,Z8.8)', x2, x2
end program
returning:
$ gfortran -o z file.f90
$ ./z
-19088887 FEDCBA09
2143289344 7FC00000
Note: gfortran converts sNaN into qNan, which is a bug but no one cares.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With