replica nfl jerseysreplica nfl jerseyssoccer jerseyreplica nfl jerseys forums.silverfrost.com :: View topic - reading reals from bytes
forums.silverfrost.com Forum Index forums.silverfrost.com
Welcome to the Silverfrost forums
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

reading reals from bytes

 
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support
View previous topic :: View next topic  
Author Message
Norm.Campbell



Joined: 31 Aug 2007
Posts: 66

PostPosted: Mon Nov 19, 2012 8:10 am    Post subject: reading reals from bytes Reply with quote

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
View user's profile Send private message
Norm.Campbell



Joined: 31 Aug 2007
Posts: 66

PostPosted: Mon Nov 19, 2012 10:24 am    Post subject: reading reals from bytes Reply with quote

The problem only occurs when I set the /dreal flag. The program runs fine with no flags, and with /intl
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1899

PostPosted: Mon Nov 19, 2012 2:28 pm    Post subject: Reply with quote

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
View user's profile Send private message
JohnCampbell



Joined: 16 Feb 2006
Posts: 2615
Location: Sydney

PostPosted: Tue Nov 20, 2012 12:59 am    Post subject: Reply with quote

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
View user's profile Send private message
JohnCampbell



Joined: 16 Feb 2006
Posts: 2615
Location: Sydney

PostPosted: Tue Nov 20, 2012 2:12 am    Post subject: Reply with quote

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
View user's profile Send private message
Norm.Campbell



Joined: 31 Aug 2007
Posts: 66

PostPosted: Tue Nov 20, 2012 2:34 am    Post subject: Reply with quote

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
View user's profile Send private message
JohnCampbell



Joined: 16 Feb 2006
Posts: 2615
Location: Sydney

PostPosted: Tue Nov 20, 2012 3:51 am    Post subject: Reply with quote

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
View user's profile Send private message
Norm.Campbell



Joined: 31 Aug 2007
Posts: 66

PostPosted: Tue Nov 20, 2012 4:05 am    Post subject: Reply with quote

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
View user's profile Send private message
JohnCampbell



Joined: 16 Feb 2006
Posts: 2615
Location: Sydney

PostPosted: Tue Nov 20, 2012 4:13 am    Post subject: Reply with quote

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
View user's profile Send private message
davidb



Joined: 17 Jul 2009
Posts: 560
Location: UK

PostPosted: Tue Nov 20, 2012 9:38 am    Post subject: Reply with quote

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
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
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