Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to assign bit-pattern Z'FEDCBA09' to a 32bit integer

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]): If A is 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 simplifying a = 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 -Inf or +Inf as appropriate. Similarly, DATA i/Z'FFFFFFFF'/ will result in an integer overflow on most systems, but with -fno-range-check the value will "wrap around" and i will be initialized to -1 instead.

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.

like image 579
kvantour Avatar asked Dec 07 '25 14:12

kvantour


1 Answers

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.

like image 144
steve Avatar answered Dec 11 '25 14:12

steve



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!