 |
forums.silverfrost.com Welcome to the Silverfrost forums
|
View previous topic :: View next topic |
Author |
Message |
Norm.Campbell
Joined: 31 Aug 2007 Posts: 66
|
Posted: Mon Nov 19, 2012 8:10 am Post subject: reading reals from bytes |
|
|
The "program test_read_real_from_bytes" below works as free-standing code.
Essentially the same code in "real_in4_w" below runs fine in /check /undef mode, but not otherwise. The Run-time Error is #67.
The code stops after " write (iot,'( '' char bytes = ichar '' )' ) ". It correctly lists the four ichar values as four ichar bytes : 103 148 19 68
Any suggestions as to what I'm doing wrong?
PS The convoluted procedure of extracting the ichar values and then reforming the chars into rbyt was simply to get a handle on what the code was doing. I get the same error message if I bypass the ichar / char steps and try to read xval from the input dbyt values.
program test_read_real_from_bytes
character *4 dbyt, rbyt
integer*2 ich_dbyt (4)
real *4 xval, zval
iot = 7
open ( iot, file = 'test_read_real_from_bytes_out.txt' )
c Sample rate: 590.318787 Hz
ich_dbyt(1) = 103
ich_dbyt(2) = 148
ich_dbyt(3) = 19
ich_dbyt(4) = 68
write (iot,'(/ '' four ichar bytes : '', 4i10 )' )
1 ( ich_dbyt(ie), ie=1,4 )
do ie = 1, 4
dbyt(ie:ie) = char ( ich_dbyt(ie) )
end do
c write (iot,'( '' four char bytes : '', 4a )' )
c 1 ( dbyt(ie:ie), ie=1,4 )
do ie = 1, 4
rbyt(ie:ie) = dbyt(ie:ie)
end do
read ( rbyt, '(4a)' ) zval
write (iot,'( '' value : '', f10.6 )' ) zval
stop
end
four ichar bytes : 103 148 19 68
value : 590.318787
subroutine real_in4_w ( dbyt, zval )
character * ( * ) dbyt
integer*2 ich_dbyt (4)
character *4 rbyt
real *4 xval
iot = 6
do ie = 1, 4
ich_dbyt(ie) = ichar ( dbyt(ie:ie) )
end do
write (iot,'(/ '' four ichar bytes : '', 4i10 )' )
1 ( ich_dbyt(ie), ie=1,4 )
write (iot,'( '' char bytes = 0 '' )' )
do ie = 1, 4
rbyt(ie:ie) = char ( 0 )
end do
do ie = 1, 4
rbyt(ie:ie) = char ( ich_dbyt(ie) )
end do
write (iot,'( '' char bytes = ichar '' )' )
read ( rbyt, '(4a)' ) xval
write (iot,'( '' value : '', f10.6 )' ) xval
zval = xval
return
end |
|
Back to top |
|
 |
Norm.Campbell
Joined: 31 Aug 2007 Posts: 66
|
Posted: Mon Nov 19, 2012 10:24 am Post subject: reading reals from bytes |
|
|
The problem only occurs when I set the /dreal flag. The program runs fine with no flags, and with /intl |
|
Back to top |
|
 |
mecej4
Joined: 31 Oct 2006 Posts: 1899
|
Posted: Mon Nov 19, 2012 2:28 pm Post subject: |
|
|
The second program is incomplete, since we do not know how the subroutine is invoked. Therefore, one has to play guessing games in an attempt to reproduce the error that was reported.
Add IMPLICIT NONE to each subprogram (or use the corresponding compiler switch) and note what options such as /DREAL do to variables with implicitly declared types and kinds. |
|
Back to top |
|
 |
JohnCampbell
Joined: 16 Feb 2006 Posts: 2615 Location: Sydney
|
Posted: Tue Nov 20, 2012 12:59 am Post subject: |
|
|
Norm,
What is the following line doing ?
read ( rbyt, '(4a)' ) zval
zval is real*4, although you appear to be storing character values. This looks like very old fortran, which should be better done if zval was declared as character zval(4)*1
Or have I got this wrong ?
( This looks like a way of writing a real*4 in a compact form and retain maximum precision.)
Would equivalencing zval to rbyt or perhaps using the intrinsic TRANSFER be better (more standard conforming?) to achieve what you want.
Also, does writing char(0) into a file create a problem when reading or writing characters ?
John
The following code demonstrates the use of EQUIVALENCE: Code: | program test_read_real_from_bytes
character*4 dbyt, rbyt
integer*4 ie,iot
integer*2 ich_dbyt (4)
real*4 xval, zval
equivalence (xval, dbyt)
iot = 1
! open ( iot, file = 'test_read_real_from_bytes_out.txt' )
!c Sample rate: 590.318787 Hz
ich_dbyt(1) = 103
ich_dbyt(2) = 148
ich_dbyt(3) = 19
ich_dbyt(4) = 68
write (iot,'(/ a, 4i10 )' ) ' four ichar bytes : ', ( ich_dbyt(ie), ie=1,4 )
do ie = 1, 4
dbyt(ie:ie) = char ( ich_dbyt(ie) )
end do
write (iot,'( a, f10.6, a )' ) ' xvalue : ', xval , ' Value from equivalence to dbyt'
!c write (iot,'( '' four char bytes : '', 4a )' )
!c 1 ( dbyt(ie:ie), ie=1,4 )
do ie = 1, 4
rbyt(ie:ie) = dbyt(ie:ie)
end do
read ( rbyt, '(4a)' ) zval
write (iot,'( a, f10.6 )' ) ' zvalue : ', zval
call real_in4_w ( dbyt, zval )
call real_in4_wa ( dbyt, zval )
stop
end
! four ichar bytes : 103 148 19 68
! value : 590.318787
subroutine real_in4_w ( dbyt, zval )
character * ( * ) dbyt
real*4 zval
!
integer*2 ich_dbyt (4)
integer*4 ie, iot
character *4 rbyt
real *4 xval
iot = 1
write (iot,*) 'Entering real_in4_w'
!
do ie = 1, 4
ich_dbyt(ie) = ichar ( dbyt(ie:ie) )
end do
write (iot,'(/ a, 4i10 )' ) ' four ichar bytes : ', ( ich_dbyt(ie), ie=1,4 )
write (iot,'( a )' ) ' char bytes = 0 '
do ie = 1, 4
rbyt(ie:ie) = char ( 0 )
end do
do ie = 1, 4
rbyt(ie:ie) = char ( ich_dbyt(ie) )
end do
write (iot,'( a )' ) ' char bytes = ichar '
read ( rbyt, '(4a)' ) xval
write (iot,'( a, f10.6 )' ) ' value : ', xval
zval = xval
return
end
subroutine real_in4_wa ( dbyt, zval )
character * ( * ) dbyt
real*4 zval
!
integer*2 ich_dbyt (4)
integer*4 ie, iot
character *4 rbyt
real *4 xval
equivalence (xval, rbyt )
!
iot = 1
write (iot,*) 'Entering real_in4_wa'
!
do ie = 1, 4
ich_dbyt(ie) = ichar ( dbyt(ie:ie) )
end do
write (iot,'(/ a, 4i10 )' ) ' four ichar bytes : ', ( ich_dbyt(ie), ie=1,4 )
write (iot,'( a )' ) ' char bytes = 0 '
do ie = 1, 4
rbyt(ie:ie) = char ( 0 )
end do
do ie = 1, 4
rbyt(ie:ie) = char ( ich_dbyt(ie) )
end do
write (iot,'( a )' ) ' char bytes = ichar '
! read ( rbyt, '(4a)' ) xval
write (iot,'( a, f10.6 )' ) ' value : ', xval
zval = xval
return
end |
|
|
Back to top |
|
 |
JohnCampbell
Joined: 16 Feb 2006 Posts: 2615 Location: Sydney
|
Posted: Tue Nov 20, 2012 2:12 am Post subject: |
|
|
Norm,
I changed the code to give an example of using EQUIVALENCE, TRANSFER and your READ approach. All produce the same result.
I have always used the EQUIVALENCE approach, although TRANSFER might be more standard conforming.
However, I'm not sure how standard conforming this approach is.
I have used this in the past to convert between "little endian" and "big endian" for unix binary formats by changing the order of the bytes.
Sorry, I just read your second post: doesn't using /dreal convert the real value to 8 bytes ? so you need to provide an 8-byte format for zval. You could find out the layout by reversing the process. such as:
Code: | integer*4 i
real*8 zval
character dbyt*8
equivalence (zval,dbyt)
!
zval = 590.318787
write (*,*) zval
write (*,*) (ichar(dbyt(i:i)),i=1,8)
!
end |
John
Code: | program test_read_real_from_bytes
character*4 dbyt, rbyt
integer*4 ie,iot
integer*2 ich_dbyt (4)
real*4 xval, zval
equivalence (xval, dbyt)
iot = 1
! open ( iot, file = 'test_read_real_from_bytes_out.txt' )
!c Sample rate: 590.318787 Hz
ich_dbyt(1) = 103
ich_dbyt(2) = 148
ich_dbyt(3) = 19
ich_dbyt(4) = 68
write (iot,'(/ a, 4i10 )' ) ' four ichar bytes : ', ( ich_dbyt(ie), ie=1,4 )
write (iot,*) 'pack byte values into dbyt'
do ie = 1, 4
dbyt(ie:ie) = char ( ich_dbyt(ie) )
end do
!
write (iot,'( a, f10.6, a )' ) ' xvalue : ', xval , ' Value from equivalence to dbyt'
!
zval = 0
zval = transfer (dbyt, zval)
write (iot,'( a, f10.6, a )' ) ' zvalue : ', zval , ' Value from TRANSFRE from dbyt'
!
do ie = 1, 4
rbyt(ie:ie) = dbyt(ie:ie)
end do
read ( rbyt, '(4a)' ) zval
write (iot,'( a, f10.6, a )' ) ' zvalue : ', zval , ' Value using read (rbyt, 4a)'
! call real_in4_w ( dbyt, zval )
! call real_in4_wa ( dbyt, zval )
stop
end
|
|
|
Back to top |
|
 |
Norm.Campbell
Joined: 31 Aug 2007 Posts: 66
|
Posted: Tue Nov 20, 2012 2:34 am Post subject: |
|
|
Thanks, John. That's neat.
As you know, I'm more of a coder than a programmer. I use Fortran to implement statistical algorithms, and so I reuse the same simple subset of Fortran that's worked in the past.
Someone gave me that bit of code for reading reals from bytes and so I went on using it.
Doesn't equivalence hark back to Fortran 77? Transfer seems more elegant. I assume that it would be insensitive to the byte ordering.
Logic dictates that the problem I was having lies with the real *4 declaration; as you note in your later post, the /dreal flag must be "doubling" the size of xval.
Out of curiosity, can I somehow declare the size of xval to be 4 bytes, so that /dreal leaves it as declared?
Cheers Norm |
|
Back to top |
|
 |
JohnCampbell
Joined: 16 Feb 2006 Posts: 2615 Location: Sydney
|
Posted: Tue Nov 20, 2012 3:51 am Post subject: |
|
|
Norm,
You would need to check /dreal documentation. However, I would NEVER use it, but explicitly declare the type of real. For such an important property, you must have the variable precision explicitly defined in the code.
You can go down the path of all the KIND related formats and selected_real_kind parameters, but for me, the simplest approach is to use "real*4" or "real*8". They clearly document the precision!
I think that /dreal only applies to statements like real x, where the byte size is not explicitly defined. I could be wrong, but again I'd strongly recommend against it.
I'm assuming you are getting the byte values from an external source, so before you do this, you should know how many bytes are in the real variable and the byte format. Unix (and I think Linux) do use a different byte format. Hence the lovely names of big endian and little endian!
All these problems are easily solved by being able to manage the bytes, such as with character*n or with an integer*1 array, which is then equivalenced or TRANSFER to the real*n variable. Much better than using a read or write statement.
The format (number of bytes and order) of the real you are being supplied (or supplying) is a key issue to clarify. The conversion is easy!
If they mix 4-byte and 8-byte values, then it becomes a bit more complex, but there is always a pre-defined structure to scan.
John |
|
Back to top |
|
 |
Norm.Campbell
Joined: 31 Aug 2007 Posts: 66
|
Posted: Tue Nov 20, 2012 4:05 am Post subject: |
|
|
Hi John
I agree totally with your comments re real*4 -- it's always made perfect sense to me to simply declare the number of bytes in the real.
Perhaps Paul can tell an old-fashioned coder how to do it so that /dreal doesn't change the declaration, if that's possible.
The file contains a whole lot of backscatter and related values from the water column and seafloor. The file format is very clearly set out, so the numbers of bytes for the various variables are all known. That's why /dreal is stuffing things up (to put it bluntly), since there are 4 bytes for all the reals.
Cheers Norm |
|
Back to top |
|
 |
JohnCampbell
Joined: 16 Feb 2006 Posts: 2615 Location: Sydney
|
Posted: Tue Nov 20, 2012 4:13 am Post subject: |
|
|
Norm,
You could separate out the routines for the conversion to a seperate file and not select /dreal for these routines (this file).
As I posted recently, I have a batch file (make.bat) which explicitly compiles each file with it's particular compiler options, then runs "SLINK <link_list.txt"
I have about 50 .f95 ( > .obj) files, plus about 6 libraries (.lib) im a typical program build.
I use /debug for most, /opt for high performance routines, or /check for more robust reading of data from files.
( using /opt and /check in the same executable is not a good idea, but now we can mix /debug and /opt and still get access to 3.8gb of memory )
John |
|
Back to top |
|
 |
davidb
Joined: 17 Jul 2009 Posts: 560 Location: UK
|
Posted: Tue Nov 20, 2012 9:38 am Post subject: |
|
|
Using John's transfer approach you can encapsulate the conversion both ways in a couple of subroutines:
Code: |
SUBROUTINE real_to_bytes(value, bytes)
REAL*4, INTENT(IN) :: value
CHARACTER, INTENT(OUT) :: bytes(4)
bytes = TRANSFER(value, bytes))
END SUBROUTINE real_to_bytes
SUBROUTINE bytes_to_real(bytes, value)
CHARACTER, INTENT(IN) :: bytes(4)
REAL*4, INTENT(OUT) :: value
value = TRANSFER(bytes, value)
END SUBROUTINE bytes_to_real
|
You can use a module and an INTERFACE to handle different kinds of reals
Code: |
MODULE real_convertor
INTERFACE real_to_bytes
MODULE PROCEDURE real4_to_bytes
MODULE PROCEDURE real8_to_bytes
END INTERFACE real_to_bytes
INTERFACE bytes_to_real
MODULE PROCEDURE bytes_to_real4
MODULE PROCEDURE bytes_to_real8
END INTERFACE bytes_to_real
CONTAINS
SUBROUTINE real4_to_bytes(value, bytes)
REAL*4, INTENT(IN) :: value
CHARACTER, INTENT(OUT) :: bytes(:)
bytes = TRANSFER(value, bytes))
END SUBROUTINE real4_to_bytes
SUBROUTINE real8_to_bytes(value, bytes)
REAL*8, INTENT(IN) :: value
CHARACTER, INTENT(OUT) :: bytes(:)
bytes = TRANSFER(value, bytes))
END SUBROUTINE real8_to_bytes
SUBROUTINE bytes_to_real4(bytes, value)
CHARACTER, INTENT(IN) :: bytes(:)
REAL*4, INTENT(OUT) :: value
value = TRANSFER(bytes, value)
END SUBROUTINE bytes_to_real4
SUBROUTINE bytes_to_real8(bytes, value)
CHARACTER, INTENT(IN) :: bytes(:)
REAL*8, INTENT(OUT) :: value
value = TRANSFER(bytes, value)
END SUBROUTINE bytes_to_real8
END MODULE real_convertor
|
_________________ Programmer in: Fortran 77/95/2003/2008, C, C++ (& OpenMP), java, Python, Perl |
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|