Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Tangeskurve (https://www.delphipraxis.net/40412-tangeskurve.html)

faux 15. Feb 2005 14:11


Tangeskurve
 
Hallo!

Ich stell' mich anscheinend gerade etwas dumm an, aber ich versuche das jetzt schon seit über zwei Stunden und ich hab anscheinend einen Denkfehler:

Delphi-Quellcode:
procedure TForm1.DrawTangens;
var
  x, y: Integer;
begin
  with Image1.Canvas do
  begin
    MoveTo(0, Image1.Height div 2);
    for x := 0 to Image1.Width do
      if x mod 90 mod 2 = 0 then //Hier will ich sicherstellen, dass der Tangeswert ein gültiger ist
      begin
        y := round(Amp.Value * tan(x / Image1.Width * Frq.Value * pi)); //Amp und Frq sind zwei SpinEdits
        LineTo(x, Image1.Height div 2 - y); //Hier ziehe ich den Wert von der Nullinie der Funktion ab
      end;
  end;
end;
Zur Zeile 9:
cos ist null, bei 90, 270, 450, etc. und tan = sin / cos

Delphi-Quellcode:
function tan(const X: Extended): Extended;
begin
  result := sin(X) / cos(X)
end;
Das ganze funktioniert mal, wenn Frq.Val 4 ist. Verändere ich Frq aber, gibts wieder einen Fehler...
Warum aber? Wo liegt mein Fehler?

Danke für die Antwort.

Bart82 15. Feb 2005 14:40

Re: Tangeskurve
 
Achtung: Die Winkel der sin(x) und cos(x) werden in rad (0 bis 2*Pi) angegeben und nicht in Grad!

Carsten

Binärbaum 15. Feb 2005 14:51

Re: Tangeskurve
 
Um den Tangens eines Winkels im Gradmaß zu berechnen, muss man den Winkel erst ins Bogenmaß umrechnen. Das geht mit Delphi-Referenz durchsuchenDegToRad und Delphi-Referenz durchsuchenRadToDeg.

MfG
Binärbaum

faux 15. Feb 2005 17:01

Re: Tangeskurve
 
OK, das ist klar...
Da lag mein Denkfehler.

Danke.

faux 15. Feb 2005 17:10

Re: Tangeskurve
 
OK, ich komm nicht weiter...

Es kommt immer folgender Fehler:

Code:
Project Functioneer.exe raised exception class EInvalidOp with message 'Invalid floating point operation'.

Jasocul 15. Feb 2005 17:24

Re: Tangeskurve
 
Mit Debugger (IDE) laufen lassen. Dann bekommst du auch die Stelle, wo es passiert. Das hilft dir weiter. Falls nicht, zeig uns die Stelle.

faux 15. Feb 2005 17:30

Re: Tangeskurve
 
Das ist ja das Komische, der Debugger zeigt die STelle nicht an, er bricht nur ab....
Ich kapier den Delphi 2005 Debugger sowieso nicht ganz, da kann man zum Beispiel keine Lokalen Variablen wärend der Laufzeit abfragen...

EDIT: Ich habs mit dem Delphi 7 Debugger nochmals probiert und der bringt mich auch nicht an die Richtige Stelle....

idontwantaname 15. Feb 2005 17:38

Re: Tangeskurve
 
könnte irgendwann eine division durch 0 erfolgen ??

ibp 15. Feb 2005 17:40

Re: Tangeskurve
 
wie wäre es denn mit einzelschritten!

idontwantaname 15. Feb 2005 17:46

Re: Tangeskurve
 
wieso eigentlich:
Delphi-Quellcode:
for x := 0 to Image1.Width
wäre es nicht eher:
Delphi-Quellcode:
for x := 0 to Image1.Width - 1

Binärbaum 15. Feb 2005 17:48

Re: Tangeskurve
 
Zitat:

Zitat von idontwantaname
könnte irgendwann eine division durch 0 erfolgen ??

Ja, nämlich immer dann, wenn der Winkel ein ganzzahliges ungerades vielfache von Pi/2 ist. Also bei (2*k+1)*Pi.
Um das abzufangen kann man folgendes machen:
Delphi-Quellcode:
var x: Integer;//Winkel in Grad
...

if (x-90) mod 180 = 0 then begin
 //Tangens ist an dieser Stelle nicht definiert
 ...
end
else begin
 //Kurve zeichnen
end;
MfG
Binärbaum

faux 15. Feb 2005 17:52

Re: Tangeskurve
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo!

Also eine Division schließe ich mal aus, denn dann würde die Fehlermeldung ja "Division by Zero" lauten...
Zur Sicherheit hab ich das mal mit folgender Anweisung ausgeschlossen:

Delphi-Quellcode:
for x := 0 to Image1.Width do
  if cos(x / Image1.Width * Frq.Value * pi) <> 0 then
  begin
    y := round(Amp.Value * tan(x / Image1.Width * Frq.Value * pi));
    LineTo(x, Image1.Height div 2 - y);
  end;
Also ich hab die Stelle jetzt:

Delphi-Quellcode:
for x := 0 to Image1.Width do
begin
  y := round(Amp.Value * tan(x / Image1.Width * Frq.Value * pi)); //Hier ist es....
  LineTo(x, Image1.Height div 2 - y);
end;
Den Wert hab ich noch nicht herausgefunden, aber vielleicht bringt da ja jemand zusammen...

faux 15. Feb 2005 17:57

Re: Tangeskurve
 
Zitat:

Zitat von idontwantaname
wieso eigentlich:
Delphi-Quellcode:
for x := 0 to Image1.Width
wäre es nicht eher:
Delphi-Quellcode:
for x := 0 to Image1.Width - 1

dann müsste es aber auch
Delphi-Quellcode:
for x := 1 to Image1.Width - 1
heißen...

Aber es ist schon so in Ordnung. Denn 1. zeichnet Delphi die Werte trotzdem, und außerdem ist der Wert Image1.Width IMHO noch im Bild.

dizzy 15. Feb 2005 18:01

Re: Tangeskurve
 
Zitat:

Zitat von faux
und außerdem ist der Wert Image1.Width IMHO noch im Bild.

Ist er NICHT. Zeichne mal einen einzelnen Pixel dahin, und sag mir ob du ihn siehst ;). Deinem Screenshot nach ist es aber wohl nicht die Zeichenroutine (die in der Regel gegen "Überm-Rand-Zeichnen" gesichert sind), sondern dein Prog fliegt bei einer Polstelle raus.
Ich vermute mal, dass das Ergebnis der Division, wenn 0 schon ausgeschlossen ist, zu groß für den Datentyp wird, und deshalb abgebrochen wird. Du solltest also Divisionen von -0.0...01 bis +0.0...01 ausschließen, und nicht nur 0 selbst.

Gruss,
Fabian

ibp 15. Feb 2005 18:01

Re: Tangeskurve
 
was ist mit den x-werten, wo tangens unendlich ist (cos(x)=0)! wo filterst du die in deinem code aus?

faux 15. Feb 2005 18:12

Re: Tangeskurve
 
Hallo!

Ich hab die FOR - Schleife jetzt Schritt für Schritt nachgerechnet (*g*)...
Und bin auch mit meinem TR bei 61 auf eine Polstelle gestoßen...
Und siehe da: Bei X = 61 hängt das Programm....

Wieso ist das so?
Deswegen:
Formel:
tan(X / Image1.Width * 4 * Pi)
Image1.Width ist 488

Rechengang:
tan(X) = sin(X) / cos(x)
cos(61 / 488 * 4 * Pi) = 0

Wieso erkennt das mein Programm nicht, wenn ich schreibe:
Delphi-Quellcode:
if cos(X / Image1.Width * 4 * Pi) <> 0

Binärbaum 15. Feb 2005 18:15

Re: Tangeskurve
 
Zitat:

Zitat von faux
Also eine Division schließe ich mal aus, denn dann würde die Fehlermeldung ja "Division by Zero" lauten...

Die meldung heißt ja "Invalid floating point operation", und die Division durch null ist meiner Meinung nach auch eine ungültige Operation :wink:

MfG
Binärbaum

faux 15. Feb 2005 18:24

Re: Tangeskurve
 
Zitat:

Zitat von ibp
was ist mit den x-werten, wo tangens unendlich ist (cos(x)=0)! wo filterst du die in deinem code aus?

Genau das meine ich, das mache ich nämlich und trotzdem tritt der Fehler auf:

Delphi-Quellcode:
for x := 0 to Image1.Width do
begin
  if cos(x / Image1.Width * 4 * pi) <> 0 then
  begin
    y := round(tan(x / Image1.Width * 4 * pi));
    LineTo(x, Image1.Height div 2 - y);
  end;
end;

Bart82 15. Feb 2005 18:34

Re: Tangeskurve
 
@ibp: Das sind ja die Stellen mit Division durch 0! Die sind raus.

dizzy 15. Feb 2005 18:35

Re: Tangeskurve
 
Weil 0 bei Floats nicht unbedingt genau 0 ist. Du musst eine klitze kleine Spanne um 0 herum abfangen.

faux 15. Feb 2005 18:38

Re: Tangeskurve
 
Hm:

Ich hab jetzt folgendes Herausgefunden:

es liegt am Pi...

Fragt mich nicht wieso, aber das dürfte wohl an der Reihenentwicklung von Tanges liegen...

Lässt man das Pi weg, gibts keine Probleme, aber sobald man das Pi reistellt, hängt das Programm an den Polstellen...
Vielleicht liegt das daran, dass der Cosinus von Pi -1 und der Sinus von Pi 0 sind...

also:

Delphi-Quellcode:
y := round(tan(Amp.Value * x / Image1.Width * Frq.Value * Pi)); //Das Programm hängt
y := round(tan(Amp.Value * x / Image1.Width * Frq.Value)); //Es läuft
Bitte um Hilfe, das verwirrt mich zu tiefst....

Bart82 15. Feb 2005 18:44

Re: Tangeskurve
 
Delphi-Quellcode:
for x := 0 to Image1.Width do
begin
  if cos(x / Image1.Width * 4 * pi) <> 0 then
  begin
    y := round(tan(x / Image1.Width * 4 * pi));
    LineTo(x, Image1.Height div 2 - y);
  end;
end;
Es ist besser du machst eine Abfrage auf das Argument, dass das nicht die unerlaubten Werte annimmt. Da die cosinus-Funktion eine Gleitkommazahl zurück gibt wird die fast nie exakt 0 sein, sondern u.U. 0.00...1!

dizzy 15. Feb 2005 18:46

Re: Tangeskurve
 
Mit ohne Pi kommst du wahrscheinlich nur sehr unwahrscheinlich auf ein Vielfaches von (Pi/2). Daher "triffst" du die Polstellen erst garnicht.

faux 15. Feb 2005 18:51

Re: Tangeskurve
 
Zitat:

Zitat von Bart82
Es ist besser du machst eine Abfrage auf das Argument, dass das nicht die unerlaubten Werte annimmt. Da die cosinus-Funktion eine Gleitkommazahl zurück gibt wird die fast nie exakt 0 sein, sondern u.U. 0.00...1!

Das ist eine gute Idee...

Danke...

Wie würde die lauten?
Wann ergibt der Cosinus eines Wertes null?

Bart82 15. Feb 2005 18:59

Re: Tangeskurve
 
Der Cosinus ist für Pi/2 und 3*Pi/2 (allgemein (2n-1)*Pi/2 mit n=1,2,3...) 0.
z.B.
Delphi-Quellcode:
while Argument >= 3*Pi/2 do begin
  Argument - Pi; // so kommst du in den Bereich von 0 bis ausschließlich 3*Pi/2
end;
if Argument <> Pi/2 do begin
                 // hier dein Code
end;

dizzy 15. Feb 2005 18:59

Re: Tangeskurve
 
Zitat:

Zitat von faux
Zitat:

Zitat von Bart82
Es ist besser du machst eine Abfrage auf das Argument, dass das nicht die unerlaubten Werte annimmt. Da die cosinus-Funktion eine Gleitkommazahl zurück gibt wird die fast nie exakt 0 sein, sondern u.U. 0.00...1!

Das ist eine gute Idee...

Das hatte ich dir auch schon geschrieben...

Zitat:

Zitat von faux
Wann ergibt der Cosinus eines Wertes null?

Bei Vielfachen von (Pi/2). (Meinem obigen Posting auch zu entnehmen, wenn auch nicht in aller Deutlichkeit.)
Aber das hilft dir nicht weiter, da man bei Float-Werten NIE sicher sein kann einen Wert ganz genau zu treffen. (Zur Erklärung hab ich hier schon mal was längeres gepostet - müsstest mal suchen.)

Also:
Delphi-Quellcode:
if (cos(irgendwas) < -0.00000001) or (cos(irgendwas) > 0.00000001) then
begin
....
end;
Unter Win32-Delphi gibt's die Funktion Math.isZero(zahl), die die nötige Spanne aus dem Datentyp ermittelt, und testet.

\\edit: Und Binärbaum hat unter mir die effizientere Variante gepostet :)

Binärbaum 15. Feb 2005 19:01

Re: Tangeskurve
 
Mach's doch so:
Delphi-Quellcode:
var sinus, cosinus: Double;
    x: Integer;
begin
 for x := 0 to Image1.Width do
 begin
   SinCos(x / Image1.Width * 4 * pi, sinus, cosinus);
   if abs(cosinus) > 0.00001 then//0.00001 bei Bedarf ändern
   begin
     y := round( sinus/ cosinus);//sin(alpha)/cos(alpha)=tan(alpha)
     LineTo(x, Image1.Height div 2 - y);
   end;
 end;
end;
Damit hast du auch solche Fälle überprüft, wo der Cosinus "beinahe" null ist und dürftest so auf der sicheren Seite sein.

MfG
Binärbaum

faux 15. Feb 2005 19:04

Re: Tangeskurve
 
Zitat:

Zitat von Bart82
Der Cosinus ist für Pi/2 und 3*Pi/2 (allgemein (2n-1)*Pi/2 mit n=1,2,3...) 0.
z.B.

ok, sorry... ist logisch:

x mod 90 mod 2 gilt in dezimalgrad
also:
90° = pi/2 rad
270* = pi(2/3) rad
usw.

Binärbaum 15. Feb 2005 20:36

Re: Tangeskurve
 
Zitat:

Zitat von faux
x mod 90 mod 2 gilt in dezimalgrad
also:
90° = pi/2 rad
270* = pi(2/3) rad
usw.

Erstens: 270° sind 3/2*Pi Radiant (war also evtl. nur ein Tippfehler von dir ? )
Zweitens: x mod 90 mod 2 ist nicht nur bei den Polstellen null.
Bsp: x=4 --> 4 mod 90 mod 2 = 0
oder
x=180 --> 180 mod 90 mod 2 = 0, obwohl bei 180° keine Polstelle ist.
Damit funktioniert das schonmal nicht, und deswegen muss man es ändern.
Also wenn schon über modulo, dann (x-90) mod 180 .

MfG
Binärbaum


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:42 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz