Datentyp Comp in String umwandeln

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Iceman_03
Beiträge: 8
Registriert: Fr 18. Jun 2010, 11:57

Datentyp Comp in String umwandeln

Beitrag von Iceman_03 »

Hallo zusammen,

ich verwende eine Variable mit dem Datentyp Comp um darin die "Nummer einer Versandeinheit" (NVE/SSCC) zu speichern.

NVE's sind 18-stellig und beginnen immer mit "1".
Eine NVE ist wie folgt aufgebaut : 1bbbbbbbxxxxxxxxxP, wobei b eine Basisnummer darstellt, die in Deutschland mit "40" beginnt, x eine Fortlaufende Nummer ist und P eine Prüfziffer darstellt.
Eine NVE kann also zum Beispiel den Wert 140123450005778024 haben, was sich mit dem Datentyp Comp darstellen lassen sollte.
Comp -> -9.2e18..9.2e18 -> -9223372036854775808 .. 9223372036854775807

Im Prinzip ist es aber für mein Problem egal wie eine NVE aufgebaut ist:

Ich benötige den Wert der Comp-Variablen als String, allerdings bekomme ich mit folgenden Funktionen falsche Werte:

Var NVE : Comp; MyString : String;

Str(NVE:1:0,MyString) -> 140123450005778024 wird zu 140123450005778000
MyString := FloatToStrF(NVE,ffFixed,1,0) -> 140123450005778024 wird zu 140123450005778020

Es wird also bei beiden Funktionen gerundet wo eigentlich nicht gerundet werden darf.

Das Problem ist nicht die Comp-Variable, dort ist Wert korrekt gespeichert.
Wenn ich den gleichen Quellcode Mit Borland Turbo Pascal 7.0 kompiliere liefert die Funktion Str(Comp:1:0,MyString) korrekte Werte.

Kennt jemand eine andere Möglichkeit die Comp-Variable in einen korrekten String ohne Rundungsfehler zu konvertieren?

Vielen Dank für Eure Hilfe

Wolfgang
Borland Pascal 7.0 | Delphi 5 Enterprise | Delphi XE6 Enterprise | Lazarus 1.2.2 - FPC 2.6.4 Win7

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Datentyp Comp in String umwandeln

Beitrag von mse »

Vielleicht geht es mit int64 besser.

Iceman_03
Beiträge: 8
Registriert: Fr 18. Jun 2010, 11:57

Re: Datentyp Comp in String umwandeln

Beitrag von Iceman_03 »

Hallo mse,

ja, das Problem ist nur, dass mein Programm auf unterschiedlichen Systemen läuft, unter anderem auch noch auf DOS-Rechnern.
Deshalb muss ich immer 2 Versionen kompilieren, eine unter TP7 für 16-Bit DOS und eine unter FPC für 32-Bit Windows.
Da es unter TP7 nur Comp gibt hatte ich mich dafür entschieden, damit ich nicht so viel am Quellcode ändern muss.

Hier ein workarround der funktioniert:

Code: Alles auswählen

Function  CompToStr(Zahl:Comp) : ShortString;
Var Help                     : ShortString;
    I64                      : Int64;
begin
  Move(Zahl,I64,8);
  Str(I64:1,Help);
  CompToStr := Help;
end;
 
FloatToStrF arbeitet übrigens auch bei Int64 nicht korrekt.

Da werde ich wohl wieder einmal ein bisschen mit {$IFDEF} rumbasteln müssen.

Bleibt trotzdem der Fakt, dass FPC hier wohl einen Bug hat, oder sehe ich das falsch?
-> Ich arbeite mit Lazarus 1.2.2, FPC 2.6.4 auf Win7/32

Ich wäre für weitere Hinweise dankbar.

Gruß

Wolfgang
Borland Pascal 7.0 | Delphi 5 Enterprise | Delphi XE6 Enterprise | Lazarus 1.2.2 - FPC 2.6.4 Win7

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Datentyp Comp in String umwandeln

Beitrag von Michl »

Ich kann da eine unterschiedliches Verhalten feststellen

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var
  r: Comp;
  i: Int64;
begin
  r:=140123450005778024;
  i:=140123450005778024;
  WriteLn(FloatToStrF(r, ffFixed, 1, 0));
  WriteLn(IntToStr(i));
end;
liefert unter Lazarus 1.2.4:
140123450005778020
140123450005778024

unter Lazarus 1.3-Trunc FPC 2.7.1-Trunc beides identische Werte:
140123450005778024
140123450005778024

Generell hilft es möglicherweise den String selber mit kleineren Varaiblen zusammenzusetzen bzw. diesen zu parsen. Zum Thema passend ist auch: http://www.lazarusforum.de/viewtopic.php?f=10&t=6852

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Iceman_03
Beiträge: 8
Registriert: Fr 18. Jun 2010, 11:57

Re: Datentyp Comp in String umwandeln

Beitrag von Iceman_03 »

Hallo Michl,

danke für Deine Antwort.

Ich habe das Fehlverhalten bei der von mir installierten Version (Lazarus 1.2.2, FPC 2.6.4) weiter eingegrenzt.

Str(Comp,String) liefert falsche Werte sobald Comp größer als 1000000000000000 (16 Stellen) ist.
FloatToStrF(Comp) und FloatToStrF(Int64) liefern falsche Werte sobald der Wert größer als 100000000000000000 (18-Stellen) ist.

Str(Int64,String) was ja identisch ist mit IntToStr(Int64) liefert, soweit ich das getestet habe immer korrekte Werte.

Code: Alles auswählen

 
Procedure Test_Comp_Int64;
var c                        : Comp;
    i                        : Int64;
    s                        : String;
begin
  c := 1000000000000001;
  i := 1000000000000001;
  Str(i,s);
  Writeln('Str(Int64)         : ',s);
  Writeln('FloatToStrF(Int64) : ',FloatToStrF(i, ffFixed, 1, 0));
  Str(c:1:0,s);
  Writeln('Str(Comp)          : ',s);
  Writeln('FloatToStrF(Comp)  : '+FloatToStrF(c, ffFixed, 1, 0));
 
  Writeln;
  c := 100000000000000001;
  i := 100000000000000001;
  Str(i,s);
  Writeln('Str(Int64)         : ',s);
  Writeln('FloatToStrF(Int64) : ',FloatToStrF(i, ffFixed, 1, 0));
  Str(c:1:0,s);
  Writeln('Str(Comp)          : ',s);
  Writeln('FloatToStrF(Comp)  : '+FloatToStrF(c, ffFixed, 1, 0));
  Pause;
end; 
Liefert bei mir folgendes Ergebnis:

Code: Alles auswählen

 
Str(Int64)         : 1000000000000001
FloatToStrF(Int64) : 1000000000000001
Str(Comp)          : 1000000000000000
FloatToStrF(Comp)  : 1000000000000001
 
Str(Int64)         : 100000000000000001
FloatToStrF(Int64) : 100000000000000000
Str(Comp)          : 100000000000000000
FloatToStrF(Comp)  : 100000000000000000
 
Kannst Du das bitte noch einmal auf den neueren Compiler-Versionen testen, ob der Fehler dort behoben wurde.
Eventuell sollte ich dann wohl mal über ein Upgrade nachdenken, wenn der Fehler in den neuen Versionen bereits behoben wurde.

Vielen Dank im voraus.
Borland Pascal 7.0 | Delphi 5 Enterprise | Delphi XE6 Enterprise | Lazarus 1.2.2 - FPC 2.6.4 Win7

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Datentyp Comp in String umwandeln

Beitrag von Michl »

Ich habe mal den Test ein bischen anders gemacht, damit eine Zufallsübereinstimmung möglichst ausgeschlossen werden kann:

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
  c: Comp;
  j: Int64;
  Base: Int64;
  s1, s2, s3, s4, s5: String;
begin
  i:=0;
  Base:=10;
  repeat
    inc(i);
    if i mod 10000 = 0 then begin
      base:=base*10;
      Caption:='Base = 10^'+IntToStr(i div 10000);
    end;
 
    j:=Random(Base);
    c:=j;
 
    Str(j, s1);
    s2:=FloatToStrF(j, ffFixed, 1, 0);
    s3:=IntToStr(j);
    Str(c:1:0, s4);
    s5:=FloatToStrF(c, ffFixed, 1, 0);
  until (s1<>s2) or (s1<>s3) or (s1<>s4) or (s1<>s5);
 
  ShowMessage('Erste Abweichung bei Base 10^'+
    IntToStr(i div 10000)+LineEnding+
    'Str(Int64)         : '+s1+LineEnding+
    'FloatToStrF(Int64) : '+s2+LineEnding+
    'IntToStr(Int64)    : '+s3+LineEnding+
    'Str(Comp)          : '+s4+LineEnding+
    'FloatToStrF(Comp)  : '+s5);
end;   

Test unter Win7 64bit, Lazarus jeweils 32bit:

Eine Abweichung unter Lazarus 1.2.4 (FPC 2.6.4) wird bei einer Potenz von 10^15 erreicht. Unter Lazarus-Trunc 1.3 und FPC-Trunc 2.7.1 kommt es zu keiner Abweichung (bis zur Bereichsüberschreitung -> läuft somit wieder von vorn los, bis?!).

Der Bug/das Feature ist somit unter FPC 2.6.4 -> 2.7.1 anders. Doch beachte bitte, falls Du Dich entschließt die FPC-Trunc-Version zu benutzen, da kommen noch einige andere Verhaltensabweichungen auf Dich drauf zu! Speziell Strings können zu bestehenden Projekten einiges an Portierungsaufwand bedeuten, was aber schon hundert mal im Forum diskutiert wurde (und hoffentlich nicht hier schon wieder :roll: )...

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

BeniBela
Beiträge: 320
Registriert: Sa 21. Mär 2009, 17:31
OS, Lazarus, FPC: Linux (Lazarus SVN, FPC 2.4)
CPU-Target: 64 Bit

Re: Datentyp Comp in String umwandeln

Beitrag von BeniBela »

Es geht nur in 2.7.1

2.6.x ist voller Bugs http://bugs.freepascal.org/view.php?id=24131 http://bugs.freepascal.org/view.php?id=23196 (in 2.6.0 auch http://bugs.freepascal.org/view.php?id=23828 (<- der ist besonders nett. Da denkt man, so blöd kann doch niemand sein...) http://bugs.freepascal.org/view.php?id=16907 )

Ich habe damals eigene Funktionen geschrieben, die immer perfekte Ergebnisse liefern (sollen), aber entsprechend langsam sind. Zwar nicht für Comp, aber das geht hier:

Code: Alles auswählen

c := 100000000000000001;  
writeln(BigDecimalToStr(FloatToBigDecimal(extended(c))));
Michl hat geschrieben:ISpeziell Strings können zu bestehenden Projekten einiges an Portierungsaufwand bedeuten, was aber schon hundert mal im Forum diskutiert wurde (und hoffentlich nicht hier schon wieder :roll: )...

2.7.1 verwendet doch auch die alten Strings, wenn man es nicht extra umstellt?

Iceman_03
Beiträge: 8
Registriert: Fr 18. Jun 2010, 11:57

Re: Datentyp Comp in String umwandeln

Beitrag von Iceman_03 »

@Michl: Vielen Dank für den Test.
@BeniBela: Danke für die Antwort. Ich verwende jetzt erst einmal folgende Lösung:

Code: Alles auswählen

Function  CompToStr(c:Comp) : String;
Var s : ShortString; 
    i : Int64;
begin  
  Move(c,i,8);  
  Str(i,s);  
  CompToStr := s;
end;
Diese Lösung scheint keine Fehler zu liefern.

Danach werde ich mich mit der Version 2.7.1 beschäftigen. Wenn da die Features :wink: behoben sind und mich keine anderen Überraschungen (Strings) ereilen, sollte das die bessere Lösung sein.

Danke noch einmal an alle für die schnelle Hilfe!
Borland Pascal 7.0 | Delphi 5 Enterprise | Delphi XE6 Enterprise | Lazarus 1.2.2 - FPC 2.6.4 Win7

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Datentyp Comp in String umwandeln

Beitrag von mse »

Bei Gleitkommazahlen sollte man sich nie auf die letzte(n) Stellen verlassen. Deine Lösung mit der Konvertierung nach int64 ist sicher die richtige.
Für positive Werte funktioniert auch

Code: Alles auswählen

 
 str(int64(c),result);
 
Bei FPC 2.6.4 stimmt es auch bei negativen Werten. Dies ist möglicherweise ein weiterer Fehler, da "comp" AFAIK Einerkomplement und nicht Zweierkomplement codiert ist...

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Datentyp Comp in String umwandeln

Beitrag von Michl »

BeniBela hat geschrieben:2.7.1 verwendet doch auch die alten Strings, wenn man es nicht extra umstellt?
Naja, will eigentlich keine Diskussion deswegen, doch z.B. unter FPC 2.6.4 ist UTF8String = AnsiString = String unter 2.7.1 ist UTF8String = AnsiString(CP_UTF8). Eine Zuweisung ohne Konvertierung eines Strings -> UTF8String war unter 2.6.4 möglich unter 2.7.1 nicht. Das war mir mal mächtig auf die Füße gefallen und hat mir einige graue Haare gebracht, bis ich verstanden hatte, warum, wieso und weshalb.

Auch habe ich noch einen Bugreport offen, dass bString:=UTF8Decode(UTF8Encode(aString)) nicht unbedingt einen verständlichen String zur Folge hat und man sich mit Insert behelfen muss (was unter 2.6.4 noch problemlos ging).

Aber FPC 2.7.1 ist mMn auf einem guten Weg und man hat die Chance Bugs aufzudecken, die evtl. recht schnell behoben werden, oder man kann einen eigenen Patch vorschlagen und somit aktiv zur Verbesserung von FPC/Lazarus beitragen. Daher kein Grund zum Meckern, da man sich ja an die eigene Nase fassen kann :)

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Iceman_03
Beiträge: 8
Registriert: Fr 18. Jun 2010, 11:57

Re: Datentyp Comp in String umwandeln

Beitrag von Iceman_03 »

Kann mir jemand einen Tipp geben, wo ich mich in das Thema "String | AnsiString | UTF8String" mal einlesen kann?

Bisher habe ich das Thema ignoriert, vor allem weil ich, im Moment den Quellcode immer noch TP7 kompatibel halten muss. Da kommen AnsiString und UTF8String für mich sowieso nicht in Frage. Deshalb kompiliere ich auch unter FP den kompletten Code mit {$H-}. Bisher hatte ich damit nur zu tun, wenn es um externe Daten (Import|Export) ging. Aber dafür habe ich mir eigene Funktionen geschrieben die eine CP850-DOS-String in ISO8859-1 oder UTF8 oder umgekehrt konvertieren.

Ich hatte gestern schon mal gesucht, aber auf die schnelle nichts gefunden. Kann mir bitte jemand sagen, wo ich die unterschiedlichen Versionen von FPC herunterladen kann? Gab/gibt es überhaupt Versionen zwischen 2.6.4 und 2.7.1 und wenn ja wo finde ich die? Ich würde gerne versuchen ob eine andere Version für meine Zwecke besser geeignet ist.

Danke!
Borland Pascal 7.0 | Delphi 5 Enterprise | Delphi XE6 Enterprise | Lazarus 1.2.2 - FPC 2.6.4 Win7

mischi
Beiträge: 206
Registriert: Di 10. Nov 2009, 18:49
OS, Lazarus, FPC: macOS, 10.13, lazarus 1.8.x, fpc 3.0.x
CPU-Target: 32Bit/64bit

Re: Datentyp Comp in String umwandeln

Beitrag von mischi »

Iceman_03 hat geschrieben:Ich hatte gestern schon mal gesucht, aber auf die schnelle nichts gefunden. Kann mir bitte jemand sagen, wo ich die unterschiedlichen Versionen von FPC herunterladen kann? Gab/gibt es überhaupt Versionen zwischen 2.6.4 und 2.7.1 und wenn ja wo finde ich die?
Release Versionen haben immer gerade Nummern, z.B. 2.2.0, 2.6.2. 2.6.4 ist die aktuelle Version, die released wurde. Die Version, die momentan entwickelt wird, hat eine ungerade Nummer, z.B. die schon erwähnte 2.7.1. Wenn die so weit für ein Release fertig ist und veröffentlicht wird, wird sie zur 2.8.0. Falls noch einmal ein Version 2.6 mit Bugfixes veröffentlicht wird, wird es dann die 2.6.6 sein. Die 2.7.1 ist die momentane Revision im svn Branch "trunk". Sie ändert sich also von Tag zu Tag und kann auch mal überhaupt nicht gehen. Meistens aber doch. Vielleicht freut es dich, dass in 2.7.1 das Target i8086-msdos dazu kommt.

Michael.
MiSchi macht die fink-Pakete

Antworten