Quand une fonction trigonométrique, avec un argument degré, devrait-elle retourner -0,0?

10

Dans la création de fonctions trigonométriques my_sind(d), my_cosd(d), my_tand(d), qui a utilisé un argument de degré plutôt qu'un radian et a fourni des réponses précises à des multiples de 90, j'ai remarqué que le résultat était parfois-0.0 plutôt que 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()et tan()retournent généralement le même résultat de signe zéro pour une entrée de signe zéro donnée. Il est logique quemy_sin() corresponde sin()à ces entrées.

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

La question est : pour quel nombre entiernon_zero_n doit / peut le résultat jamais revenir -0.0pour my_sind(180*non_zero_n), my_cosd(180*n + 180), my_tand(180*non_zero_n)?

Il est assez facile de coder donc ne f(-0.0)produit -0.0et n'en a plus besoin. Je me demande simplement s'il y a une raison de faire un autre f(x) retour -0.0pour un autre ( non nul ) xet l'importance d'assurer ce signe.


Remarque: Il ne s'agit pas de savoir pourquoi 0.0vs -0.0se produit. Ce n'est pas pourquoi cos(machine_pi/4)ne revient pas 0.0. Il ne s'agit pas non plus de savoir comment contrôler la génération de 0.0ou -0.0. Je le vois mieux comme une question de conception.

chux - Réintégrer Monica
la source

Réponses:

4

Le principe de conception de la «moindre surprise» suggère que nous nous tournons vers les fonctionnalités précédemment établies pour nous guider. Dans ce cas, la fonctionnalité établie la plus proche est fournie par sinpietcospi fonctions introduites dans IEEE Std 754-2008 (la norme IEEE pour l'arithmétique à virgule flottante), section 9. Ces fonctions ne font pas partie des normes ISO C et ISO C ++ actuelles, mais ont été incorporés dans les bibliothèques mathématiques de diverses plates-formes de programmation, par exemple CUDA.

Ces fonctions calculent sin (πx) et cos (πx), où la multiplication avec π se produit implicitement à l'intérieur de la fonction. tanpin'est pas défini, mais pourrait, sur la base de l'équivalence mathématique, être supposé fournir une fonctionnalité selon tanpi(x) = sinpi(x) / cospi(x).

Nous pouvons maintenant définir sind(x) = sinpi(x/180), cosd(x) = cospi(x/180), tand(x) = tanpi(x/180)de manière intuitive. La section 9.1.2 de IEEE-754 explique le traitement des arguments spéciaux pour sinpiet cospi. En particulier:

sinPi (+ n) est +0 et sinPi (−n) est −0 pour les entiers positifs n. Cela implique, dans les modes d'arrondi appropriés, que sinPi (−x) et −sinPi (x) sont le même nombre (ou les deux NaN) pour tout x. cosPi (n + ½) est +0 pour tout entier n lorsque n + ½ est représentable.

La norme IEEE 754-2008 ne fournit pas de justification pour les exigences citées, cependant, un avant- projet de la section pertinente déclare:

Si la valeur de la fonction est nulle, le signe de ce 0 est mieux déterminé en considérant l'extension continue de la fonction de signe de la fonction mathématique.

La lecture des archives du courrier du groupe de travail 754 peut fournir des informations supplémentaires, je n'ai pas eu le temps de les parcourir. En mettant en œuvre sind(), cosd()et tand()comme décrit ci-dessus, nous arrivons ensuite à ce tableau d'exemples de cas:

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
njuffa
la source
5

sin () et tan () renvoient généralement le même résultat de signe zéro pour une entrée de signe zéro donnée

Cela pourrait être généralement vrai puisque:

  • Vitesse / précision . Pour les doubles suffisamment petits, la meilleure réponse sin(x)est x. Autrement dit, pour les nombres inférieurs à environ 1.49e-8, le double le plus proche du sinus de x est en fait x lui-même (voir le code source de la glibc pour sin () ).

  • Traitement des cas spéciaux .

    Quelques opérations arithmétiques extraordinaires sont affectées par le signe zéro; par exemple, "1/(+0) = +inf"mais"1/(-0) = -inf" . Pour conserver son utilité, le bit de signe doit se propager à travers certaines opérations arithmétiques selon des règles dérivées de considérations de continuité.

    Les implémentations de fonctions transcendantales élémentaires comme sin (z) et tan (z) et leurs inverses et analogues hyperboliques, bien que non spécifiées par les normes IEEE, devraient suivre des règles similaires. La mise en œuvre de sin(z) devrait reproduire le signe de z ainsi que sa valeur àz = ±O .

    ( Coupes de branche pour des fonctions élémentaires complexes ou beaucoup de bruit sur le bit de signe de rien par W. Kahan)

    Le zéro signé négativement fait écho au concept d'analyse mathématique d'approcher le 0 par le bas comme une limite unilatérale (considérez 1 / sin(x): le signe de zéro fait une énorme différence).

ÉDITER

Compte tenu du deuxième point, j'écrirais my_sindpour que:

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

La dernière norme C (F.10.1.6 sinet F.10.1.7 tan, implémentations avec un zéro signé), spécifie que si l'argument est ±0, il est retourné sans modification .

EDIT 2

Pour les autres valeurs, je pense que c'est une question d'approximation. Étant donné 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

Donc, si my_sindfournit des réponses exactes à des multiples de 180 °, il peut revenir +0.0ou -0.0(je ne vois pas de raison claire de préférer l'une à l'autre).

Si elle my_sindutilise une approximation (par exemple une degree * M_PI / 180.0formule de conversion), elle devrait considérer comment elle approche les valeurs critiques.

manlio
la source
Quelles sont vos pensées concernant sind(180), sind(-180), sind(360), sind(-360),...?
chux
Merci pour la mise à jour. Peut-être que mon message n'est pas clair. La principale question est devrait my_trig(x)jamais revenir -0.0quand |x|est pas 0.0?
chux
Merci pour le "Donc, si my_sind fournit des réponses exactes par multiples de 180 °, il peut renvoyer +0,0 ou -0,0 (je ne vois pas de raison claire de préférer l'une à l'autre)." C'est le point de discussion le plus proche jusqu'à présent. Je pense que le "principe du moindre étonnement" encourage toujours le retour +0.0, mais je cherche à voir s'il y a des raisons impérieuses de revenir -0.0dans certaines situations (autres que x == +/-0.0).
chux
@chux: Je pense que pour des multiples de 180.0, il faut vraiment examiner les valeurs de précision relative de la machine étant donné ces valeurs. C'est-à-dire, le plus petit incrément / décrément qui donne une valeur représentable différente dans ce format numérique. Ensuite, comparez cette valeur avec la vraie valeur pour voir si elle tomberait du côté positif ou négatif.
rwong
@rwong Merci pour l'idée. 90,0 de multiples degrés , la exactes sind(double degrees) et la cosd(double degrees)valeur peuvent être retournés: -1.0, +0.0, +1.0. Ce message est sur le point d' -0.0être renvoyé (à l'exception de sind (-0.0)). Remarque: sind()n'utilise pas l' sin(x/360*M_PI)approche simpliste .
chux
3

La bibliothèque n'essaie pas de distinguer +0 de -0. IEEE 754 s'inquiète un peu de cette distinction ... J'ai trouvé les fonctions [en math.h] assez difficiles à écrire sans s'inquiéter du signe de rien. - PJ Plauger, The Standard C Library , 1992, page 128.

Formellement, les fonctions trig devraient retourner le signe de zéro en accord avec la norme C ... ce qui laisse le comportement indéfini.

Face à un comportement indéfini, le principe du moindre étonnement suggère de dupliquer le comportement de la fonction correspondante de math.h. Cela sent justifiable, tout en s'écartant du comportement de la fonction correspondante en math.hodeurs comme un moyen d'introduire des bogues dans le code exactement qui dépend du signe de zéro.

ben rudgers
la source
Les fonctions trig dans math.hne renvoient pas 0.0 lorsque des arguments donnés comme +/- pi / 2 ou +/- pi car ces fonctions ne peuvent prendre que des valeurs représentables près de +/- pi / 2, etc. Ces valeurs "proches" renvoient des résultats proches de 0,0. Étant donné que les fonctions trig de la bibliothèque std ( sin cos tan) ne renvoient pas 0,0 (ou -0,0) pour aucune entrée (sauf +/- 0,0), mais my_sind (), my_cosd (), my_tand () peuvent renvoyer 0,0 (ou -0,0), il y a aucun comportement 0.0 à dupliquer.
chux
@chux La prémisse qui sin(-0.0)devrait revenir -0est suspecte. Il traite un détail d'implémentation de la norme IEEE comme un principe trigonométrique. Bien qu'il existe un principe mathématique général de zéro comme limite de deux intervalles incorporés dans l'implémentation IEEE, il se produit à ce niveau d'abstraction hors de la trigonométrie générale [d'où la variabilité de ce que vos fonctions trigonométriques renvoient]. Le mieux qui puisse arriver est que vous puissiez définir une convention arbitraire, mais elle sera différente de math.hla nonchalance de 'sur le signe de zéro.
ben rudgers
Note: Je ne veux pas dire sin(-0.0)devrait revenir -0.0, mais my_sind(x)doit correspondre à sin(x)quand xest +/-0.0. IOW: suivez la pratique précédente. De plus, la question elle-même est plutôt de savoir quoi faire quand x != 0.0, devrait my_sind(x)jamais revenir -0.0comme dans my_sind(180), etc. Peut-être que votre réponse / commentaire répond à cela - mais je ne l'ai pas vu.
chux
@chux Si le comportement n'est pas défini, alors il n'est pas défini. C'est comme ça que C est. Plauger ne vous préoccupez pas +0contre -0quand il a écrit math.hil y a vingt ans. Pour moi, le problème que vous vous inquiétez de la différence résout n'est pas clair.
ben rudgers
1
Avec un peu de chance vous voyez que pour un bien implémenté sin(rad)pour n'importe quelle valeur rad>0et de n'importe quelle précision ne cédera jamais 0.0car pi est irrationnel. [Ref] (www.csee.umbc.edu/~phatak/645/supl/Ng-ArgReduction.pdf) Cependant, my_sind(deg)donne un exact 0.0(soit + ou -) chaque multiple de 180.0car la valeur 0.0 est le résultat mathématique correct. "Principe du moindre étonnement" suggère de renvoyer 0,0 dans ces cas. Ma question est devrait -0.0jamais être retournée dans ces cas?
chux