Solved

Reading a float(?)

Posted on 2001-06-15
15
1,084 Views
Last Modified: 2009-07-29
I have a piece of C (eurgh) code that I'm converting to Delphi (hooray). As part of it I need to read a file structure in and as it's a byte file I'm using FILE of BYTE. However (and it's here that my brain gave up) part of the structure contains a float value. Any idea how I read in a float value from a stream of bytes?

e.g.

VAR
  bFile  : FILE OF BYTE;
  rValue : DOUBLE;
...
  READ(bFile, byte1);
  READ(bFile, byte2);
  READ(bFile, rValue); ?!?!?!?!

I know that the reading of rValue is wrong but anybody got any ideas how it needs to be?

The Neil =:)
0
Comment
Question by:TheNeil
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 4
  • 4
  • +1
15 Comments
 
LVL 8

Expert Comment

by:Cesario
ID: 6194311
Hi,


VAR
 bFile  : FILE;
 rValue : DOUBLE;
...
 Reset ( bFile, 1 );
 BlockRead(bFile, byte1,SizeOf(Byte));
 BlockREAD(bFile, byte2,SizeOf(Byte));
 BlockREAD(bFile, rValue, SizeOf(rValue);


good luck



Cesario
0
 
LVL 5

Author Comment

by:TheNeil
ID: 6194373
Thanks Cesario, that works perfectly, but (and here it comes) the file is stored in little-endian (Intel byte ordering) format so all the byte values are stores backwards. Using block read gets the values in in the wrong order and therefore gets the wrong value back out. Any ideas?

The Neil =:(
0
 
LVL 5

Author Comment

by:TheNeil
ID: 6194378
Thanks Cesario, that works perfectly, but (and here it comes) the file is stored in little-endian (Intel byte ordering) format so all the byte values are stores backwards. Using block read gets the values in in the wrong order and therefore gets the wrong value back out. Any ideas?

The Neil =:(
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 8

Expert Comment

by:Cesario
ID: 6194411
Yeah, read it in as an integer or cardinal, and then swap things around,
either with masks and shifts or by using asm instructions to do the
swap.
0
 
LVL 8

Expert Comment

by:Cesario
ID: 6194427
Hi

http://www.caos.dk/development/delphi/turnint.htm
http://www.rdrop.com/~cary/html/endian_faq.html

try to use the BSWAP and XCHG assembler instructions, respectively



function SWAP16(ASmallInt: SmallInt): SmallInt; register;
asm
  xchg al, ah
end;


function SWAP32 (AnInteger: Integer): Integer; register;
asm
  bswap eax;
end;

Best Regards

Cesario
0
 
LVL 5

Author Comment

by:TheNeil
ID: 6194465
Err, it's the float that's causing me problems (and I'm probably being dense) but doesn't all of this apply to int values only? If you can post me a piece of code that does it, the points are yours

The Neil =:(
0
 
LVL 8

Expert Comment

by:Cesario
ID: 6194534
Helle,

sorry, but I must leave the office now.. ( Client is waiting ).
So I try to post some code tommorow..


best Regards

Cesario
0
 
LVL 3

Expert Comment

by:f15iaf
ID: 6198001
try to use low level format functions
like
Fileopen
fileread
filewrite
fileclose

You can define with fileread how much bytes to read and
to any type whether it's byte or double;
0
 
LVL 5

Author Comment

by:TheNeil
ID: 6198045
f15iaf

Thanks for the suggestion but the problem isn't getting the data in from the file, it's getting it in the correct order and reassembling it. The data is stored as a float consisting of 4 bytes (no problems so far, blockread will handle that) BUT the bytes are stored in reverse order. If you read the four bytes straight into a float then you're not allowing for the reverse byte order. What I think needs to happen is that the four bytes need to be read in, re-ordered and THEN converted to a float (which has just given me an idea...)

The Neil =:)
0
 
LVL 3

Accepted Solution

by:
f15iaf earned 50 total points
ID: 6198065
first of all using double it's 8 byte real type you should use 4 byte real which is single;

Here is the code which reverses the bytes:
var
  hl:pchar;
  fl:single;
  h:char;
begin
        hl:=@fl;
        {read 4 bytes here to hl here by BlockREAD(bFile, hl,4)}
        h:=hl[0];
        hl[3]:=hl[0]
        hl[3]:=h;
        h:=hl[1];
        hl[2]:=hl[1]
        hl[2]:=h;
        {the fl here is the right 4 byte real}

end;
0
 
LVL 3

Expert Comment

by:f15iaf
ID: 6198142
Sorry this si the correct one


first of all using double it's 8 byte real type you should use 4 byte real which is single;

Here is the code which reverses the bytes:
var
 hl:pchar;
 fl:single;
 h:char;
begin
       hl:=@fl;
       {read 4 bytes here to hl here by BlockREAD(bFile, hl,4)}
       h:=hl[0];
       hl[0]:=hl[3]
       hl[3]:=h;
       h:=hl[1];
       hl[1]:=hl[2]
       hl[2]:=h;
       {the fl here is the right 4 byte real}

end;
0
 
LVL 5

Author Comment

by:TheNeil
ID: 6198539
Have you tried running this code? I've pasted it in (and uncommented the BlockRead and added the missing semi-colons) and it falls flat on it's face when it hits the line:

h:=hl[0];

It's causing an access violation

The Neil =:(
0
 
LVL 3

Expert Comment

by:f15iaf
ID: 6198570
I've found the bug use
blockread(bfile,fl,4);
and then
      hl:=@fl;
      h:=hl[0];
      hl[0]:=hl[3]
      hl[3]:=h;
      h:=hl[1];
      hl[1]:=hl[2]
      hl[2]:=h;
      {the fl here is the right 4 byte real}

end;


var
hl:pchar;
fl:single;
h:char;
begin
      blockread(bfile,fl,4);
      hl:=@fl;
      h:=hl[0];
      hl[0]:=hl[3]
      hl[3]:=h;
      h:=hl[1];
      hl[1]:=hl[2]
      hl[2]:=h;
      {the fl here is the right 4 byte real}

end;
0
 
LVL 5

Author Comment

by:TheNeil
ID: 6199487
Well this is a weird one. I should explain, I'm reading data from Quake 2 model files and the floats correspond to three scaling values that are used (and are stored in little endian order). When I use your code it's pulling out weird values (I'm not saying the code is wrong but ID's data files to be wrong...).

The byte sequences are as follows:

223 22 216 61  -> -1.0869504771e+19  ?
119 212 147 61 -> 8.6230725089e+33  ?

Yet if I put 0 0 0 0 in I get 0 out (which seems correct). As far as I can tell, the code is correct and it's re-ordering the bytes correctly and getting them effectively cast as a Single so I can't argue with it. Looks like you answered the question (but my overall problem hasn't been solved), so I'm giving you the points. This has me baffled though

The Neil =:)
0
 

Expert Comment

by:paolinoilpescatore
ID: 7093126
Hi "TheNeil", try this code. The trick is to have a true double var "pippo" at the same memory location of single 8 byte "TempByte". In this way you don't do anything !! "pippo" is ready to show the correct result in Edit1.Text. (in my code I suppose to have a file with data "filinp", then I open the file as you want "file of byte" and every time you want read a double var apply the short "for" loop and "pippo" is filled with the answer.

procedure TForm1.Button2Click(Sender: TObject);
var
  FilInp : file of byte;
  tempByte : array [0..7] of byte;
  pippo : double absolute TempByte;
  n : integer;
begin
  if od1.execute then begin
    AssignFile(FilInp, od1.FileName);
    Reset(FilInp);
    for n:=0 to 7 do begin
      Read(FilInp, TempByte[n]);
    end;
    CloseFile(FilInp);
    Edit1.Text:=FloatToStr(Pippo);
  end;
end;
0

Featured Post

[Webinar] Code, Load, and Grow

Managing multiple websites, servers, applications, and security on a daily basis? Join us for a webinar on May 25th to learn how to simplify administration and management of virtual hosts for IT admins, create a secure environment, and deploy code more effectively and frequently.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

752 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question