Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - 1 != 1 - Problem beim Vergleich mit Double
freedy - Fr 26.01.07 17:41
Titel: 1 != 1 - Problem beim Vergleich mit Double
Hallo Leute!
Ich habe folgendes Problem. Es soll eine logarithmische Skala gezeichnet werden. Als Test und zum Probieren habe ich auf eine Form einen TButton und ein TImage gesetzt.
Hier mein Code (leider nicht Kommentiert):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
type TForm1 = class(TForm) Image1: TImage; Button1: TButton; ListBox1: TListBox; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private public end;
var Form1: TForm1;
implementation
{$R *.dfm}
function log10(Value : Double) : Double; var res : Double; begin Res := (ln(Value) / ln(10)); if IsZero(Res, 0.00000001) then Result := 0 else Result := Res; end;
procedure TForm1.Button1Click(Sender: TObject); var Erg : Double; I : Double; r : TRect; pix : Integer; Start : Double; Ende : Double; Step : Double; big : Integer; a, b : Extended; begin Start := 0.1; Ende := 100; R.Right := Image1.Width; R.Bottom := Image1.Height; Image1.Picture.Bitmap.SetSize(Image1.Width, Image1.Height); with Image1.Picture.Bitmap.Canvas do begin FillRect(R); MoveTo(0, Image1.Height div 2); LineTo(Image1.Width, Image1.Height div 2); end;
I := Start; Step := Start;
big := Trunc((Image1.Width - 10) / (log10(Ende) - log10(Start)));
while (I <= Ende) do begin Erg := log10(I); ListBox1.Items.Add(FloatToStr(Erg));
pix := Trunc(big * (Erg - log10(Start))); with Image1.Picture.Bitmap.Canvas do begin MoveTo(pix + 5, Image1.Height div 2 - 5); LineTo(pix + 5, Image1.Height div 2 + 5);
a := log10(I); b := Trunc(a); if (a = b) then begin TextOut(pix + 2, Image1.Height div 2 + 8, FloatToStr(I)); Step := I; end; I := I + Step; end; end; end;
procedure TForm1.FormCreate(Sender: TObject); begin Image1.Picture := TPicture.Create; end; |
Damit kann man beliebig rumspielen. Das tolle ist, er zeichnet alle Werte an die Skala, solange der Startwert nicht unter 1 geht. Warum?
Mit diesem Source erkennt er nicht, dass 1 = 1 sein soll, wenn die 10 gezeichnet werden soll. Ich weiß echt nicht weiter.
Gruß
Gausi - Fr 26.01.07 17:45
Real-Typen sollten aufgrund der ungenauen Darstellung im Rechner niemals mit = verglichen werden. Du hast in deinem Code eine Funktion IsZero drin. Ich würde mal den Vergleich a=b durch IsZero(a-b,0.000001) ersetzen, dann sollte es gehen.
freedy - Fr 26.01.07 17:50
Zitat: |
Real-Typen sollten aufgrund der ungenauen Darstellung im Rechner niemals mit = verglichen werden. Du hast in deinem Code eine Funktion IsZero drin. Ich würde mal den Vergleich a=b durch IsZero(a-b,0.000001) ersetzen, dann sollte es gehen. |
Schon ausprobiert. Klappt nicht, da
b den Wert 0 annimmt, während
a näherungsweise 1 ist.
IsZero war also keine Lösung.
Die Zeilen, wo a und b "berechnet" werden, sollten ja verständlich sein. Ich prüfe, ob der Log-Wert eine Zahl ohne Nachkommastellen ist.
Kennt da vielleicht noch jemand eine andere Lösung?
Gausi - Fr 26.01.07 17:58
Dann probier mal, ob du mit Frac weiterkommst. Das liefert die Nachkommastellen. Wenn die fast 0 sind, oder 1-frac fast 0, dann bist du sehr nahe an einer ganzen Zahl dran.
freedy - Fr 26.01.07 18:04
Das kann nicht funktionieren.
Das Problem sind doch die Nachkommastellen, die Trunc() abschneidet. Das Programm rechnet ja richtig. log(10) ist 1. Jetzt schneide ich von diesem Wert aber die Nachkommastellen ab und weise ihn
b zu. Da der Wert aber nicht genau 1 war, ist
b = 0. Er rechnet aber mit
a = 1 weiter. Natürlich sind die beiden nicht gleich, so dass er logischerweise nicht in meine if-Schleife läuft. Frac() liefert mir leider aber genau 0 zurück.
Edit:
Damit klappt es jetzt doch:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| if (frac(log10(I)) = 0) or IsZero(1 - frac(log10(I)), 1e-10) then begin TextOut(pix + 2, Image1.Height div 2 + 8, FloatToStr(I)); Step := I; end;
|
Gruß
Gausi - Fr 26.01.07 18:09
Deswegen hab ich ja Frac vorgeschlagen. Wenn die Nachkommastellen .0000001 sind oder .999999, dann ist man sehr nahe bei einer ganzen Zahl und geht in die Schleife rein. Oder verstehe ich dich immer noch nicht richtig?
Edit: Hab dein Edit nicht gelesen ;-)
BenBE - So 28.01.07 16:58
freedy hat folgendes geschrieben: |
Das kann nicht funktionieren.
Das Problem sind doch die Nachkommastellen, die Trunc() abschneidet. Das Programm rechnet ja richtig. log(10) ist 1. Jetzt schneide ich von diesem Wert aber die Nachkommastellen ab und weise ihn b zu. Da der Wert aber nicht genau 1 war, ist b = 0. Er rechnet aber mit a = 1 weiter. Natürlich sind die beiden nicht gleich, so dass er logischerweise nicht in meine if-Schleife läuft. Frac() liefert mir leider aber genau 0 zurück. |
Es gibt keine
If-Schleifen [
http://www.if-schleife.de]!!!
Zu deinem Problem: Probier mal Round statt Trunc.
freedy - Mo 29.01.07 01:23
Nein, natürlich nicht. "verschrieben"! Soll jetzt keine Ausrede sein. Fehler ist natürlich Fehler. Das "if" habe ich nachträglich zugefügt.
BenBE hat folgendes geschrieben: |
Zu deinem Problem: Probier mal Round statt Trunc. |
Hat sich alles schon erledigt. Mit Round klappte es übrigens gar nicht.
Gruß
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!