Fixpoint - library bzw. sinnvolles Vorgehen

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Lemmy
Beiträge: 57
Registriert: Do 23. Feb 2017, 06:18

Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von Lemmy »

Servus,

ich habe da ein Stück Programm, dasim Grunde eine Datenaktualisierung macht (d.h. Daten aus CSV Dateien in eine Datenbank schiebt und dann noch ein paar Berechnungen durch führt. Das Teil ist jetzt ein paar Jahre im Einsatz. Die Berechnungen werden in Double gemacht, obwohl es um Finanzberechnungen geht.

Grund für den Double dürfte damals die Performance gewesen sein, weil im Vergleich Currency rund 30-40% langsamer ist. Kennt hier jemand eine Fixpoint Library für FPC die ausreichend schnelle ist? D.h. nicht langsamer als Double....

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von af0815 »

Die frage ist schon mal, wo die Berechnung stattfindet. Lokal oder am DB-Server (oder ist es gar eine Desktopdatenbank). Man muss auch dann sehen ob nicht die Konversion von und zur DB nicht dann Fehlerbehaftet ist (auch dort wird manchmal konvertiert, das sich die Balken biegen).
Die Frage ist ob Currency noch wirklich langsamer ist ?! Und wenn eine Fixpoint Lib, dann bezweifle ich stark, das die schneller als Double sein kann. Da kann man froh sein, wenn die schneller als Currency sein wird :-)
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Lemmy
Beiträge: 57
Registriert: Do 23. Feb 2017, 06:18

Re: Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von Lemmy »

af0815 hat geschrieben:Die frage ist schon mal, wo die Berechnung stattfindet. Lokal oder am DB-Server (oder ist es gar eine Desktopdatenbank). Man muss auch dann sehen ob nicht die Konversion von und zur DB nicht dann Fehlerbehaftet ist (auch dort wird manchmal konvertiert, das sich die Balken biegen).
Die Frage ist ob Currency noch wirklich langsamer ist ?! Und wenn eine Fixpoint Lib, dann bezweifle ich stark, das die schneller als Double sein kann. Da kann man froh sein, wenn die schneller als Currency sein wird :-)

lokal im Code. Der Produktivcode ist wie gesagt rund 40 % langsamer was mir ein Testprogramme (1000 x 1000x 1.1 auf Currency addieren) so im Grunde bestätigt hat.
Konvertierung in Richtung datenbank: Was soll da von Double auf Double konvertiert werden? Double ist halt ungenau - und im Vergleich zur Currency Berechnung zeigen sich halt doch immer mehr Unterschiede.

Eine externe Lib habe ich inzwischen gefunden (BigDecimal) - ist dann aber wie du sagst, extremst langsam.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von af0815 »

Lemmy hat geschrieben:Konvertierung in Richtung datenbank: Was soll da von Double auf Double konvertiert werden? Double ist halt ungenau

Täusch dich nicht - Double in Pascal muss nicht mit dem Typ in der DB zusammenstimmen.

MSSQL siehe auch die Diskussion: https://stackoverflow.com/questions/120 ... sql-server -> real, float, decimal(x,y) ?!

Was nehmen wir da wohl, bzw. was bleibt an Ungenauigkeit hängen :-) Du hast noch keine Daten von der DB bekannt gegeben.

Die Frage ist was ist wichtiger ?! Speed oder Genauigkeit.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von Winni »

Moin!

Double hat 15 Stellen Genauigkeit. D.H. der Ärger fängt schon ab 1 (deutsche) Billion an, also 1000 Milliarden. Hast Du solche Summen in der Datenbank?

Außerdem sind die Berechnungen bei Datenbankanwendungen ziemlich egal. Das wichtige und der Faschenhals ist das Lesen und Schreiben auf die DB. Da muss man optimieren, nicht bei irgendwelchen Zins- oder MwSt-Berechnungen.

Winni

Lemmy
Beiträge: 57
Registriert: Do 23. Feb 2017, 06:18

Re: Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von Lemmy »

af0815 hat geschrieben:Du hast noch keine Daten von der DB bekannt gegeben.


DB ist MariaDB 5.5. Zieltyp dort wäre ein Decimal - wie gesagt in meinem jugendlichen Leichtsinn dachte ich Currency = verkappter Integer, also schnell. Aber scheinbar wird dort ständig rumkonvertiert, was entsprechend Zeit kostet.

af0815 hat geschrieben:Die Frage ist was ist wichtiger ?! Speed oder Genauigkeit.


beides :-) Laufzeit bei größeren Importen liegt bei 4-6h, da ist eine halbe Stunde mehr nicht akzeptabel.
Wenn ich nur additionen / Subtraktionen hätte würde ich versuchen das ganze über einen INT64 abzubilden und an den Schnittstellen nach außen dann das Komma hin und herschieben, aber ich habe da auch Multiplikation und Division und meine verkümmerten Mathe/Rechenkenntnisse haben mir noch keine Lösung gezeigt.

Lemmy
Beiträge: 57
Registriert: Do 23. Feb 2017, 06:18

Re: Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von Lemmy »

Winni hat geschrieben:Double hat 15 Stellen Genauigkeit. D.H. der Ärger fängt schon ab 1 (deutsche) Billion an, also 1000 Milliarden. Hast Du solche Summen in der Datenbank?


ok, dann erzähl mir mal, warum hier 2 unterschiedliche Ergebnisse raus kommen:

Code: Alles auswählen

 
procedure TForm1.Button1Click(Sender: TObject);
var
 Ergebnis1: Currency;
 Ergebnis2: Double;
 idx: Integer;
begin
  Ergebnis1 := 1;
  Ergebnis2 := 1;
 
  for idx := 0 to 300 do
  begin
    Ergebnis1 := Ergebnis1 * 1.01;
    Ergebnis2 := Ergebnis2 * 1.01;
  end;
 
  label1.Caption:= FloatToStr(Ergebnis1);
  label2.Caption:= FloatToStr(Ergebnis2);
end;   
 


Nicht erst an der unsicheren vierten Stelle von Currency - sondern schon an der dritten Stelle. [Edit: Wobei ich zugebe, dass ich da etwas unfair bin :-) ]

Winni hat geschrieben:Außerdem sind die Berechnungen bei Datenbankanwendungen ziemlich egal. Das wichtige und der Faschenhals ist das Lesen und Schreiben auf die DB. Da muss man optimieren, nicht bei irgendwelchen Zins- oder MwSt-Berechnungen.


nein. Nicht, wenn die Berechnungen mehrere Stunden laufen, weil die Datenmenge entsprechend sind. Klar kostet auch Daten holen und schreiben Zeit, aber da wir an der Anwendung seit 15 Jahren arbeiten, denke ich dass wir da aktuell recht gut aufgestellt sind.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von af0815 »

Da wird man ohne genaue Analyse des Laufzeitverhaltens nicht wirklich weiterkommen. http://download.nust.na/pub6/mysql/doc/ ... -math.html Da steht was drinnen über die Genauigkeit am Server. Das sollte mal ein Schritt sein, damit in der DB ein richtig geformter Wert ankommt bzw. bestehen bleibt.

Für mich stellt sich da die Frage ob man am Server mit Berechnungen nicht gleich besser dran ist. Siehe auch hier http://download.nust.na/pub6/mysql/doc/ ... mples.html . Ich habe mit MariaDB leider zuwenig Erfahrung, da wir speziell den MS-SQL bei unseren Kunden verwenden müssen (auch unter Linux :-) ). Allerdings ist mir aufgefallen, das sehr viel Finanzmathematik Einzug in die SQL-DBs gehalten hat. Herstellerspezifisch, na klar :-) Nur die Ergebnisse auf Datenmengen können sich sehen lassen. Auf einem SQL-Server können Mengenoperation erstaunlich performant sein. Bei einem kurzen Blick auf MariaDB/MySQL, kommt man dort nicht in Versuchung das so zu machen.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von wp_xyz »

Lemmy hat geschrieben:ok, dann erzähl mir mal, warum hier 2 unterschiedliche Ergebnisse raus kommen:

Code: Alles auswählen

 
procedure TForm1.Button1Click(Sender: TObject);
var
 Ergebnis1: Currency;
 Ergebnis2: Double;
 idx: Integer;
begin
  Ergebnis1 := 1;
  Ergebnis2 := 1;
 
  for idx := 0 to 300 do
  begin
    Ergebnis1 := Ergebnis1 * 1.01;
    Ergebnis2 := Ergebnis2 * 1.01;
  end;
 
  label1.Caption:= FloatToStr(Ergebnis1);
  label2.Caption:= FloatToStr(Ergebnis2);
end;   
 


Das erinnert mich an diesen Bug: https://bugs.freepascal.org/view.php?id=33963. Dieser ist seit Ende Dezember gefixt, aber nur im FPC Trunk.

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von Warf »

Lemmy hat geschrieben:Grund für den Double dürfte damals die Performance gewesen sein, weil im Vergleich Currency rund 30-40% langsamer ist. Kennt hier jemand eine Fixpoint Library für FPC die ausreichend schnelle ist? D.h. nicht langsamer als Double....


Nö, gibts nicht und kanns auch nicht geben. IEEE 754 zahlen (Single, Double, Real) werden über hardware Multiplikationswerke in der CPU verrechnet, die eigens dafür gebaut wurden. Software auf einer general purpose hardware kann nie schneller sein als custom hardware.

Ich denke mal schneller als currency wird es nicht werden. Andere Frage, kann man das Problem eventuell irgendwie parallelisieren eventuell sogar auf der GPU?
Beispiel, du hast eine lange liste mit multiplikationen die du machen must, dann nimm 4 threads, thread1 multipliziert alle zahlen von lst[0] bis lst[len div 4], thread2 alle zahlen von lst[len div 4] bis lst[len div 2], etc. am ende musst du dann nur noch 4 zahlen miteinander multiplizieren und du hast deine rechenzeit geviertelt.
Wenn du durch currency 40% länger brauchst, dafür aber auf 4 cores deine geschwindigkeit vervierfachst, bist du am ende des tages immernoch schneller.

Ansonsten könntest du mal einen blick auf das LLVM target vom FPC werfen, wenn es um berechnungen geht ist LLVMs optimizer richtig gut. Du könntest bestimmt so 20% damit rausholen

Winni hat geschrieben:Double hat 15 Stellen Genauigkeit. D.H. der Ärger fängt schon ab 1 (deutsche) Billion an, also 1000 Milliarden. Hast Du solche Summen in der Datenbank?


Wenn man nur mit ganzen Zahlen rechnet stimmt das. Das problem ist das IEEE 754 Zahlen mit Fractions von 2 arbeitet, alles was sich also nicht durch das addieren von zweierpotenzen ausdrücken lässt ist also periodisch.
Wir benutzen das 10er system, was in primfaktorzerlegung 5*2 ist, alle zahlen aus dem 10er system werden also als kombination aus 5er und 2er potenzen dargestellt. 0,1 z.b. ist 0,5 (2^-1) * 0,2(5^-1). Da sich 0,2 nicht als zweierpotenz darstellen lässt, kann es es nicht, und damit auch 0,1, im zweresystem dargestellt werden.

Das ist wie 1/3 (3^-1) sich nicht im 10er system darstellen lässt (also periodisch ist), weil sich 3 nicht als kombination von 2er und 5er potenzen darstellen lässt

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von Winni »

Tja, Herr Lemmy!


Lemmy hat geschrieben:
Winni hat geschrieben:Double hat 15 Stellen Genauigkeit. D.H. der Ärger fängt schon ab 1 (deutsche) Billion an, also 1000 Milliarden. Hast Du solche Summen in der Datenbank?


ok, dann erzähl mir mal, warum hier 2 unterschiedliche Ergebnisse raus kommen:

Code: Alles auswählen

 
procedure TForm1.Button1Click(Sender: TObject);
var
 Ergebnis1: Currency;
 Ergebnis2: Double;
 idx: Integer;
begin
  Ergebnis1 := 1;
  Ergebnis2 := 1;
 
  for idx := 0 to 300 do
  begin
    Ergebnis1 := Ergebnis1 * 1.01;
    Ergebnis2 := Ergebnis2 * 1.01;
  end;
 
  label1.Caption:= FloatToStr(Ergebnis1);
  label2.Caption:= FloatToStr(Ergebnis2);
end;   
 


Nicht erst an der unsicheren vierten Stelle von Currency - sondern schon an der dritten Stelle. [Edit: Wobei ich zugebe, dass ich da etwas unfair bin :-) ]

Winni hat geschrieben:Außerdem sind die Berechnungen bei Datenbankanwendungen ziemlich egal. Das wichtige und der Faschenhals ist das Lesen und Schreiben auf die DB. Da muss man optimieren, nicht bei irgendwelchen Zins- oder MwSt-Berechnungen.


nein. Nicht, wenn die Berechnungen mehrere Stunden laufen, weil die Datenmenge entsprechend sind. Klar kostet auch Daten holen und schreiben Zeit, aber da wir an der Anwendung seit 15 Jahren arbeiten, denke ich dass wir da aktuell recht gut aufgestellt sind.



Da würde ich mir doch mal die Definition von currency durchlesen. Es hat vier (4!!) Nachkommastellen. Da tritt dann bei Deinem Loop schon innerhalb von 300 Durchläufen die Ungenauigkeit in der 3 Stelle auf, während Double kein FESTkomma ,hat sondern ein Fließkomma, also exact bleibt.

Die Definition von curreny ist hier: .
https://wiki.freepascal.org/Currency/de

Hoffentlich habt ihr nicht all die letzten Jahre falsche Werte mittels currency berechnet.

Winni

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von Winni »

Hi!

Wiedergefunden:

Ein Artikel über die interne Darstellung der verschiedenen Fließkomma-Werte von dem neulich verstorbenen Rudy Venthuis:
(english)

http://rvelthuis.de/articles/articles-floats.html

Hier steht auch, was ich noch undeutlich in Erinnerung hatte:

currency ist nix anderes als ein spezialisierter 64-Bit-Integer.
Sie rechnen intern mit Hundersteln Cent auf integer basis. Da fliegt schon Einiges weg wegen der Berechnungen mit div.
Auf der anderen Seite sind integer Operationen natürlich viel schneller als Fließkomma-Operationen.

Wenn die Genauigkeit von currency ausreicht dann bleib dabei. Es ist schlicht das Schnellste. Wenn nicht musst Du double nehmen.

Wenn Du CSV Listen verarbeitest, dann kannst Du ja mal darüber nachdenken, jedem core in der CPU einen thread zur Verarbeitung zu spendieren . Das bringt Geschwindigkeit .

Winni

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von Warf »

Winni hat geschrieben:Wenn die Genauigkeit von currency ausreicht dann bleib dabei. Es ist schlicht das Schnellste. Wenn nicht musst Du double nehmen.


Double ist für jede form von Monetären berechnungen gänzlich ungeignet, Beispiel:

Code: Alles auswählen

program Test;
 
{$MODE OBJFPC}{$H+}
 
var
d1, d2, d3: Double;
c1, c2, c3: Currency;
begin
  c1 := 0.1;
  d1 := 0.1;
  d2 := d1 * 3;
  c2 := c1 * 3;
  d3 := 0.3;
  c3 := 0.3;
  if d2 = d3 then Writeln('Double: 3 * 0.1 = 0.3');
  if c2 = c3 then Writeln('Currency: 3 * 0.1 = 0.3');
end.


Das If ist nur für currency True, nicht für Double, den Grund dafür hab ich in einem vorrigen Post bereits erklärt, weder 0.1 noch 0.3 lässt sich als IEEE 754 darstellen. Das ist für finanzielle anwendungen komplett inakzeptabel, während rundungsfehler im berech von 10^-5 vollkommen akzeptabel sind. Und ich möchte an dieser stelle mal anmerken das weder 0.1 noch 0.3 jetzt besonders seltene zahlen sind, die in finanziellen anwendungen nicht vorkommen. Übrigens, die zahlen 0.2, 0.3, 0.4, 0.6, 0.7, 0.8 und 0.9 können auch nicht korrekt dargestellt werden. Das einzige was double präzise darstellen kann an Fraktionen ist 0.5, 0.25, 0.75, 0.125, 0.375, etc. also alles was sich aus additionen von zweierpotenzen darstellen lässt. Wenn man die einfach mal runterschreibt sind das verdammt wenige Zahlen. D.h. immer wenn du einen artikel hast dessen cent beträge nicht 25, 50 oder 75 ist, hast du nen rundungsfehler bei double drin

Soweit ich weiß kann man sogar rechtlich belangt werden wenn man double statt fixpunkt arithmetik mit mindestens 4 nachkommastellen für finanzielle berechnungen benutzt (da daraus nich unerheblicher finanzieller schaden entstehen kann). Man sollte niemals, absolut niemals double für Finanzen verwenden

Benutzeravatar
Winni
Beiträge: 1577
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von Winni »

Hi!

Wer Fließkommazahlen auf Gleichheit prüft, der hat von diesem Datentyp nix verstanden.
Da wir nicht mehr wie in Wikingerzeiten mit Hacksilber arbeiten, sondern eine minimale Einheit - nämlich den Cent - besitzen, kann dann am Ende der Rechnung auf diesen gerundet werden. Wesentlich genauer als mit currency zu rechnen.

Außerdem möchte ich gerne mal den Paragraphen sehen, wo die finanziellen Berechnungen mit Double verboten sind. Ist das nun eine urbane Legende? Oder bringt das den Banken finanzielle Nachteile, wenn man mit Double rechnet? Weil es genau ist?

Winni

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Fixpoint - library bzw. sinnvolles Vorgehen

Beitrag von Warf »

Winni hat geschrieben:Wer Fließkommazahlen auf Gleichheit prüft, der hat von diesem Datentyp nix verstanden.

Ok:

Code: Alles auswählen

program Project1;
 
{$mode objfpc}{$H+}
 
var
  Kontostand: Double;
  Auszahlung: Double;
  i: Integer;
begin
  Kontostand := 0.3;
  Auszahlung:=0.1;
  for i:= 0 to 2 do
  begin
    if Kontostand < Auszahlung then
      WriteLn('Buchung nicht möglich, nicht genug Geld auf dem Konto')
    else
      WriteLn('Buchung erfolgreich');
    Kontostand -= Auszahlung;
  end;
end.     


Toll für ne Finanzsoftware, sagt mir ich hab nicht genug geld obwohl ich offensichtlich genug Geld für 3 transaktionen hab...
Oder darf ich jetzt auch keine Subtraktionen und < vergleiche mehr machen weil ich es "nicht verstanden" habe?

Winni hat geschrieben:Außerdem möchte ich gerne mal den Paragraphen sehen, wo die finanziellen Berechnungen mit Double verboten sind. Ist das nun eine urbane Legende? Oder bringt das den Banken finanzielle Nachteile, wenn man mit Double rechnet? Weil es genau ist?


Nein, als entwickler bist dazu verpflichtet nach dem Stand der Kunst (Stand der Technik) zu arbeiten. Ob dus willst oder nicht, Fixpunktarithmetik ist der Standard in Finanzanwendungen, daher ist es Stand der Kunst.

Nehmen wir das Beispiel oben, du als Bank implementiert eine Finanzsoftware so mit Double wie das beispiel oben, ich bin selbstständig und hab genug Geld auf dem Konto für alle ausgaben für einen Job. Jetzt kann ich was wichtiges nicht kaufen weil deine Bank mir sagt: Du hast nicht genug Geld. Damit kann ich die Deadline nicht einhalten und es entsteht Finanzieller Schaden für mich. Ich rechne alle ein und Auszahlungen mit dem Taschenrechner (der übrigens Dezimalsystem basierte Fixpunktarithmetik verwendet, wie fast alle vernünftigen Taschenrechner) nach und komme drauf das ich genug geld auf dem konto haben müsste (siehe beispiel oben), und verklage dich.

Bitte für ein Argument warum das was du getan hast stand der Kunst war, wobei kein anderes Finanzunternehmen es so macht und der schaden offensichtlich durch Fixpunktarithmetik verhindert werden könnte.

Klar kann auch schaden durch Fixpunktarithmetik entstehen, z.b. 1.9999 * 0.0001, dabei verliert man 0.0001. Aber, hier ist man rechtlich auf der sicheren seite, weil Fixpunktarithmetik der standard ist (der auf von Software für den Bund verwendet wird) und damit Stand der Kunst ist. Jetzt mal ganz unabhängig davon ob du Recht hast oder nicht, rechtlich gesehen bist du auf der sicheren Seite wenn du dich an den Stand der Kunst hälst, während wenn du das nicht machst, du dich rechtfertigen musst.
Zuletzt geändert von Warf am Di 25. Feb 2020, 18:37, insgesamt 1-mal geändert.

Antworten