Hallo zusammen!
Ich moechte folgenden Quellcode zur Diskussion stellen.
<PRE>
procedure TForm1.btnStartClick(Sender: TObject);
var
e_org,
e100,
e1000: extended;
begin
with adoQryWerte do begin
if Active then Close;
Open;
while not EOF do begin
e_org := FieldByName('WERT').AsFloat;
e100 := btKaufmRunden(FieldByName('WERT').AsFloat, 100);
e1000 := btKaufmRunden(FieldByName('WERT').AsFloat, 1000);
Memo1.Lines.Add(FloatToStr(e_org));
Memo1.Lines.Add(FloatToStr(e100)+' - '+FloatToStr(e1000));
Memo1.Lines.Add('- - - - - - - - - - - - - - - - - - - -');
Edit;
FieldByName('WERT').AsFloat := e_org;
Post;
Next;
end;
Close;
end;
end;
</PRE>
Die Abfrage adoQryWerte greift auf eine Tabelle zu, die in einer Access 2000 DB liegt. Diese Tabelle enthält nur ein Feld WERT; Typ: Zahl, Feldgroesse: double, Dezimalstellen: automatisch.
Es werden zwei gerundete Werte berechnet: e100 auf zwei Stellen und e1000 auf drei Stellen nach dem Komma. Hier der Quellcode der Rundungsfkt.:
<PRE>
function btKaufmRunden(
const x: extended;
const Genauigkeit: integer): extended;
begin
Assert((Genauigkeit mod 10 = 0));
if x < 0 then
result := trunc((x * Genauigkeit) - 0.5) / Genauigkeit
else
result := trunc((x * Genauigkeit) + 0.5) / Genauigkeit;
end;
</PRE>
Die Werte in der Tabelle lauten:
<PRE>
2,655
2,6555
2,65555
</PRE>
Hier die Ausgabe in Memo1 nach dem ersten Start-Click:
<PRE>
2,655
2,66 - 2,655
- - - - - - - - - - - - - - - - - - - - - -
2,6555
2,66 - 2,655 (FALSCH)
- - - - - - - - - - - - - - - - - - - - - -
2,65555
2,66 - 2,656
- - - - - - - - - - - - - - - - - - - - - -
</PRE>
Hier die Ausgabe nach dem zweiten Start-Click:
<PRE>
2,655
2,65 (FALSCH) - 2,655
- - - - - - - - - - - - - - - - - - - - - -
2,6555
2,66 - 2,655 (FALSCH)
- - - - - - - - - - - - - - - - - - - - - -
2,65555
2,66 - 2,656
- - - - - - - - - - - - - - - - - - - - - -
</PRE>
Der Clou an der ganzen Sache ist: wenn ich die Zeile zwischen dem edit und dem post auskommentiere, rechnet die Rundungsfunktion korrekt, und zwar unabhaengig davon, wie oft ich auf Start druecke:
<PRE>
2,655
2,66 - 2,655
- - - - - - - - - - - - - - - - - - - - - -
2,6555
2,66 - 2,656
- - - - - - - - - - - - - - - - - - - - - -
2,65555
2,66 - 2,656
- - - - - - - - - - - - - - - - - - - - - -
</PRE>
Das Beispiel laesst sich auch ueber ODBC nachvollziehen. Ich habe ebenfalls bei der Zuweisung anstatt AsFloat mal Value versucht - keine Wirkung.
Obwohl e_org in keinem Zusammenhang mit e100 und e1000 steht, scheint die Zuweisung eine Auswirkung auf die Rundung zu haben. Ich habe auch Compileroptimierungsbemühungen unterdrückt, indem ich das Zurueckschreiben in die DB von einem Kriterium abhängig gemacht habe, das erst zur Laufzeit bekannt ist (über eine Checkbox).
Laesst man in dem Beispiel e100 und e1000 komplett weg und macht alles ueber eine Variable entsteht derselbe Effekt.
Kann jemand dieses Verhalten nachvollziehen ?<BR>
Dieses vielleicht konstruiert anmutende Beispiel hat fuer mich durchaus einen realen Hintergrund und ist keinesfalls lustig.
Meine Umgebung: Windows 2000 Prof, Access 2000, D5 Enterprise mit MDAC 2.6 Patch.
Vielen Dank fuer Antworten oder sonstige Teilnahme an der Diskussion.
Jens
Ich moechte folgenden Quellcode zur Diskussion stellen.
<PRE>
procedure TForm1.btnStartClick(Sender: TObject);
var
e_org,
e100,
e1000: extended;
begin
with adoQryWerte do begin
if Active then Close;
Open;
while not EOF do begin
e_org := FieldByName('WERT').AsFloat;
e100 := btKaufmRunden(FieldByName('WERT').AsFloat, 100);
e1000 := btKaufmRunden(FieldByName('WERT').AsFloat, 1000);
Memo1.Lines.Add(FloatToStr(e_org));
Memo1.Lines.Add(FloatToStr(e100)+' - '+FloatToStr(e1000));
Memo1.Lines.Add('- - - - - - - - - - - - - - - - - - - -');
Edit;
FieldByName('WERT').AsFloat := e_org;
Post;
Next;
end;
Close;
end;
end;
</PRE>
Die Abfrage adoQryWerte greift auf eine Tabelle zu, die in einer Access 2000 DB liegt. Diese Tabelle enthält nur ein Feld WERT; Typ: Zahl, Feldgroesse: double, Dezimalstellen: automatisch.
Es werden zwei gerundete Werte berechnet: e100 auf zwei Stellen und e1000 auf drei Stellen nach dem Komma. Hier der Quellcode der Rundungsfkt.:
<PRE>
function btKaufmRunden(
const x: extended;
const Genauigkeit: integer): extended;
begin
Assert((Genauigkeit mod 10 = 0));
if x < 0 then
result := trunc((x * Genauigkeit) - 0.5) / Genauigkeit
else
result := trunc((x * Genauigkeit) + 0.5) / Genauigkeit;
end;
</PRE>
Die Werte in der Tabelle lauten:
<PRE>
2,655
2,6555
2,65555
</PRE>
Hier die Ausgabe in Memo1 nach dem ersten Start-Click:
<PRE>
2,655
2,66 - 2,655
- - - - - - - - - - - - - - - - - - - - - -
2,6555
2,66 - 2,655 (FALSCH)
- - - - - - - - - - - - - - - - - - - - - -
2,65555
2,66 - 2,656
- - - - - - - - - - - - - - - - - - - - - -
</PRE>
Hier die Ausgabe nach dem zweiten Start-Click:
<PRE>
2,655
2,65 (FALSCH) - 2,655
- - - - - - - - - - - - - - - - - - - - - -
2,6555
2,66 - 2,655 (FALSCH)
- - - - - - - - - - - - - - - - - - - - - -
2,65555
2,66 - 2,656
- - - - - - - - - - - - - - - - - - - - - -
</PRE>
Der Clou an der ganzen Sache ist: wenn ich die Zeile zwischen dem edit und dem post auskommentiere, rechnet die Rundungsfunktion korrekt, und zwar unabhaengig davon, wie oft ich auf Start druecke:
<PRE>
2,655
2,66 - 2,655
- - - - - - - - - - - - - - - - - - - - - -
2,6555
2,66 - 2,656
- - - - - - - - - - - - - - - - - - - - - -
2,65555
2,66 - 2,656
- - - - - - - - - - - - - - - - - - - - - -
</PRE>
Das Beispiel laesst sich auch ueber ODBC nachvollziehen. Ich habe ebenfalls bei der Zuweisung anstatt AsFloat mal Value versucht - keine Wirkung.
Obwohl e_org in keinem Zusammenhang mit e100 und e1000 steht, scheint die Zuweisung eine Auswirkung auf die Rundung zu haben. Ich habe auch Compileroptimierungsbemühungen unterdrückt, indem ich das Zurueckschreiben in die DB von einem Kriterium abhängig gemacht habe, das erst zur Laufzeit bekannt ist (über eine Checkbox).
Laesst man in dem Beispiel e100 und e1000 komplett weg und macht alles ueber eine Variable entsteht derselbe Effekt.
Kann jemand dieses Verhalten nachvollziehen ?<BR>
Dieses vielleicht konstruiert anmutende Beispiel hat fuer mich durchaus einen realen Hintergrund und ist keinesfalls lustig.
Meine Umgebung: Windows 2000 Prof, Access 2000, D5 Enterprise mit MDAC 2.6 Patch.
Vielen Dank fuer Antworten oder sonstige Teilnahme an der Diskussion.
Jens
Comment