Extended auf dem Raspberri Pi Speichern/Laden

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1498
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Extended auf dem Raspberri Pi Speichern/Laden

Beitrag von corpsman »

Servus,

Ich sehe mal wieder für Lauter Bämen den Wald nicht, und deswegen frage ich euch.
Ich habe mir ein Programm gebastelt, welches Extended werte in einen TFilestream Speichert und auch wieder laden kann.
Nun versuche ich die so gespeicherten Dateien auf dem Pi wieder zu laden und zu speichern.

Das Problem auf dem Pi ist sozeof(extended) = 8, während es auf meiner x86 Maschine 10 ist.

Nun habe ich mir eine Laden und eine Speichern Routine geschrieben, welche das Problem entsprechend umschiffen soll. Das Laden der 10-bit Extended auf dem Pi geht wunderbar. Nur leider funktioniert die Speichern Routine noch nicht, könnt ihr mir weiter helfen ?

Code: Alles auswählen

 
Program project1;
 
Uses sysutils, Classes, math;
 
Function Read10ByteExtended(Const Stream: Tstream): Extended; // Liest den TFIlestream eines 10Byte extended gespeicherten Wertes aus und legt ihn in der 8-Byte variable ab.
Var
  data: Array[0..9] Of byte;
  i: integer;
  Exponent: integer;
  Mantissa: extended;
Begin
  For i := 0 To 9 Do
    data[9 - i] := 0;
  stream.read(data[9 - i], 1);
  If ((data[0] And 128) = 128) Then Begin
    result := -1;
  End
  Else Begin
    result := 1;
  End;
  data[0] := data[0] And 127; // Clear Sign Bit
  Exponent := ((data[0] Shl 8) Or data[1]) - 16382; // Calculate Exponent
  // Add Mantissa, shouldnt this be 1 ??, but it is working
  Mantissa := 0;
  mantissa := mantissa + data[2] / 256;
  mantissa := mantissa + data[3] / (256 * 256);
  mantissa := mantissa + data[4] / (256 * 256 * 256);
  mantissa := mantissa + data[5] / (256 * 256 * 256 * 256);
  mantissa := mantissa + data[6] / (256 * 256 * 256 * 256 * 256);
  mantissa := mantissa + data[7] / (256 * 256 * 256 * 256 * 256 * 256);
  // Not possible on Arm
  //  mantissa := mantissa + data[8] / (256 * 256 * 256 * 256 * 256 * 256 * 256);
  //  mantissa := mantissa + data[9] / (256 * 256 * 256 * 256 * 256 * 256 * 256 * 256);
  result := result * Mantissa * power(2, Exponent);
End;
 
Procedure Write10ByteExtended(val: extended; Const Stream: TStream); // Soll eine 8-byte Extended abspeichern, als sei sie 10-Byte Groß
//Type
//  pint32 = ^int32;
Var
  data: Array[0..9] Of byte;
  i: integer;
  Exponent: integer;
Begin
  For i := 0 To 9 Do
    data[i] := 0;
  If val < 0 Then data[0] := data[0] Or 128;
  Exponent := 0;
  While val < 1 Do Begin
    Exponent := Exponent + 1;
    val := val * 2;
  End;
  While val > 2 Do Begin
    Exponent := Exponent - 1;
    val := val / 2;
  End;
  Exponent := exponent + 16382;
  data[0] := data[0] Or ((exponent Shr 8) And ($7F));
  data[1] := Exponent And $FF;
  data[2] := Trunc(val * 256);
  data[3] := Trunc(val * 256 * 256);
  data[4] := Trunc(val * 256 * 256 * 256);
  data[5] := Trunc(val * 256 * 256 * 256 * 256);
  data[6] := Trunc(val * 256 * 256 * 256 * 256 * 256);
  data[7] := Trunc(val * 256 * 256 * 256 * 256 * 256 * 256);
 
  For i := 0 To 9 Do Begin
    stream.write(data[9 - i], 1);
  End;
End;
 
Var
  f: TFilestream;
  s: Single;
  d: Double;
  e: Extended;
Begin
  { // Code zum Speichern
  f := TFileStream.Create('x68Out.dat', fmCreate Or fmOpenWrite);
  s := 12.4;
  d := 23.4;
  e := 0.123;
  f.Write(s, sizeof(s));
  f.Write(d, sizeof(d));
  If SizeOf(extended) = 10 Then Begin
    f.Write(e, sizeof(e));
  End
  Else Begin
    Write10ByteExtended(e, f);
  End;
  f.free;
  // -- Write Ende }

  // { // Code zum Lesen
  f := TFileStream.Create('piOut.dat', fmOpenRead);
  s := 0;
  d := 0;
  e := 0;
  f.read(s, sizeof(s));
  f.read(d, sizeof(d));
  If SizeOf(extended) = 10 Then Begin
    f.read(e, sizeof(e));
  End
  Else Begin
    e := Read10ByteExtended(f);
  End;
  f.free;
  // -- Read Ende }
  writeln(format('%0.3f', [s]));
  writeln(format('%0.3f', [d]));
  writeln(format('%0.3f', [e]));
End.
 
--
Just try it

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Extended auf dem Raspberri Pi Speichern/Laden

Beitrag von Mathias »

Das Problem auf dem Pi ist sozeof(extended) = 8, während es auf meiner x86 Maschine 10 ist.

Brauchst du unbedingt die Genauigkeit eines Extended, ansonsten würde ich es als Double speichern, der ist immer 8 Byte.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1498
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: Extended auf dem Raspberri Pi Speichern/Laden

Beitrag von corpsman »

Das Problem ist, das mein Programm schon längst veröffentlich ist, und es ettliche Dateien gibt, welche mit Extended gespeichert wurden, diese würden alle ungültig werden, wenn ich das Format einfach ändere. Die fehlende Genauigleit auf dem Pi ist aktzeptabel, die Kompatibilität zum Hauptformat wollte ich aber schon beibehalten.

Code: Alles auswählen

 
// Diese Variante ist leider auch nicht richtig, behandelt aber wenigstens das Corzeichen korrekt ;(
Procedure Write10ByteExtended(val: extended; Const Stream: TStream);
Var
  data: Array[0..9] Of byte;
  i: integer;
  Exponent: integer;
Begin
  For i := 0 To 9 Do
    data[i] := 0;
  If val < 0 Then Begin
    val := -1 * val;
    data[0] := data[0] Or 128;
  End;
  Exponent := 0;
  While val < 1 Do Begin
    Exponent := Exponent + 1;
    val := val * 2;
  End;
  While val > 2 Do Begin
    Exponent := Exponent - 1;
    val := val / 2;
  End;
  Exponent := exponent + 16382;
  data[0] := data[0] Or ((exponent Shr 8) And ($7F));
  data[1] := Exponent And $FF;
  data[2] := Trunc(val * 256);
  data[3] := Trunc(val * 256 * 256);
  data[4] := Trunc(val * 256 * 256 * 256);
  data[5] := Trunc(val * 256 * 256 * 256 * 256);
  data[6] := Trunc(val * 256 * 256 * 256 * 256 * 256);
  data[7] := Trunc(val * 256 * 256 * 256 * 256 * 256 * 256);
 
  For i := 0 To 9 Do Begin
    stream.write(data[9 - i], 1);
  End;
End;   
 
--
Just try it

Horst_h
Beiträge: 72
Registriert: Mi 20. Mär 2013, 08:57

Re: Extended auf dem Raspberri Pi Speichern/Laden

Beitrag von Horst_h »

Hallo,

bei extended bleibt die 1 der Mantisse vor dem Komma erhalten.
EDIT:
Leicht modifiziert.Es geht ja praktisch darum die double als extended zu speichern und extended in double einzulesen.
Wobei alles little endian ist.
Noch ein Edit:
Laut Wikipedia: "Der Standardmodus der ARM ist Little-Endian." Damit kann man die DWord Variante wohl benutzen.Je weniger Umwandlungen von Int -> float desto besser.Mit UInt64 statt Int64 in der Read Funktion es es auch.
Ich habe keinen Raspi, also ist dort ein Test notwendig.
DIe ganzen NaN Bedingungen fehlen hier auch.
https://de.wikipedia.org/wiki/IEEE_754
Der Bias Wert bei Read 16382 ist um 1 kleiner, als in Wiki, weil extended Mantisse 1.XXXXXX und nicht .XXXXX wie bei double ist.
DIe Zahlen sind also aus 1..1.99..99 und nicht 0.5 .. 0.9999999...
Bei der Umwandlung aus double bei Write, ist nur der Abstand der Bias relevant, also 16383-1023

Code: Alles auswählen

Program project1;
{$MODE DELPHI}
 
Uses sysutils, Classes, math;
 
Function Read10ByteExtended(Const Stream: Tstream): double;
//Liest den TStream eines 10Byte extended (little Endian) gespeicherten Wertes
//aus und legt ihn in der 8-Byte variable ab.
const
  rezDW = 1/(256*256)/(256*256);
  rez64 = rezDW*rezDW;
Var
  Exponent: integer;
  data: Array[0..9] Of byte;
  dataDw: Array[0..1] of cardinal absolute data;
  //data64: UINt64 absolute data;
Begin
  stream.read(data, 10);
  //-1.0 or +1.0 //Integer( because otherwise intermidiate conversion to Int64 )
  result := Integer(1- Ord(data[9]>127)*2);
  //clear Sign Bit
  data[9] := data[9] And 127;
  // Calculate Exponent
  Exponent := ((data[9] Shl 8) Or data[8]) - 16382;
  result :=(dataDW[0]* rezDW+dataDW[1])*rezDW*result;
  //alternative Uint64
  //result := data64* rez64*result;
  result := result * power(2, Exponent);
End;
 
Procedure Write10ByteExtended(val: double; Const Stream: TStream);
// Soll eine 8-byte Extended abspeichern, als sei sie 10-Byte Groß
Var
  OutData: Array[0..9] Of byte;
  tmpdbl : double;
  tmpBArr : Array[0..7] of byte absolute tmpdbl;
  tmpWArr : Array[0..3] of Word absolute tmpdbl;
  tmpInt64 : Int64 absolute tmpdbl;
  Exponent,
  VZ     : Word;
Begin
  tmpdbl := val;
  Vz :=  Ord(tmpdbl<0) *32768;
  //Exponent formen
  Exponent := tmpWArr[3]-Vz;
  Exponent := (Exponent shl 1) shr 5 +(-1023+16383) + Vz;
  //Mantisse schieben und oberstes Bit setzen
  tmpInt64 := (tmpInt64 shl 11) OR (1 shl 63);
  //Mantisse kopieren
  move(tmpBArr[0],OutData[0],8);
  OutData[8] := lo(Exponent);
  OutData[9] := hi(Exponent);
  stream.write(OutData[0], 10);
End;
 
const
 cFILENAME = 'x68Out.dat';
Var
//  f: TFilestream;
  f: TMemorystream;
  s: Single;
  d: Double;
  e: Extended;
Begin
//  f := TFileStream.Create(cFILENAME, fmCreate Or fmOpenReadWrite);
  f := TMemoryStream.Create;
  s := 12.4;
  d := 23.4;
  f.Write(s, sizeof(s));
  f.Write(d, sizeof(d));
  e := -pi;
  writeln(e,' Extended');
  d := -e;
  writeln(d,' Double');
  f.Write(e, sizeof(e));
  f.Write(e, sizeof(-e));
  Write10ByteExtended(e, f);
  Write10ByteExtended(-e, f);
  // -- Write Ende
 
  f.Position := 0;
  s := 0;
  d := 0;
  f.read(s, sizeof(s));
  f.read(d, sizeof(d));
  e := -10;
  f.read(e, sizeof(e));
  writeln(e,' Extended');
  f.read(e, sizeof(e));
  writeln(e,' Extended');
  e := Read10ByteExtended(f);
  writeln(e,' Double');
  e := Read10ByteExtended(f);
  writeln(e,' Double');
  f.free;
  // -- Read Ende
  writeln(format('%0.3f', [s]));
  writeln(format('%0.3f', [d]));
end.
(*
-3.14159265358979323851E+0000 Extended
 3.1415926535897931E+000 Double
-3.14159265358979323851E+0000 Extended
-3.14159265358979323851E+0000 Extended
-3.14159265358979311600E+0000 Double
 3.14159265358979311600E+0000 Double
12.400
23.400
*)
 


Gruß Horst

Antworten