Autor Beitrag
Tobias1
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 454

Win 98, XP Prof
D3 Prof, D2005 Prof
BeitragVerfasst: Mi 01.06.05 13:43 
Wenn ich mit real werten rechne kommt es vor das es anstatt mit 4 mit 3,9999956 oder so rechnet.
Warum ist das so? Muss ich immer den Wert 4,000000 zuweisen?
Gibt es ein Befehl oder einen anderen Variablentyp, der das behebt?

Danke!

_________________
Auch das schlechteste Buch hat seine gute Seite: die letzte. (John Osborne)
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 01.06.05 13:49 
Rundungsungenauigkeit, die darin begründet liegt, wie Fließkommazahlen im Speicher abgelegt werden.
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8535
Erhaltene Danke: 473

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Mi 01.06.05 13:50 
Hallo,

Das hat mehrere Ursachen. Zum einen ist generell die Rechengenauigkeit im Rechner beschränkt. Einige Rechenoperationen sind dabei so bösartig, das sich diese Ungenauigkeiten extrem hochschaukeln. Ein Beispiel für Matrizen ist dabei die Hilbertmatrix. Sie ist zwar invertierbar, aber durch ihre Struktur kommen beim Berechnen der Inversen komplett andere Werte heraus, als man erwarten würde.

Zum anderen lassen sich auch "ganz normale Zahlen" wie z.B. 0.1 im Binärsystem überhaupt nicht exakt darstellen. Auch da arbeitet der PC dann mit Näherungswerten.

So kommt es, dass einige Rechnungen bisweilen Fehler aufweisen. Ein so großer Fehler ist aber schon merkwürdig. Was berechnest du denn in deinem Beispiel?

_________________
We are, we were and will not be.
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6386
Erhaltene Danke: 146

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Mi 01.06.05 13:50 
user profile iconTobias1 hat folgendes geschrieben:
Wenn ich mit real werten rechne kommt es vor das es anstatt mit 4 mit 3,9999956 oder so rechnet.
Warum ist das so? Muss ich immer den Wert 4,000000 zuweisen?
Gibt es ein Befehl oder einen anderen Variablentyp, der das behebt?

1. Weil der PC im Binärsystem rechnet und nicht, wie wir, im Dezimalsystem.
2. Du könntest due Funktion Round benutzen (siehe OH).
3. Meines Wissens nicht. Außer du benutzt Integer. Dann hast du aber keine Nachkommstellen. :wink:
deccer
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 57



BeitragVerfasst: Mi 01.06.05 13:51 
<senf>
auf real sollte man verzichten, da es "veraltet"/"deprecated" ist, stattdessen nimmst lieber
single (einfache genauigkeit), oder double (doppelte genauigkeit) - die genauigkeit bezieht sich auch wieder auf die nachkommastellen
</senf>

@forumscheffs - mir fehlt son "Senf" button im editfenster P:
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 01.06.05 17:23 
Naja, Auf Single und Double sollte er dann getrost verzichten, wenn ihm Real (=Double unter Delphi) schon Probleme macht.

Versuch Dein Glück mal mit Extended (10 Byte), der zwar etwas mehr Code für die CPU bedeutet, aber genauere Ergebnisse liefert und intern schneller verwendet werden kann (da natives Format der FPU).

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Tobias1 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 454

Win 98, XP Prof
D3 Prof, D2005 Prof
BeitragVerfasst: Mi 01.06.05 17:29 
Danke!

_________________
Auch das schlechteste Buch hat seine gute Seite: die letzte. (John Osborne)
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Mi 01.06.05 17:30 
Und wer richtig genau werden will, nimmt BCD. Das kann wenigstens 0.1 100% genau darstellen. Leider sind Floatingpoint Operationen sehr viel schneller als BCD, weswegen in den FPU nur floats benutzt werden, was dann den eingangs zitierten Effekt hat.
Immer wieder gern gesehen (1x form, 1x Button, 3xMemo):
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure TForm3.Button1Click(Sender: TObject);
Var e: Extended; s : single; r : Real;
begin
  e:= -1; s:= -1; r:= -1;
  while r<0.2 do begin
    memo1.lines.add (FloatToStr(e));
    memo2.lines.add (FloatToStr(s));
    memo3.lines.add (FloatToStr(r));
    r := r+0.1;
    e := e+0.1;
    s := s+0.1;
    End;
end;
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8535
Erhaltene Danke: 473

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Mi 01.06.05 17:41 
user profile iconalzaimar hat folgendes geschrieben:
Und wer richtig genau werden will, nimmt BCD. Das kann wenigstens 0.1 100% genau darstellen.

Nur mal aus Neugierde: Was ist/sind BCD, und wie wird damit im Rechner 0.1 genau dargestellt?

_________________
We are, we were and will not be.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 01.06.05 18:43 
BCD = Binary Coded Decimals...

Da werden einfach die Ziffern der Dezimal-Darstellung als Nibbels eines Bytes gespeichert.

25d --> $25 * 100 ^ 0bcd.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Fr 03.06.05 00:29 
user profile iconTobias1 hat folgendes geschrieben:
Wenn ich mit real werten rechne kommt es vor das es anstatt mit 4 mit 3,9999956 oder so rechnet.
Warum ist das so? Muss ich immer den Wert 4,000000 zuweisen?
Gibt es ein Befehl oder einen anderen Variablentyp, der das behebt?

Danke!

Die Zahl 4 sollte dir eigentlich keine Schwierigkeiten bereiten. Sie ist mit Floats exakt darstellbar. Wenn du die Zahl aber mit einer anderen, ungenaueren Zahl verknüpfst, dann kann es schon vorkommen, dass die Zahl dann nicht mehr genau stimmt. Was für eine Rechnung führst du durch?
Tobias1 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 454

Win 98, XP Prof
D3 Prof, D2005 Prof
BeitragVerfasst: Fr 03.06.05 07:53 
Division, Multiplikation

_________________
Auch das schlechteste Buch hat seine gute Seite: die letzte. (John Osborne)
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Fr 03.06.05 08:17 
Dafür gibt es die Schutzstellen: Du rechnest intern (z.B.) mit voller Genauigkeit und nimmst in Kauf, das eben anstatt mit 4.0000 mit 3.9999996 gerechnet wird. Bei Division und Multiplikation wird sich der Fehler i.A. (hier wörtlich zu verstehen) nicht hochschaukeln. Aber Vorsicht bei Iterationen etc.

Dein Ergebnis stellst Du aber nicht mit voller Genauigkeit dar. Im richtigen Leben reichen normalerweise 4 Stellen aus. Alles Andere ist Quark. Beispiel Abmessungen: Es ist interessant, das z.B. die berechnete Länge 4,56786 m ist, aber das ist doch völlig Schnurz, weil im Meter-Bereich normalerweise nur auf mm genau gemessen wird. Wichtig ist, mit Augenmaß und Drang zur Realität die Genauigkeit anzugeben.

Ich würde Extended-Zahlen nehmen und nie auf Gleichheit prüfen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
Var
  a,b : Extended;

Begin
  a := 8.9;
  b := 4.9;
  If a-b = 4 Then Showmessage('Foo');
  If Abs (4 - (a-b)) < 1E10 Then Showmessage('Bar'); 
// Oder 
  If IsZero (4 - (a-b)) Then Showmessage ('Bar 2');
End;

Ob hier 'Foo' angezeigt wird, weiss nich nicht. Aber 'Bar' wird in jedem Fall angezeigt, 'Bar 2' auch.

Im Umgang mit reelen Zahlen wirst Du immer mit Schutzstellen arbeiten, also die letzten paar Stellen ignorieren.
deccer
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 57



BeitragVerfasst: Fr 03.06.05 09:10 
user profile iconBenBE hat folgendes geschrieben:
Naja, Auf Single und Double sollte er dann getrost verzichten, wenn ihm Real (=Double unter Delphi) schon Probleme macht.

Versuch Dein Glück mal mit Extended (10 Byte), der zwar etwas mehr Code für die CPU bedeutet, aber genauere Ergebnisse liefert und intern schneller verwendet werden kann (da natives Format der FPU).


aha, aber dann nur wenn er mit dem FPU asmbefehlssatz arbeitet, ansonsten weiß ja der compiler nicht, obber jetz die fpu oder cpu bemühen soll :!:
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Fr 03.06.05 09:27 
Darf ich trotzdem nochmal fragen, was du genau berechnen möchtest (evtl. Source?). Vielleicht lässt sich das Problem umschreiben... (Vielleicht auch nicht)
Stefan.Buchholtz
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 612

WIN 2000, WIN XP, Mac OS X
D7 Enterprise, XCode, Eclipse, Ruby On Rails
BeitragVerfasst: Fr 03.06.05 09:29 
user profile icondeccer hat folgendes geschrieben:
user profile iconBenBE hat folgendes geschrieben:
Naja, Auf Single und Double sollte er dann getrost verzichten, wenn ihm Real (=Double unter Delphi) schon Probleme macht.

Versuch Dein Glück mal mit Extended (10 Byte), der zwar etwas mehr Code für die CPU bedeutet, aber genauere Ergebnisse liefert und intern schneller verwendet werden kann (da natives Format der FPU).


aha, aber dann nur wenn er mit dem FPU asmbefehlssatz arbeitet, ansonsten weiß ja der compiler nicht, obber jetz die fpu oder cpu bemühen soll :!:


Da alle x86er-Prozessoren ab dem 486er aufwärts eine FPU integriert haben, benutzt der Delphi-Compiler (und auch alle anderen mir bekannten aktuellen Compiler) für Fließkommaoperationen immer FPU-Befehle.

Stefan
deccer
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 57



BeitragVerfasst: Fr 03.06.05 09:38 
warum rechnest das nich einfach auf ganze zahlen hoch?

4,123123 * 100000 = 4123123 ..... damit lässts sich "einfacher" rechnern

_________________
I <3 PeRLe
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6386
Erhaltene Danke: 146

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Fr 03.06.05 09:46 
Ich benutze im Zweifel immer Round.
Auf Ganzzahlen hochrechnen kann schnell zu Problemen führen. Du weißt ja nicht, wieviele Nachkommastellen zu berücksichtigen sind. Wenn du dann noch zuviele Vorkommastellen hast, gibt es sehr lustige Effekte. :mrgreen:
deccer
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 57



BeitragVerfasst: Fr 03.06.05 10:00 
das is klar :)

aber in den meisten fällen hatmer ja nich mehr als 5 oder 6 nachkommastellen (z.b. bei opengl krams) wenn man da nen epsilon oder so brauch .......

naja was solls </senf>

_________________
I <3 PeRLe
Tobias1 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 454

Win 98, XP Prof
D3 Prof, D2005 Prof
BeitragVerfasst: Fr 03.06.05 13:36 
Ich habe jetzt recht viele round-Funktionen,damit gehts, in meinem Code.
Ich wills jetzt aber auf Integer umproggen.

_________________
Auch das schlechteste Buch hat seine gute Seite: die letzte. (John Osborne)