Wann sollte eine Triggerfunktion mit einem Gradargument -0.0 zurückgeben?


10

Bei der Erstellung trigonometrischen Funktionen my_sind(d), my_cosd(d), my_tand(d), dass ein gewisses Maß Argument , anstatt eine Radiant ein verwendet und genaue Antworten auf ein Vielfaches von 90 vorgesehen ist , bemerkte ich , dass das Ergebnis war manchmal -0.0nicht 0.0.

my_sind( 0.0) -->  0.0
my_sind(-0.0) --> -0.0

my_sind(180.0) --> -0.0
my_sind(360.0) -->  0.0

sin()und geben tan()typischerweise das gleiche Vorzeichen-Null-Ergebnis für eine gegebene Vorzeichen-Null-Eingabe zurück. Es ist sinnvoll, dass für diese Eingaben my_sin()übereinstimmen sollte sin().

my_sind( 0.0) alike sin( 0.0) -->  0.0
my_sind(-0.0) alike sin(-0.0) --> -0.0

Die Frage ist : für das, was ganze Zahl non_zero_nsollte / kann das Ergebnis je zurückkehren -0.0für my_sind(180*non_zero_n), my_cosd(180*n + 180), my_tand(180*non_zero_n)?

Es ist einfach genug zu codieren, also nur f(-0.0)produziert -0.0und damit fertig. Einfach fragen, ob es einen Grund gibt, eine andere f(x) Rendite -0.0für eine andere ( ungleich Null ) xzu erzielen, und wie wichtig es ist, dieses Zeichen zu versichern.


Hinweis: Dies ist keine Frage, warum 0.0vs. -0.0auftritt. Dies ist nicht der Grund, warum cos(machine_pi/4)nicht zurückkehrt 0.0. Dies ist auch keine Frage, wie die Erzeugung von 0.0oder gesteuert werden kann -0.0. Ich sehe es am besten als Designfrage.

Antworten:


4

Das Designprinzip der "geringsten Überraschung" legt nahe, dass wir uns an zuvor etablierten Funktionen orientieren. In diesem Fall wird die am nächsten festgelegte Funktionalität durch sinpiund cospiFunktionen bereitgestellt, die in IEEE Std 754-2008 (IEEE-Standard für Gleitkomma-Arithmetik), Abschnitt 9, eingeführt wurden. Diese Funktionen sind jedoch nicht Teil der aktuellen ISO C- und ISO C ++ - Standards, sondern wurden in die Mathematikbibliotheken verschiedener Programmierplattformen, beispielsweise CUDA, integriert.

Diese Funktionen berechnen sin (πx) und cos (πx), wobei die Multiplikation mit π implizit innerhalb der Funktion erfolgt. tanpiist nicht definiert, könnte aber aufgrund der mathematischen Äquivalenz als funktional angenommen werden tanpi(x) = sinpi(x) / cospi(x).

Wir können nun definieren sind(x) = sinpi(x/180), cosd(x) = cospi(x/180), tand(x) = tanpi(x/180)auf intuitive Art und Weise. In Abschnitt 9.1.2 von IEEE-754 wird der Umgang mit speziellen Argumenten für sinpiund beschrieben cospi. Speziell:

sinPi (+ n) ist +0 und sinPi (−n) ist −0 für positive ganze Zahlen n. Dies impliziert unter geeigneten Rundungsmodi, dass sinPi (–x) und –sinPi (x) für alle x die gleiche Zahl (oder beide NaN) sind. cosPi (n + ½) ist +0 für jede ganze Zahl n, wenn n + ½ darstellbar ist.

Der IEEE 754-2008-Standard gibt keine Begründung für die angegebenen Anforderungen, ein früher Entwurf des relevanten Abschnitts besagt jedoch:

Wenn der Wert der Funktion Null ist, wird das Vorzeichen dieser 0 am besten unter Berücksichtigung der kontinuierlichen Erweiterung der Vorzeichenfunktion der mathematischen Funktion bestimmt.

Die Durchsicht des Mail-Archivs der 754-Arbeitsgruppe kann zusätzliche Erkenntnisse liefern. Ich hatte keine Zeit, es zu durchsuchen. Die Umsetzung sind(), cosd()und tand()wie oben beschrieben, wir an diesem Tisch von Beispielfällen dann ankommen:

SIND
 angle value 
  -540 -0
  -360 -0
  -180 -0
     0  0
   180  0
   360  0
   540  0

COSD
 angle value
  -630  0
  -450  0
  -270  0
   -90  0
    90  0
   270  0
   450  0

TAND
 angle value
  -540  0
  -360 -0
  -180  0
     0  0
   180 -0
   360  0
   540 -0

5

sin () und tan () geben normalerweise das gleiche Vorzeichen-Null-Ergebnis für eine gegebene Vorzeichen-Null-Eingabe zurück

Es könnte allgemein wahr sein, da:

  • Geschwindigkeit / Genauigkeit . Für klein genug , um Doppelzimmer, die beste Antwort für sin(x)ist x. Das heißt, für Zahlen kleiner als ungefähr 1.49e-8ist das dem Sinus von x am nächsten liegende Doppel tatsächlich x selbst (siehe den glibc-Quellcode für sin () ).

  • Behandlung von Sonderfällen .

    Einige außergewöhnliche arithmetische Operationen werden durch das Nullzeichen beeinflusst. zum Beispiel "1/(+0) = +inf"aber "1/(-0) = -inf". Um seine Nützlichkeit beizubehalten, muss sich das Vorzeichenbit durch bestimmte arithmetische Operationen gemäß Regeln ausbreiten, die aus Kontinuitätsüberlegungen abgeleitet wurden.

    Es wird erwartet, dass Implementierungen elementarer transzendentaler Funktionen wie sin (z) und tan (z) und ihrer Inversen und hyperbolischen Analoga, obwohl sie nicht durch die IEEE-Standards spezifiziert sind, ähnlichen Regeln folgen. Es sin(z) wird erwartet, dass diezz = ±O Implementierung von das Vorzeichen sowie dessen Wert bei reproduziert .

    ( Branch Cuts für komplexe Elementarfunktionen oder viel Lärm um Nothing's Sign Bit von W. Kahan)

    Negativ vorzeichenbehaftete Null spiegelt das mathematische Analysekonzept wider, sich 0 als einseitige Grenze von unten zu nähern (bedenken Sie 1 / sin(x): Das Vorzeichen Null macht einen großen Unterschied).

BEARBEITEN

In Anbetracht des zweiten Punktes würde ich my_sindso schreiben :

my_sind(-0.0) is -0.0
my_sind(0.0) is 0.0

Der neueste C - Standard (F.10.1.6 sinund F.10.1.7 tan, Implementierungen mit einem signierten Null), die angibt , ob das Argument ist ±0, ist es nicht modifiziert zurückgegeben .

BEARBEITEN 2

Für die anderen Werte denke ich, dass es eine Frage der Annäherung ist. Gegeben M_PI<π:

0 = sin(π) < sin(M_PI)  1.2246467991473532e-16  +0.0
0 = sin(-π) > sin(-M_PI)  -1.2246467991473532e-16  -0.0
0 = sin(2*π) > sin(2*M_PI)  -2.4492935982947064e-16
0 = sin(-2*π) < sin(-2*M_PI)  2.4492935982947064e-16

Wenn also my_sindbei einem Vielfachen von 180 ° genaue Antworten geliefert werden, kann dies zurückkehren +0.0oder -0.0(ich sehe keinen klaren Grund, eines dem anderen vorzuziehen).

Wenn my_sindeine Annäherung verwendet wird (z. B. eine degree * M_PI / 180.0Umrechnungsformel), sollte berücksichtigt werden, wie sich die kritischen Werte nähern.


Was denkst du darüber sind(180), sind(-180), sind(360), sind(-360),...?
chux

Danke für das Update. Vielleicht ist mein Beitrag nicht klar. Die Hauptfrage ist, sollte my_trig(x)jemals zurückkehren, -0.0wenn |x|nicht 0.0?
chux

Vielen Dank für die "Wenn my_sind also bei Vielfachen von 180 ° genaue Antworten liefert, kann es +0,0 oder -0,0 zurückgeben (ich sehe keinen klaren Grund, eine der anderen vorzuziehen)." Es ist der bisher engste Diskussionspunkt. Ich denke, dass das "Prinzip des geringsten Erstaunens" dazu ermutigt, immer wieder zurückzukehren +0.0, aber zu prüfen, ob es zwingende Gründe gibt, -0.0in bestimmten Situationen (außer x == +/-0.0) zurückzukehren.
chux

@chux: Ich denke, für ein Vielfaches von 180.0muss man wirklich die Werte der relativen Maschinengenauigkeit untersuchen, wenn diese Werte gegeben sind. Das heißt, das kleinste Inkrement / Dekrement, das in diesem numerischen Format einen anderen darstellbaren Wert ergibt. Vergleichen Sie diesen Wert dann mit dem wahren Wert, um festzustellen, ob er auf die Plus- oder Minus-Seite fällt.
Rwong

@rwong Danke für die Idee. Vielfache von 90,0 Grad , die genaue sind(double degrees) und cosd(double degrees)Wert können zurückgegeben werden : -1.0, +0.0, +1.0. Dieser Beitrag sollte ungefähr -0.0zurückgegeben werden (abgesehen von sind (-0.0)). Hinweis: sind()nicht nicht den vereinfach verwendet sin(x/360*M_PI)Ansatz.
chux

3

Die Bibliothek versucht nicht, +0 von -0 zu unterscheiden. IEEE 754 macht sich ziemlich viele Sorgen um diese Unterscheidung ... Ich fand die Funktionen [in math.h] ziemlich schwierig genug, um zu schreiben, ohne mich über das Vorzeichen von nichts zu ärgern. - PJ Plauger, The Standard C Library , 1992, Seite 128.

Formal sollten Triggerfunktionen das Vorzeichen Null gemäß dem C-Standard zurückgeben ... wodurch das Verhalten undefiniert bleibt.

Angesichts undefinierten Verhaltens schlägt das Prinzip des geringsten Erstaunens vor, das Verhalten der entsprechenden Funktion aus zu duplizieren math.h. Dies riecht gerechtfertigt, während es vom Verhalten der entsprechenden Funktion abweicht, wenn es math.hdarum geht, Fehler in genau den Code einzuführen, der vom Vorzeichen Null abhängt.


Die Triggerfunktionen in math.hgeben nicht 0.0 zurück, wenn Argumente wie +/- pi / 2 oder +/- pi angegeben werden, da diese Funktionen nur darstellbare Werte in der Nähe von +/- pi / 2 usw. Annehmen können. Diese "nahen" Werte geben Ergebnisse nahe 0,0 zurück. Da die sin cos tanTriggerfunktionen der Standardbibliothek () für keine Eingabe 0.0 (oder -0.0) zurückgeben (außer +/- 0.0), können my_sind (), my_cosd (), my_tand () 0.0 (oder -0.0) zurückgeben Kein 0.0-Verhalten zum Duplizieren.
chux

@chux Die Prämisse, sin(-0.0)die zurückkehren sollte, -0ist verdächtig. Es behandelt ein Implementierungsdetail des IEEE-Standards als trigonometrisches Prinzip. Obwohl es ein allgemeines mathematisches Prinzip von Null als Grenze für zwei in der IEEE-Implementierung enthaltene Intervalle gibt, tritt es auf dieser Abstraktionsebene nicht innerhalb der allgemeinen Trigonometrie auf [daher die Variabilität dessen, was Ihre trigonometrischen Funktionen zurückgeben]. Das Beste, was passieren kann, ist, dass Sie eine beliebige Konvention definieren können, die jedoch von math.hder Nonchalance über das Vorzeichen Null abweicht.
Ben Rudgers

Hinweis: Ich schlage nicht sin(-0.0)vor, zurückzukehren -0.0, aber das my_sind(x)sollte übereinstimmen, sin(x)wenn es xist +/-0.0. IOW: Befolgen Sie die vorherigen Übungen. Weiter ist die Frage selbst mehr darüber, was zu tun ist, wann x != 0.0, sollte my_sind(x)jemals -0.0wie in my_sind(180)usw. zurückkehren? Vielleicht spricht Ihre Antwort / Ihr Kommentar das an - aber das habe ich nicht gesehen.
chux

@chux Wenn das Verhalten undefiniert ist, ist es undefiniert. So ist C eben. Plauger hat sich keine Sorgen um +0gegen , -0als er schrieb math.hvor zwanzig Jahren. Mir ist nicht klar, welches Problem Ihr Ärger über den Unterschied löst.
Ben Rudgers

1
Hoffentlich sehen Sie, dass für ein gut implementiertes sin(rad)für jeden Wert rad>0und von jeder Präzision niemals nachgeben wird, 0.0da pi irrational ist. [Ref] (www.csee.umbc.edu/~phatak/645/supl/Ng-ArgReduction.pdf) my_sind(deg)Ergibt jedoch ein genaues 0.0(entweder + oder -) jedes Vielfache von, 180.0da der Wert 0.0 das richtige mathematische Ergebnis ist. "Prinzip des geringsten Erstaunens" schlägt vor, in diesen Fällen 0,0 zurückzugeben. Meine Frage ist, sollte -0.0in diesen Fällen jemals zurückgegeben werden?
chux
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.