Delphi-PRAXiS
Seite 2 von 5     12 34     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   tan() von Single, Double, etc. (https://www.delphipraxis.net/194431-tan-von-single-double-etc.html)

Medium 20. Nov 2017 13:23

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

Zitat von Rollo62 (Beitrag 1386709)
Ja, genau dehalb bezeiche ich als "Bug", denn das genaue Verhalten ist ja nicht dokumentiert und bei Single, Double, etc. auch individuell anders.

Genau genommen ist es eigentlich eine wohlbekannte und zwangsweise Folge des Rechnens mit Zahlendarstellungen nach IEEE 754. Braucht man höhere Genauigkeit als diese zusichern, muss man zu entsprechenden Libs greifen die diese Eigenschaften umschiffen.

Zitat:

Das mag sein, mir geht es aber um die Richtigkeit der Ergebnisse.
Nochmal: Die Ergebnisse sind richtig. Die Eingabe in Grad und die Nutzung von binärer Gleitkommaarithmetik verschleiern lediglich die Rundungen die auf dem Weg zum Ergebnis hin notwendigerweise passieren. Wie schon erwähnt wirst du genau genommen (und darum geht es dir ja) es niemals schaffen der tan() Funktion einen Parameter zu übergeben der korrekterweise zu NaN führt, da eben genau diese Parameter schon per Definition eine Wertigkeit haben, die kein x86 Computer der Welt (nativ) korrekt abbilden kann.

Zitat:

Das Ganze hat für mich den Geschmack von "irgendeinen Tod muss man sterben".
Das ist schon durch die Nutzung von binären Gleitkommazahlen abgemachte Sache.

gammatester 20. Nov 2017 14:39

AW: tan() von Single, Double, etc.
 
Das mit nachträglichen Korrektur ist doch Bastelei, und jemandem, dem es auf Genauigkeit ankommt, unwürdig. Selbst bei einem Bereich von -1000..1000 wäre dann tan(89.95°) ungültig. Und ich würde mit Recht darauf hinweisen, daß das ein Bug ist.

Wie gesagt, die Gleitkomma-Arithmetik ist exakt, genau so exakt wie Integer-Arithmetik. Sorgen mach mir der schlampige Umgang von EMBA z.B. mit der Bereichsreduktion für sin, cos etc. Für Beispiele im Vergleich zu DAmath siehe unten. Und selbstverständlich kann man die Polstellen für tan bei 90° + k * 180° sauber darstellen, die Funktion tand in DAMath liefert allerdings Infinity statt NaN.
Code:
(Machine eps for double = 2.220446049250E-016)
-----------------------------------------------------------------
Test of DAMath.cos
at 10000 random values in [-10.0000000000 .. 10.0000000000]
RMS = 0.25, max rel = 0.91 eps at
 x(dbl) =    -8.11413601040840E+000 = $C0203A7009000000
 y(dbl) =    -2.57229736666779E-001 = $BFD07673B6A2B86F
 y(mpf) = -2.57229736666778837208918104020787799191734279958E-1

Test of DAMath.cos
at 10000 random values in [0.0000000000 .. 1000000000.0000000000]
RMS = 0.24, max rel = 0.90 eps at
 x(dbl) =     3.09463918209076E+008 = $41B2720B6E358600
 y(dbl) =    -2.58174239840314E-001 = $BFD085ED3F3229E9
 y(mpf) = -2.58174239840313841975953009564740744055663588700E-1

Test of DAMath.cos
at 10000 random values in [1000000000.0000000000 .. 5.000000000000E+018]
RMS = 0.24, max rel = 0.88 eps at
 x(dbl) =     6.18510209900251E+017 = $43A12AC7848E1D0B
 y(dbl) =     2.60040880178592E-001 = $3FD0A48280FF5DF3
 y(mpf) = +2.60040880178592397382630269801769340226378199265E-1

Test of system.cos
at 10000 random values in [-10.0000000000 .. 10.0000000000]
RMS = 0.19, max rel = 0.55 eps at
 x(dbl) =     7.85423278808594E+000 = $401F6ABC00000000
 y(dbl) =    -2.51154108814005E-004 = $BF3075AAAF01351D
 y(mpf) = -2.51154108814004449238616298892359426342137631612E-4

Test of system.cos
at 10000 random values in [0.0000000000 .. 1000000000.0000000000]
RMS = 257703.83, max rel = 14362143.15 eps at
 x(dbl) =     7.73584246635437E+008 = $41C70DFABB515600
 y(dbl) =     3.12296110038815E-004 = $3F347775944C00FF
 y(mpf) = +3.12296109042891252641009359676336492980461957722E-4

Test of system.cos
at 10000 random values in [1000000000.0000000000 .. 5.000000000000E+018]
RMS = 931290736633651.00, max rel = 60109746020807300.00 eps at
 x(dbl) =     2.46350079825587E+018 = $43C1180E763FF750
 y(dbl) =     2.93392152252295E-003 = $3F6808E11F9FE142
 y(mpf) = -2.37621355417792405078768037054894663841091297810E-4

TiGü 20. Nov 2017 15:12

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

Zitat von Rollo62 (Beitrag 1386709)
Das Ganze hat für mich den Geschmack von "irgendeinen Tod muss man sterben".

Die Frage ist halt auch, wie genau man es braucht? Und wofür wird es gebraucht?
Für komplexe mathematische Geschichten würde ich auf eine externe Bibliothek setzen.
Ob man wirklich den tan-Wert für bspw. 89.9999° braucht sei mal dahingestellt.
Die Genauigkeit, bis wann man welche Eingangswerte behandelt muss man sich vorher überlegen.
Was für Werte hast du denn? Willst du irgendwas darstellen?

Delphi-Quellcode:
const
  FAKTOR = 10000;

procedure Main;
var
  I: Integer;
  Degree, Rad, TanResult: Double;
  LogMsg: string;
  DegArray: TArray<Integer>;
begin
  for I := 89 * FAKTOR to 90 * FAKTOR do
  begin
    Degree := I / FAKTOR;
    Rad := DegToRad(Degree);
    TanResult := Tan(Rad);
    LogMsg := '';
    if InRange(TanResult, -500000, 500000) then
    begin
      LogMsg := Format('Grad: %2.4f - Tan: %2.4f', [Degree, TanResult]);
    end
    else
      LogMsg := Format('Ungültige Eingabe für Tan(%2.4f) - Tan: %2.4f', [Degree, TanResult]) ;

    if LogMsg <> '' then
      Writeln(LogMsg);
  end;
end;

Redeemer 20. Nov 2017 17:29

AW: tan() von Single, Double, etc.
 
@gammatester: Ich verwende derzeit in meiner SVG-Unit die trigonometrischen Funktionen von Delphi. Genutzt werden ausschließlich Extended-Werte. Die Genauigkeit überzeugt mich nicht. Verbessert AMath (nicht DAMath) desselben Autors diese Genauigkeit merklich?

Medium 20. Nov 2017 17:55

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

Zitat von gammatester (Beitrag 1386718)
daß das ein Bug ist.

Dann ist es ein Bug in jeder x86/x64 CPU der Welt. Denn Delphi macht nichts anderes als deren integrierten trigonometrischen Funktionen ohne viel drumrum direkt zu nutzen. In meinen Augen KEIN Bug, sondern eine systembedingte, bekannte Designschwäche, mit der ALLE Compiler entweder leben müssen, und/oder für gehobene Ansprüche Libs einsetzen, die die Spezialfälle gezielt abdecken.

Und NEIN, du kannst 90° usw. niemals 100%ig korrekt darstellen, es sei denn du hast unendlich breite Register, ooooder eben eine Lib die bei entsprechenden Parametern gesondert vorgeht, und/oder andere Algorithmen verwendet, die sich nicht auf die integrierten Funktionen der CPU verlassen. (Die sind dann natürlich etwas langsamer in aller Regel.)

gammatester 20. Nov 2017 18:49

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

Zitat von Medium (Beitrag 1386744)
Zitat:

Zitat von gammatester (Beitrag 1386718)
daß das ein Bug ist.


Lies noch einmal genau nach! Ich habe beschrieben:
Zitat:

Zitat von gammatester (Beitrag 1386718)
Das mit nachträglichen Korrektur ist doch Bastelei, und jemandem, dem es auf Genauigkeit ankommt, unwürdig. Selbst bei einem Bereich von -1000..1000 wäre dann tan(89.95°) ungültig. Und ich würde mit Recht darauf hinweisen, daß das ein Bug ist.

Und wenn tan(89.95°)=Nan oder Inf oder was auch immer Du als ungültig wählst, kein Bug wäre, was ist dann noch ein Bug?
Zitat:

Zitat von Medium (Beitrag 1386744)
Und NEIN, du kannst 90° usw. niemals 100%ig korrekt darstellen, es sei denn du hast unendlich breite Register, ooooder eben eine Lib die bei entsprechenden Parametern gesondert vorgeht, und/oder andere Algorithmen verwendet, die sich nicht auf die integrierten Funktionen der CPU verlassen.

Das ist doch Unsinn, selbstverständlich kann 90 exakt als Double/Single darstellen, und man braucht auch keine 'unendlich breite' Register, um korrekt gerundete Werte für sin, tan etc auszurechnen. Man muß es nur wollen! Für ein frei zugängliches Beispiel zu nennen siehe http://cvsweb.openbsd.org/cgi-bin/cv.../lib/libm/src/, und nicht wie EMBA, das Problem aussitzen. Immerhin haben sie in der 64-Bit-RTL einen Schritt in die richtige Richtung gemacht und eine schon 37 Jahre junge Technik von Cody/Waite übernommen, aber den letzten Schritt woll(t)en sie nicht gehen, aus welchen Gründen auch immer (zumindest im letzten für mich vorliegen Quellcode of Delphi18/XE4).

gammatester 20. Nov 2017 18:59

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

Zitat von Redeemer (Beitrag 1386741)
@gammatester: Ich verwende derzeit in meiner SVG-Unit die trigonometrischen Funktionen von Delphi. Genutzt werden ausschließlich Extended-Werte. Die Genauigkeit überzeugt mich nicht. Verbessert AMath (nicht DAMath) desselben Autors diese Genauigkeit merklich?

Ja, und wenn Du Fragen hast, stehe ich selbstverständlich zur Verfügung. Bei den trigonometrischen extended Funktionen kommt erschwerend hinzu, daß ein viel größerer Bereich bis 2^16384 behandelt werden muss und die Reduktion mod 2*Pi entsprechend aufwendig ist. Für Vergleiche siehe die Datei t_amathx.cmp im Archiv http://www.wolfgang-ehrhardt.de/amath_2017-11-02.zip.

Uwe Raabe 20. Nov 2017 21:28

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

Zitat von gammatester (Beitrag 1386746)
Das ist doch Unsinn, selbstverständlich kann 90 exakt als Double/Single darstellen,

Dummerweise nimmt die Funktion aber keine Grad an sondern Radians. Daher werden die 90° mit einer nur begrenzt genauen Repräsentation von π multipliziert, was dann im Ergebnis eben nicht genau π/2 entspricht.

gammatester 20. Nov 2017 22:02

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

Zitat von Uwe Raabe (Beitrag 1386751)
Dummerweise nimmt die Funktion aber keine Grad an sondern Radians. Daher werden die 90° mit einer nur begrenzt genauen Repräsentation von π multipliziert, was dann im Ergebnis eben nicht genau π/2 entspricht.

Richtig, aber so sollte eine
Delphi-Quellcode:
tand(x)
Funktion mit Argumenten in ° ja auch nicht programmiert werden (tand ist eine de-facto Standardbezeichnung, sie zB Matlab, Scilab, Octave oder GNU Fortran.

Zuerst wird x modulo 360 reduziert, dann werden exakte Werte 0,+1,Inf,-1 je nach Vielfachen von 45 zurückgeliefert, der Rest (bei geschickter Reduktion ist der im Bereich -45 < x < 45) wird halt mit Pi/180 multipliziert und dann mit
Delphi-Quellcode:
math.tan
weiter verarbeitet. In diesem Bereich sind selbst die Delphi-Funkionen genau genug (und es gibt keinen Pol/Infinity).

Uwe Raabe 20. Nov 2017 23:42

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

Zitat von gammatester (Beitrag 1386755)
Richtig, aber so sollte eine
Delphi-Quellcode:
tand(x)
Funktion mit Argumenten in ° ja auch nicht programmiert werden

Da zum Delphi-Sprachumfang aber nun mal keine tand-Funktion gehört (Delphi 5 kannte noch nicht einmal tan), kann man sich ja bei Bedarf was Passendes selbst programmieren. Mach doch mal einen Vorschlag so wie du es dir vorstellst.

Kleine Anmerkung am Rande:
Die Delphi Tan-Funktion wird je nach Zielplattform auf eine eigene Implementierung namens Tangent in System.pas weitergeleitet. Potentiell kommen da auf unterschiedlichen Plattformen und Prozessoren auch unterschiedliche Werte raus.


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:53 Uhr.
Seite 2 von 5     12 34     Letzte »    

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