AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

tan() von Single, Double, etc.

Ein Thema von Rollo62 · begonnen am 20. Nov 2017 · letzter Beitrag vom 22. Nov 2017
Antwort Antwort
Seite 4 von 5   « Erste     234 5      
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#31

AW: tan() von Single, Double, etc.

  Alt 21. Nov 2017, 12:48
Wie gesagt, die Gleitkomma-Arithmetik ist exakt, genau so exakt wie Integer-Arithmetik. Was sollte denn die tan(90°) (Eingabe als Radian, natürlich Uwe) deiner Meinung nach zurückgeben ?
Der richtige Wert wäre vielleicht MAX_SINGLE als größtmögliche Näherung an Infinity ?
Obwohl ich bei tan(90°) nicht meine das es überhaupt + oder - Infinity ist, sondern einfach eine undefinierte Polstelle
(Kann mich auch irren. bin jetzt kein Zahlentheoretiker).

Jedenfalls liefert tan(90°) bei mir irgendwas mit -235343.. zurück, also eine konkrete Zahl die unter dem möglichen Max_Single liegt und relativ "zufällig" ist.
Du hast es immer noch nicht ganz verstanden glaube ich. Das hier:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  s: Single;
  d: Double;
  e: Extended;
begin
  s := DegToRad(90);
  d := DegToRad(90);
  e := DegToRad(90);
  Edit1.Text := FloatToStrF(s, ffFixed, 30, 30);
  Edit2.Text := FloatToStrF(d, ffFixed, 30, 30);
  Edit3.Text := FloatToStrF(e, ffFixed, 30, 30);
end;
Das liefert für die drei Variablen:
s = 1,570796370506286620
d = 1,570796326794896560
e = 1,570796326794896620

pi/2 wäre nach diesem Rechner auf 50 Stellen genau: 1.570796326794896619231321691639751442098584699687 6

Die Differenz von dieser Näherung zu pi/2 ist
für s: -0.000000043711390000768678308360248557901415300312 4471
für d: 0.000000000000000059231321691639751442098584699687 553
für e: -0.000000000000000000768678308360248557901415300312 4471

Derselbe Rechner liefert für
tan(s) = -22877332.42942889836981039204072541441251573432
tan(d) = 16882959411340397.91436507298177193134
tan(e) = -1300934329906107203.0757511956816777
(Auch jeweils auf 50 Stellen genau, etwas was eine CPU von Hause aus nicht kann.)

Die Funktion Tan() ist in Delphi (2007) so realisiert:
Delphi-Quellcode:
function Tan(const X: Extended): Extended;
{  Tan := Sin(X) / Cos(X) }
asm
        FLD X
        FPTAN
        FSTP ST(0) { FPTAN pushes 1.0 after result }
        FWAIT
end;
Es wird, wie zu erwarten ist, einfach die tan() Funktion der CPU (bzw. FPU) genutzt, so wie es auch sein sollte für eine Basisfunktionalität. Und hier wird eben mit binären Gleitkommazahlen und Radian gearbeitet, so dass du niemals auch nur die CHANCE hättest tand(90) mit einem 100%ig exakt richtigen Parameter aufzurufen. Und für die zwingend gerundeten Parameter stimmt das Ergebnis das du siehst. Es wäre falsch hier NaN oder +/-Inf zurückzugeben.

Das ist anders für DEINEN Anwendungsfall, in dem du explizit Funktionen in Grad nutzen willst. Das ist aber ein Sonderwunsch, und NICHT Aufgabe eines Compilers bzw. des Basisumfangs einer Entwicklungsumgebung. Im Gegenteil: Ich wäre ziemlich sauer wenn Emba so ein Monster für ein popeliges tan() als Basis hätte wie weiter oben gezeigt, wenn doch die CPU selbst schon eine solche Funktion bietet die für 99,999% aller Echt-Welt-Fälle Werte liefert die den üblichen Ansprüchen genügen. Wer besondere Anforderungen hat, nutzt eben besondere Libs, die entsprechende Fälle anders behandeln; meist auf Kosten der Performance.

Rechnen mit Floats ist immer ungenau, nicht nur bei Trigonometrie. Wenn dich das hier schon stört, müsstest du eigentlich schon weit eher pochende Schläfen bekommen: Es ist nämlich schon manchmal nicht möglich ein exakt eingegebenes Literal in ein Float zu packen:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  s: Single;
begin
  s := 0.01;
  Edit1.Text := FloatToStrF(s, ffFixed, 30, 30);
end;
Ergebnis: 0,009999999776482582

Hier müsstest du eigentlich schon aufgegeben haben. Aber das ist normal. Das ist überall so bei aktuellen üblichen Computern, und das war es auch schon Jahrzehnte lang.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#32

AW: tan() von Single, Double, etc.

  Alt 21. Nov 2017, 13:52
Wie ist denn der Tangens = tan(x) definiert?
In der Regel sagt man sin(x) / cos(x)!
Bei 90° haben wir sin(90°) / cos(90°) = 1 / 0.
Irgendetwas durch irgendetwas unendlich kleines ist halt abnormal übergroß bzw. unendlich.

Das kann man auch in der System.Math so nachlesen (hier nicht relevante Compiler-Direktiven entfernt):
Delphi-Quellcode:
  { The following constants should not be used for comparison, only
    assignments. For comparison please use the IsNan and IsInfinity functions
    provided below. }

  NaN = 0.0 / 0.0;
  Infinity = 1.0 / 0.0;
  NegInfinity = -1.0 / 0.0;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#33

AW: tan() von Single, Double, etc.

  Alt 21. Nov 2017, 13:59
Es ist nämlich schon manchmal nicht möglich ein exakt eingegebenes Literal in ein Float zu packen:
Das ist schon richtig! Allerdings lässt sich gerade 90 schon exakt darstellen. Daher besteht berechtigte Hoffnung, daß bei Verwendung von Grad statt Radians die Singularitäten schon erkannt werden können bevor man in Radians umrechnet.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#34

AW: tan() von Single, Double, etc.

  Alt 21. Nov 2017, 14:51
Es ist nämlich schon manchmal nicht möglich ein exakt eingegebenes Literal in ein Float zu packen:
Das ist schon richtig! Allerdings lässt sich gerade 90 schon exakt darstellen. Daher besteht berechtigte Hoffnung, daß bei Verwendung von Grad statt Radians die Singularitäten schon erkannt werden können bevor man in Radians umrechnet.
Ja natürlich. Aber dies von der Tan()-Funktion die von Hause aus mitgeliefert wird, und die dokumentierterweise mit Floats und in Radians arbeitet zu erwarten und sogar als Bug zu bezeichnen ist schlicht vermessen. Es ist nicht der Fehler von Emb wenn ein Nutzer die Technologie die er einsetzt nicht ausreichend kennt, dies aber dank mannigfaltig verfügbarer Ressourcen heutzutage jedoch problemlos könnte. Die Tan()-Funktion in Delphi arbeitet zu 100% so wie man es von ihr erwarten kann/muss. Darum geht es mir.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#35

AW: tan() von Single, Double, etc.

  Alt 21. Nov 2017, 15:02
Die Tan()-Funktion in Delphi arbeitet zu 100% so wie man es von ihr erwarten kann/muss. Darum geht es mir.
Das sehe ich genau so!
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.094 Beiträge
 
Delphi 12 Athens
 
#36

AW: tan() von Single, Double, etc.

  Alt 22. Nov 2017, 07:28
@TiGü
Zitat:
In der Regel sagt man sin(x) / cos(x)!
Bei 90° haben wir sin(90°) / cos(90°) = 1 / 0.
Ja logisch, ich hatte nur von der Kurve drauf geschlossen das es springt.
So gesehen macht es natürlich wunderbar Sinn.

@Medium
Mir ist das Alles schon klar, aber wie das jetzt implementiert ist FPU, GPU oder CPU interessiert mich nur am Rande.
Wichtig für mich wäre das es am Ende mathematisch korrekt interpretiert werden kann.

Wie du selbst siehst springt auch dein Ergebnis, und die Zahlen sind relativ "random".
Zitat:
Derselbe Rechner liefert für
tan(s) = -22877332.42942889836981039204072541441251573432
tan(d) = 16882959411340397.91436507298177193134
tan(e) = -1300934329906107203.0757511956816777
Wird das so gespeichert, und man schaltet mal von Single auf Double, etc. passt das nicht zusammen.

Ich verstehe ja das Argument das der Fehler sowieso zu klein ist um ein Problem zu sein,
ich muss aber diese Werte in verschiedene Einheiten Umrechen, und zurückrechnen (°, %, mm/m, in/ft, ...).

Das Problem was ich sehe ist das bei Rechnung und Rückrechnung am Ende ein verschiedene Werte rauskommen.
Klar wird der Fehler minimal sein, aber z.B. die Zahlen oben zeigen auch das es +/- springen kann,
und das würde bei mir im Ergebnis eine falsche Richtungsanzeige bedeuten.

Wenn man die Rechnung vor- und zurück öfters macht käme u.U. ständig wechselnde Werte und Richtungen heraus,
was für meinen Fall nicht Optimal wäre.
Also müsste ich diesen Fall im Aufruf abfangen und sauber definieren, z.B. durch +/-Infinity, die Methode von
gammatester sieht dazu sehr gut für mich aus.

Edit:
Weiterhin wären die Ergebnisse, obwohl logisch gleich im Vergleich nicht mehr gleich.
Auch das kommt als Problem heraus.

Ich will auch gar nicht die tan() Funktion anzweifeln, das dies so korrekt ist sehe ich auch so, sondern ich wollte nur mal wissen wie Ihr mit solchen Problemen umgeht.
Lediglich das welcher Stelle man das Infinity abfangen sollte wäre interessant.
Also bitte wieder locker werden ...

Rollo

Geändert von Rollo62 (22. Nov 2017 um 07:42 Uhr)
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.070 Beiträge
 
Delphi 10.4 Sydney
 
#37

AW: tan() von Single, Double, etc.

  Alt 22. Nov 2017, 09:11
Wenn man die Rechnung vor- und zurück öfters macht käme u.U. ständig wechselnde Werte und Richtungen heraus, was für meinen Fall nicht Optimal wäre.
Also müsste ich diesen Fall im Aufruf abfangen und sauber definieren, z.B. durch +/-Infinity, die Methode von
gammatester sieht dazu sehr gut für mich aus.
Edit:
Weiterhin wären die Ergebnisse, obwohl logisch gleich im Vergleich nicht mehr gleich.
Auch das kommt als Problem heraus.
Hier ist doch schon dein Denkfehler. Du willst mit dem Ergebnissen von Tan(90°) und Tan(270°) weiterrechnen.
Das geht aber nicht! Es ist sachlich falsch. Die entstehenden sehr großen positiven und negativen Zahlen sind nicht richtig.
Warum wurde auch schon hinreichend dargelegt.

Ich will auch gar nicht die tan() Funktion anzweifeln, das dies so korrekt ist sehe ich auch so, sondern ich wollte nur mal wissen wie Ihr mit solchen Problemen umgeht.
Lediglich das welcher Stelle man das Infinity abfangen sollte wäre interessant.
Lösungen dazu wurden dir vielfach gezeigt.
Siehe Beitrag #23 und #24 oder nehme eine von den schon genannten Mathematik-Bibliotheken.
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.094 Beiträge
 
Delphi 12 Athens
 
#38

AW: tan() von Single, Double, etc.

  Alt 22. Nov 2017, 09:21
Zitat:
Hier ist doch schon dein Denkfehler. Du willst mit dem Ergebnissen von Tan(90°) und Tan(270°) weiterrechnen.
Genau DAS will ich nicht, sondern diese Situationen möglichst elegant Vermeiden.

So das die Routinen möglichst fehlerfrei damit umgehen können.
Deshalb bin ich ja ein Verfechter von +/-Infinity, weil das dem entspricht was ich hier methematisch erwarte.

Die tan() Routinen liefern aber stattdessen irgendeinen Wert zurück.

Das Thema ist für mich erstmal erledigt, ich schaue mir die Lösungen aus den Units von gammatester mal genauer an,
und ich werde wohl +/-Infinity einführen um darauf Testen und Reagieren zu können.
Dankesehr für die konstruktiven Vorschläge und Anregungen.

Rolf
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#39

AW: tan() von Single, Double, etc.

  Alt 22. Nov 2017, 10:28
ich werde wohl +/-Infinity einführen um darauf Testen und Reagieren zu können.
Dank der diversen FloatHelper gibt es das bereits:
Delphi-Quellcode:
var
  myFloat: Single; // oder Double, Extended

{ Abfragen }
if myFloat.IsPositiveInfinity then...
if myFloat.IsNegativeInfinity then...
if myFloat.IsInfinity then... // prüft beides
{ auch }
if myFloat.IsNan then...

{ Zuweisungen, passen automatisch zu der Deklaration von myFloat.
  Alternative über direkte Typangabe (z.B. Single.NaN) }

myFloat := myFloat.NegativeInfinity;
myFloat := myFloat.PositiveInfinity;
myFloat := myFloat.NaN;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#40

AW: tan() von Single, Double, etc.

  Alt 22. Nov 2017, 11:18
@Medium
Mir ist das Alles schon klar, aber wie das jetzt implementiert ist FPU, GPU oder CPU interessiert mich nur am Rande.
Wichtig für mich wäre das es am Ende mathematisch korrekt interpretiert werden kann.

Wie du selbst siehst springt auch dein Ergebnis, und die Zahlen sind relativ "random".
Zitat:
Derselbe Rechner liefert für
tan(s) = -22877332.42942889836981039204072541441251573432
tan(d) = 16882959411340397.91436507298177193134
tan(e) = -1300934329906107203.0757511956816777
Nein, dir ist es offenbar nicht so ganz klar. Das Problem ist nicht die Funktion tan() (oder irgendeine andere), sondern das "Problem" setzt schon vorher an. Nämlich an der Stelle, an der du versuchst einen Wert, der "in echt" unendlich viele (und nicht-wiederholende) Nachkommastellen hat in einen begrenzten Speicherplatz zu schreiben, und diesen als Parameter übergibst.
Die Funktion rechnet genau richtig - für den Wert, der nachher im Parameter wirklich steht. Da ist auch nichts "random" dran. Auf derselben CPU wird völlig deterministisch immer derselbe Wert herauskommen. Die Rundungen und Umwandlungen sind klar definiert und dokumentiert (halt nicht in der Emba-Doku sondern in den Specs der jeweiligen CPU).

Dein Denkfehler ist, dass du nicht wahrnimmst, dass DegToRad(90) schon zu einem Ergebnis führt, das von dem "echt-Welt"-Wert PI/2 abweicht. Und ohne Mechanismen dies gezielt zu umschiffen ist dies für die meisten Architekturen auch einfach schlicht unmöglich. tan() sollte NIEMALS NaN oder +/-Inf zurückgeben, da es keine Möglichkeit gibt sie mit einem Parameter aufzurufen für den diese Ergebnisse richtig wären.

Zitat:
ich muss aber diese Werte in verschiedene Einheiten Umrechen, und zurückrechnen (°, %, mm/m, in/ft, ...).
Ja und? Was hat das damit zu tun?

Zitat:
Das Problem was ich sehe ist das bei Rechnung und Rückrechnung am Ende ein verschiedene Werte rauskommen.
Klar, das ist normal bei binärer Gleitkommaarithmetik. Nicht alle Zahlen die dezimal mit endlich vielen Stellen geschrieben werden können sind in dieser Darstellung endlich darstellbar. Und sobald (vielfache von) PI ins Spiel kommen gilt dies für beide Systeme, sodass bei Rechnung und Umwandlung zwischen diesen Rundungsfehler auftreten müssen.

Zitat:
Klar wird der Fehler minimal sein, aber z.B. die Zahlen oben zeigen auch das es +/- springen kann,
und das würde bei mir im Ergebnis eine falsche Richtungsanzeige bedeuten.
Klar, da man um einen Grenzbereich herum rundet. Zu erwarten. Wenn du in Grad rechnest (was kein Computer intern tut), dann ist das ein Sonderfall, den du eben als solchen gesondert behandeln musst.

Was du ja jetzt auch tust. Aber ich bin mir noch immer nicht sicher, dass du wirklich verstanden hast, wo der Hund im Ursprung begraben liegt.

Zitat:
Edit:
Weiterhin wären die Ergebnisse, obwohl logisch gleich im Vergleich nicht mehr gleich.
Auch das kommt als Problem heraus.
Auch dies ist ein [i]normaler[i] Umstand bei Floats, und zu dem Thema "Floats vergleichen" gibt es mehrere zig Threads in diesem Forum hier allein.

Zitat:
Also bitte wieder locker werden ...
Jetzt, ja Mich bringt nur auf die Palme wenn man versucht eigenen Mangel an Informationen als Fehler anderer auszulegen, bzw. davon auszugehen dass die eigene Sichtweise und Erwartungshaltung universell wären. Aber du hast ja nun eine Lösung. Das freut mich!
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 4 von 5   « Erste     234 5      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:45 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz