Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Rechnung wird nicht gleich 0, sondern 3,5527136788005E-14


Delete - Do 28.05.09 22:42
Titel: Rechnung wird nicht gleich 0, sondern 3,5527136788005E-14
Hallo Leute,

Darlehenstilgung bei Zinssatz X in Y Jahren, das soll das Programm machen.

Ich habe ein Programm geschrieben, bei dem man den Kredit eingeben soll, dann noch den Prozentsatz und die Jahre, in denen der Kredit getilgt werden soll.

Jetzt habe ich auch einen Code geschrieben, der eigentlich funktionieren sollte, aber das Teil spinnt iwie. Ich weiß aber nicht warum.

Ich habe zur Kontrolle eine Art Ausgabefunktion geschrieben, die nach jedem Durchlauf der Schleife die Werte ausgibt.
Seht ihr alles auf den Screenshots ;)
Dabei kam dann raus, dass das Teil einfach nicht den Wert auf 3,5527136788005E-14 oder so setzt. Aber schauts euch selber an.
Eigentlich sollte er nachdem die Annuität 2000 erreicht hat, abbrechen. Das zeigt das rechte Programm, das anhand von Kredit, Zinssatz und Annuität in einem Stinggrid ausgibt, wie das über die Jahre abläuft.

Der Code des ersten Programms habe ich auch angehängt.
Ich hoffe, ihr habt da mal ne Idee zu.

Moderiert von user profile iconNarses: Bild als Anhang hochgeladen.
Danke für's hochladen. Dachte, es ginge nur eine Datei.

Achja. Was ich noch sagen wollte. Ich habe mal für die 500, die am Ende dazu addiert werden, 499 eingesetzt und das funktioniert. Warum check ich auch nicht.


Gr33tZ
Rn


Delete - Fr 29.05.09 15:51

Okay, hier noch mal die genaue Zahl. Ich check das echt nicht. Warum macht Delphi son Schrott?

3,5527136788005E-14

Wenn ich die allerdings in der IF-Abfrage angebe, dann wird das Teil zur Endlosschleife. ~.~


baka0815 - Fr 29.05.09 16:03

3,5527136788005E-14 entsprechen ja 0,0000000000000035527...

Klingt für mich nach 'nem Fließkommaproblem. Nimmst du die Datentypen Real, Extended oder Double? Wenn ja, versuch mal Currency.


Delete - Fr 29.05.09 16:11

Ich benutze real.
Lol ^^ Du bist ein Gott. DAnke. Hat funktioniert.

Aber warum? Ich meine, warum ist 0 nicht gleich 0, sondern diese komische Zahl da, wenn ich REAL und nicht CURRENCY nehme?


Yogu - Fr 29.05.09 16:33

Hast du der Real-Variable wirklich 0 zugewiesen? Dann finde ich das etwas seltsam, kenne mich aber mit Fließkommazahlen in Delphi zu wenig aus, um da richtig Stellung zu nehmen. Tatsächlich musst du immer runden, um einen halbwegs verwendbaren Wert haben willst, denn Single, Double, Extendet und natürlich Real werden intern binär und in wissenschaftlicher Darstellung gespeichert, und diese Kombination hat so ziemlich überhaupt nichts mit dem Dezimalsystem zu tun. Folglich ist das Ganze auch nicht genau.

Curency hingegen ist einfach ein Integer, der aber immer durch IMHO 100 geteilt wird. 123,45 (Euro) wird also intern als "12345 / 100" dargestellt, und das ist eben wieder genau. Für Währungen und dergleichen also immer Currency verwenden :idea:


nagel - So 31.05.09 00:45

user profile iconYogu hat folgendes geschrieben Zum zitierten Posting springen:
... der aber immer durch IMHO 100 geteilt wird.

Durch 10000.


arj - So 31.05.09 11:29

Üblicherweise macht man Fließkommazahlenvergleiche wegen der Ungenauigkeit immer mit nem Epsilon.

Sei Epsilon > 0, dann gibt Epsilon (im Code einfach als Variable e), die benötigte Genauigkeit an
und ein Vergleich schaut dann so aus:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var epsilon : Single;

epsilon := 0.0000001;
// entspricht if zahl1 = zahl2 then
if (zahl1 >= zahl2 - epsilon) and (zahl1 <= zahl2 + epsilon) then
begin
end;


Allerdings kann es natürlich sein, dass der Wert den Du dem epsilon gibst - im Code 0.0000001 - von
einer Fließkommazahl wiederrum nicht exakt dargestellt werden kann, deshalb musst Du da ggf. bisschen probieren.

Der Vergleich kann dann also in ne Funktion gepackt werden:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
function Equals(f1, f2 : Single) : Boolean;
const epsilon : Single = 0.0000001;
begin
// entspricht if f1 = f2 then
Result := (f1 >= f2 - epsilon) and (f1 <= f2 + epsilon);
end;


Dann sollte die Nullprüfung auch funkltionieren.


Martok - So 31.05.09 11:34

Oder, unter Verwendung der Unit Math:

Delphi-Quelltext
1:
2:
3:
uses ..., Math, ...;
if IsZero(FloatValue) then foo;
if SameValue(FloatValue, 42then bar;


arj - So 31.05.09 11:38

Mist, das dachte ich mir fast dass es da schon was gibt *g*


Delete - So 07.06.09 16:30

Also jetzt funktioniert es wie gesagt, aber ist ungenau. Check ich aber iwie nicht. Also ne Ungenauigkeit von rund 50 oder so. Das ist doch nen bisschen hart.

Was ich aber nicht verstehe ist, warum man runden muss, wenn man bei ner REAL 0 erhalten will. Das ist doch iwie unlogisch.


Robert.Wachtel - So 07.06.09 16:41

user profile iconregsnerven hat folgendes geschrieben Zum zitierten Posting springen:
[...] Was ich aber nicht verstehe ist, warum man runden muss, wenn man bei ner REAL 0 erhalten will. Das ist doch iwie unlogisch.

http://de.wikipedia.org/wiki/Gleitkommazahl


jfheins - So 07.06.09 16:49

Nein, ist es nicht wenn man es versteht ;)

Da dein Computer leider nicht unendlich viel speicher hat, muss er die (unendlich genaue) Zahl annähern. Resultat: Er kann die Zahl nur auf (bspw.) 5 Stellen genau speichern. (5 zur Anschaulichkeit, in der Realität 10-15 Stellen)

D.h.: a := 1000000; // wird als 1,0000 * 10^6 gespeichert
Wenn du jetzt eine 1 dazuaddiert entsteht folgendes "Paradoxon":

1,0000 * 10^6 + 1,0000 * 10^0 = (Exponenten angleichen) = 1,0000 * 10^6 + 0,000001 * 10^6 = 1,000001 * 10^6 = (Da nur 5 signifikante Stellen) = 1,0000 * 10^6

Also eine Million plus 1 ist immernoch eine Million.

Macht dein Taschenrechner übrigens auch. Tipp mal 1E20 + 1 - 1E20 ein ;)


Delete - So 07.06.09 23:23

Hinzukommt, dass man Zahlen in Dezimaldarstellung nicht genau in ihrer Binärdarstellung repräsentieren kann: http://www.michael-puff.de/Artikel/Fliesskomma.shtml


Delete - Mo 08.06.09 20:56

Danke jfheins ^^ Das ist doch mal etwas, was man verstehen kann.

Danke natürlich auch allen anderen für die Hilfe und die Links :D

Ich beende den Thread hiermit mal.

Gr33tZ
Rn