Lazarus/SQLite: Rundungsfehler bei einer Münze und Wert seltener 2-Euro-Münzen

Für sonstige Unterhaltungen, welche nicht direkt mit Lazarus zu tun haben
Antworten
Gsilen
Beiträge: 1
Registriert: Fr 2. Okt 2026, 11:45

Lazarus/SQLite: Rundungsfehler bei einer Münze und Wert seltener 2-Euro-Münzen

Beitrag von Gsilen »

Moin zusammen,

ich programmiere seit ein paar Jahren ein kleines Lazarus-Tool mit einer SQLite-Datenbank, um meine Sammlung von 2-Euro-Gedenkmünzen zu verwalten (Land, Jahr, Zustand, Preis). Eigentlich nichts Kompliziertes, am Anfang einfach ein TSQLQuery, das mit einem TDBGrid verbunden ist, dazu ganz normale Felder.

Letztes Wochenende wollte ich eine Liste mit aktuellen Kursen importieren, um meine Einträge zu aktualisieren, und dann wurden die Preise im Grid nach der zweiten Nachkommastelle plötzlich völlig absurd angezeigt. Eine Münze für 12,50 wurde zum Beispiel als 12,4999999 angezeigt oder je nach Zeile irgendwie falsch gerundet.

Ich habe zwei Abende gebraucht, um herauszufinden, dass das Feld irgendwo in der Importprozedur als Double statt als Currency gecastet wurde und SQLite das Ganze seinerseits am Ende als Text gespeichert hat. Dadurch gab es bei jedem Auslesen eine doppelte und ziemlich unsaubere Konvertierung. Eigentlich ein Klassiker, aber es hat ewig gedauert, den Fehler einzugrenzen, weil er nur bei bestimmten Werten auftrat und nicht bei allen.

Franchement, eine Zeit lang dachte ich sogar, dass das Problem direkt vom Component kommt. Ausgerechnet bei einer seltenen 2-Euro-Münze aus Monaco ist mir der Rundungsfehler aufgefallen, als ich meine Werte mit dem **Wert seltener 2-Euro-Münzen** in einem Online-Katalog verglichen habe. Da ist mir die Abweichung aufgefallen und ich konnte den Fehler bis zu diesem fehlerhaften Cast zurückverfolgen.

Danach habe ich noch einen Vergleich Zeile für Zeile gemacht, um sicherzugehen, dass es wirklich am Import lag und nicht noch irgendwo anders etwas schiefgelaufen ist. Jetzt sind überall Currency-Felder drin und im Importcode versteckt sich kein Double mehr. Seitdem läuft alles problemlos.

Hatte jemand von euch schon mal so ein Problem mit SQLite und numerischen Datentypen? Vielleicht habe ich auf der Seite des Components noch irgendeine Einstellung übersehen. Kann natürlich auch einfach sein, dass ich das Ganze am Anfang falsch konfiguriert hatte.

Gruß

Benutzeravatar
Zvoni
Beiträge: 763
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz/FPC fixes)
CPU-Target: 64Bit
Wohnort: BW

Re: Lazarus/SQLite: Rundungsfehler bei einer Münze und Wert seltener 2-Euro-Münzen

Beitrag von Zvoni »

Ich glaube mich daran zu erinnern, dass es ein Rundungsthema zwischen Single und Double gibt.
Desweiteren kommt es darauf an, welchen tatsächlichen Datentyp du für die Spalte in deiner Tabelle hast.

Unabhängig davon: Wenn, du, wie in deinem Fall, Preise/Geldwerte in der DB speichern willst, würde ich Integer nehmen, und Preise/Werte als "Cent" speichern.
Bsp: "12,47 €" werden in der Datenbank "1247" (cent).
Beim speichern mal 100 (inkl. runden), beim abholen geteilt durch 100
Generell würde ich solche Sachen (z.B. Runden) immer von der DB machen lassen
Stichwort: Computed/Generated columns

Code: Alles auswählen

CREATE TABLE "tbl_coins" (
	"ID"	INTEGER,
	"Bezeichnung"	TEXT,
	"PreisRaw"	REAL,
	"PreisCent" INTEGER GENERATED ALWAYS AS (ROUND("PreisRaw"*100)) Stored,
	"PreisReal" REAL GENERATED ALWAYS AS ("PreisCent"/100.0) virtual,
	PRIMARY KEY("ID")
);
INSERT/UPDATE nur auf (Spalte 2 und) Spalte 3, hier den "rohen" Double-Wert liefern.
und Spalte 4 und 5 wird automagisch von der DB selbst berechnet, und zur Verfügung gestellt (Können ganz normal per SELECT abgeholt werden).
Bei DB-Gebundenen Controls resp. wenn du mit "Dataset.Insert/Append/Edit" arbeitest, muss besondere Sorgfalt für InsertSQL und UpdateSQL angewendet werden.
Die kann man definitiv nicht von der Komponente "erraten" lassen, sonst knallts
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 7455
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: Lazarus/SQLite: Rundungsfehler bei einer Münze und Wert seltener 2-Euro-Münzen

Beitrag von af0815 »

Grundlagen zur Ungenauigkeit (Klugscheissermodus):
Hier im Forum
viewtopic.php?t=9410
viewtopic.php?t=17088

Extern über C, Probleme aber gleich
https://learn.microsoft.com/de-de/cpp/b ... w=msvc-170
https://labex.io/de/tutorials/c-how-to- ... ems-419921
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: Lazarus/SQLite: Rundungsfehler bei einer Münze und Wert seltener 2-Euro-Münzen

Beitrag von wp_xyz »

Zvoni hat geschrieben: Di 6. Okt 2026, 08:14 beim abholen geteilt durch 100
Da ist aber auch nicht garantiert, dass z.B. 1249/100 exakt als 12.49 ausgegeben wird, denn 12.49 lässt sich nicht als Kombination von Zweierpotenzen darstellen:

Code: Alles auswählen

program Project1;
begin
  WriteLn(1249/100);
  ReadLn;
end.

// Ausgabe:
 1.24899999999999999998E+0001
 
Wichtiger ist, dem FloatFeld ein DisplayFormat zuzuweisen:

Code: Alles auswählen

  for i := 0 to Dataset1.FieldCount-1 do
  begin
    if Dataset1.Fields[i] is TFloatField then
      TFloatField(Dataset1.Fields[i]).DisplayFormat := '0.00';   // auf zwei Stellen nach dem Komma runden
  end; 

Antworten