I am tasked with converting some Fortran code to PHP and am stumbling at the last hurdle.
In essence the Fortran converts a REAL into a binary CHAR(4) which it ultimately writes to file.
The Fortran (which also confuses me) is as follows:
FUNCTION MKS(x)
CHARACTER (LEN=4) :: MKS ! The 4-character string which is returned to
REAL :: x ! The incoming single-precision variable
CHARACTER (LEN=1), DIMENSION(4) :: a ! A working variable
CHARACTER (LEN=4) :: d ! A working variable
CALL MKS1(x,a) ! Send x - get back a(1), a(2), a(3), a(4)
! Note: x will hold the first 32 bits referenced
! and a will hold the next 32 bits
d = a(1) // a(2) // a(3) // a(4) ! concatenate into 1 string (d)
MKS = d ! assign string to variable MKS
END FUNCTION MKS
SUBROUTINE MKS1 (b,c)
IMPLICIT NONE
CHARACTER (LEN=1), DIMENSION(4) :: b ! array with incoming 32 bits
CHARACTER (LEN=1), DIMENSION(4) :: c ! array with each character returned
INTEGER :: i ! DO Loop counter
DO i=1,4
c(i) = b(i)
END DO
END SUBROUTINE MKS1
I have attempted to recreate this function using php as follows
pack('CCCC', $value & 0x000F,
($value>>8) & 0x000F,
($value>>16) & 0x000F,
($value>>24) &0x000F);
But on comparing the output values using the *nix od command shows completely different results.
What is the correct way to pack the equivalent to a Fortran REAL into a char[4] Array in PHP?
It turned out to be quite simple.
Your FORTAN REAL is stored as an IEEE 754 32 bit floating point number.
The output from your od
was misleading. Converting it to hex gives the following.
0115040 0134631 0005077
0x20, 0x9A, 0x99, 0xB9, 0x3f, 0x0a
The first and last bytes of the file are redundant, they are a space and a carriage return respectively. The bit we're after is the middle 4 bytes.
Using pack
we can convert from floats (warning - endianness is machine dependant).
The following:
var_dump(bin2hex(pack('f', 1.450)));
Gives us a familar sequence of bytes.
string(8) "9a99b93f"
So instead of converting to hex, output that to a file with a space at the start and a carriage return at the end, and you'll have an identical file. (as long as your PHP/machine configuration doesn't do something mad with floats - but even then if you follow the IEEE 754 spec, you should be able to reproduce it)