Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading stream binary files in Fortran

I am reading a binary file where I know the byte positions of a large vector that contains more than 10^8 data samples written on 4-byte real in IBM format (described here).

As far as I know the real types in Fortran use the more recent IEEE format of samples (1 bit for sign, 8 bits for the exponent instead of 7-bit exponent for IBM format) as described here. Therefore reading these real values assuming a real format will give me wrong values, so I want to split each real number into 4 integers each occupying a single byte and then making the transformation to get the IEEE sample data from the 4 integer bytes.

I wrote the following test program to investigate this where I declare a positive real a1=1876752.76854 and its negative equivalent a2=-a1 into byte positions 1 and 5 respectively (a1 and a2 were declared to be 4 bytes long (kind=1)).

Later I read the same byte positions from the stream file for two reals of the same kind b1 and b2, but I also read in the same byte position two integers n1 and n2 (4 bytes each) to see if I can get the IEEE real type from the integer type easily. I also read the 4 integers (1 byte each) to use them to compute IEEE values as shown below:

program test_real_types
implicit none
integer,parameter       :: rk=kind(1.0)
real(rk)         :: a1,a2,b1,b2
integer(kind=1)  :: bytes1(4),bytes2(4)
integer          :: i
integer(kind=4)  :: n1,n2

a1=1876752.76854
a2=-a1

open(1,file='reals.dat',access="stream",form="unformatted")

write(1,pos=1) a1
write(1,pos=5) a2
close(1)

open(2,file='reals.dat',access="stream",form="unformatted",status="old")

!! reading byte positions: 1-4
do i=1,4
read(2,pos=i) bytes1(i)
enddo
read(2,pos=1) n1  !! read integer n1 of 4 bytes length in the same position
read(2,pos=1) b1  !! read real (4 bytes) in the same position

!! reading byte positions: 5-8
do i=5,8
read(2,pos=i) bytes2(i)
enddo
read(2,pos=5) n2
read(2,pos=5) b2

write(*,*) 'bytes1 = ',bytes1(1:4)
write(*,*) '    n1 = ',n1
write(*,*) '    b1 = ',b1
write(*,*) 'bytes2 = ',bytes2(1:4)
write(*,*) '    n2 = ',n2
write(*,*) '    b2 = ',b2
end program test_real_types

After execution of the code above, I got the following:

 bytes1 =   -122   24   -27   73
     n1 =   1239750790
     b1 =    1876752.8
 bytes2 =      0    0     0    0
     n2 =   -907732858
     b2 =   -1876752.8

As the results indicate, n2 is not equal to -n1 (expected), but I am surprised that bytes 5-8 are all equal to zero when I read them byte by byte while they print b2 correctly as -b1. I tried to read byte 9 but it is empty as expected.

Any help on how I am getting zero bytes for locations 5-8 while I can read correctly the real value of a2 and a non-zero integer n2?

like image 569
PolarXYZ Avatar asked Feb 13 '26 18:02

PolarXYZ


1 Answers

First of all, your program is buggy:

% gfortran -O2 -g -Wall -fcheck=all test_real_types.f90 
% ./a.out 
At line 30 of file test_real_types.f90
Fortran runtime error: Index '5' of dimension 1 of array 'bytes2' above upper bound of 4

Fixing the obvious error, and also avoiding the use of unit numbers < 10 (which is a good idea in general, though per se not relevant to the error you're seeing here), I get

% ./a.out      
 bytes1 =  -122   24  -27   73
     n1 =   1239750790
     b1 =    1876752.75    
 bytes2 =  -122   24  -27  -55
     n2 =   -907732858
     b2 =   -1876752.75    
like image 133
janneb Avatar answered Feb 16 '26 13:02

janneb



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!