Forum > General

How do you read Doubles from a byte array

(1/2) > >>

cov:
Sorry for asking such a dumb question, but I'm reading an eight byte double from a file.

Blockread(SHPFile, buffer[0], 8);

Is there a simple way to typecast the buffer?

I know that the eight bytes in the buffer are a double.

Surely this should be quite common circumstance, but I can't seem to find it on Google.

I'm about to start using this:


--- Code: ---
function TForm1.readDouble(buff: array of byte): Real;
var
  man, val: Int64;
  i, sh, expon, sign: integer;
begin
  man:=buff[0];
  sh:=8;
  for i:=1 to 5 do
  begin
    val:=buff[i];
    val:=val shl sh;
    man+=val;
    Inc(sh,8);
  end;
  val:=((buff[6]and 15)+16) shl 48;
  man+=val;
  expon:=((buff[7]and 127)shl 4)+ (buff[6]shr 4)-1075;
  Result:=power(2,expon)*man;
  if buff[7]>127 then Result*=-1;
end;   
--- End code ---

Cyrax:
In which format is that eight byte double which are you trying to read from the file?

If it is in standard format, this code snippet should work:

--- Code: ---Var
  ADouble : Double;
begin
   ..
   BlockRead(AFile, ADouble, SizeOf(ADouble));
   ..
end;

--- End code ---

Supported Real types : http://www.freepascal.org/docs-html/ref/refsu6.html

Leledumbo:

--- Quote ---I know that the eight bytes in the buffer are a double.

Surely this should be quite common circumstance, but I can't seem to find it on Google.
--- End quote ---
IEEE 754 doesn't specify endianness for floating point, so even if you know these 8 bytes are double, the byte order is unknown.
It's not common, especially in Pascal world, to do such a thing unless the file is saved with the same Pascal code compiled by the same Pascal compiler or it's manually saved with a format defined by the programmer.

engkin:
I think I have to re-read Leledumbo's answer a few times to understand what he meant. Meanwhile, I assume you are just like me, using Double as specified by your FPU. Your code supports my assumption:

--- Code: ---man :=
       (buff[0] shl 0) +
       (buff[1] shl 8) +
       (buff[2] shl 16) +
..
       (buff[5] shl 40) +
       ((buff[6]and 15)+16) shl 48;

--- End code ---
in this case I think you can simply follow Cyrax' code.

cov:
Thanks all, for your responses.

I was thinking that a pointer to the variable in the buffer array would be the way to go.

However, the file format ('.shp') mixes both endian formats, so it's safer to control this by shl as suggested by engkin.

My readDouble() function seems to work ok for 8-byte doubles and I've written this for other number formats:


--- Code: ---function readInteger(buff: array of byte; pos,size: integer): integer;
var
  i,val,sh, endpos, interv: integer;
begin
  sh:=0;
  Result:=0;
  interv:=1;
  endpos:=pos+size;
  i:=pos;
  if size<0 then
  begin
    interv:=-1;
    endpos:=pos;
    i:=pos-size-1;
  end;
  while i<>endpos do
  begin
    val:=buff[i];
    Result+=val shl sh;
    Inc(sh,8);
    i+=interv;
  end;
end; 
--- End code ---

A four byte big-endian integer occurring in the buffer at byte 4 would be read like this: myInt:=readInteger(buffer,4,4);

and a four byte little-endian integer occurring in the buffer at byte 4 would be read like this: myInt:=readInteger(buffer,8,-4);

Navigation

[0] Message Index

[#] Next page

Go to full version