67 votes

Pourquoi NaN^0 == 1

A la suite d'un code de golf antérieur, pourquoi le feraient-ils ?

>NaN^0
[1] 1

C'est tout à fait logique pour NA^0 à 1 parce que NA est une donnée manquante, et cualquier un nombre porté à 0 donne 1, y compris -Inf y Inf . Cependant NaN est censé représenter pas un numéro Pourquoi en est-il ainsi ? C'est d'autant plus déroutant et inquiétant que la page d'aide de ?NaN États :

Dans R, toutes les fonctions mathématiques (y compris les fonctions de base de la Arithmetic ), sont censés fonctionner correctement avec +/- Inf y NaN comme d'entrée ou de sortie.

La règle de base devrait être que les appels et les relations avec les Inf sont vraiment avec une limite mathématique appropriée.

Calculs impliquant NaN renverra NaN ou peut-être NA : lequel de ces deux n'est pas n'est pas garanti et peut dépendre de la plate-forme R (puisque compilateurs peuvent réordonner les calculs).

Y a-t-il une raison philosophique à cela, ou est-ce simplement lié à la façon dont R représente ces constantes ?

0 votes

Je ne sais pas pour R mais la même chose se produit en Python sur ma machine avec la même erreur : 1**nan returning 1.0

6 votes

@hivert au moins dans le cas de R ^ est une fonction qui ne se contente pas d'appeler la fonction C fonction pow Il vérifie si la base est 1 ou si l'exposant est 0 et si l'un ou l'autre est TRUE il renvoie 1. avant d'appeler pow : if((x1 = INTEGER(s1)[i1]) == 1 || (x2 = INTEGER(s2)[i2]) == 0); REAL(ans)[i] = 1.;

3 votes

Je ne suis pas convaincu NA^0 == 1 n'a pas non plus beaucoup de sens parce que Inf^0 est une forme indéterminée. En d'autres termes, lorsqu'elle est considérée comme une limite, nous ne pouvons pas déterminer, à partir de cette seule forme, quelle était la valeur de la limite d'origine. Par exemple, lorsque n s'approche de l'infini, exp(n)^*(1/n) se rapproche de e, mais n^(1/n) s'approche de 1, même si les deux ont l'air de Inf^0 .

28voto

BondedDust Points 105234

Ceci est référencé dans la page d'aide référencée par ?'NaN'

"La norme IEC 60559, également connue sous le nom de norme ANSI/IEEE 754 pour la virgule flottante.

http://en.wikipedia.org/wiki/NaN ."

C'est là que l'on trouve cette déclaration concernant ce qui devrait créer un NaN :

 "There are three kinds of operations that can return NaN:[5]
       Operations with a NaN as at least one operand.

Il s'agit probablement d'un problème lié au compilateur C, comme l'indique la note à laquelle vous avez fait référence. C'est ce que dit la documentation GNU C :

http://www.gnu.org/software/libc/manual/html_node/Infinity-and-NaN.html

" NaN, en revanche, infecte tout calcul qui l'implique. À moins que le calcul ne produise le même résultat quelle que soit la valeur réelle qui remplace NaN, le résultat est NaN."

Il semble donc que les gens de GNU-C aient une norme différente à l'esprit lorsqu'ils écrivent leur code. Et la version 2008 de la norme ANSI/IEEE 754 pour la virgule flottante est signalée comme faisant cette suggestion :

http://en.wikipedia.org/wiki/NaN#Function_definition

La norme publiée n'est pas gratuite. Si vous avez des droits d'accès ou de l'argent, vous pouvez donc consulter cette page :

http://ieeexplore.ieee.org/xpl/mostRecentIssue.jsp?punumber=4610933

0 votes

Merci. J'ai décidé d'accepter cette réponse parce que je pense qu'il y a suffisamment de lectures liées qui, comme vous le soulignez, répondent à la décision de conception. Mais la documentation R sur NaN devrait peut-être être modifiée au niveau de la ?NaN page pour mentionner que les opérations impliquant NaN aboutissent toujours à Na ou NaN, sauf en cas d'élévation à 0. Merci.

0 votes

... sauf que la documentation de R pourrait dire "excepté éventuellement lors de l'élévation à zéro, en fonction de la plate-forme" (la réponse ne me permet pas de savoir clairement si NaN^0 est 1 sur tous les systèmes d'exploitation possibles avec tous les compilateurs possibles ...)

1 votes

J'ai ajouté la note de la page d'aide. (Je n'avais certainement pas l'intention de couvrir "tous les compilateurs possibles".) Et je dirais que le comportement actuel du compilateur GNU-C n'est pas en accord avec la "Note".

20voto

eddi Points 17947

La réponse se résume à "pour des raisons historiques".

Il semble que l'IEEE 754 ait introduit deux différentes fonctions de puissance - pow y powr , ce dernier préservant NaN dans le cas du PO et en retournant également les NaN para Inf^0 , 0^0 , 1^Inf mais cette dernière a finalement été abandonnée en tant que expliquée brièvement ici .

D'un point de vue conceptuel, je suis dans la NaN Je pense que les conventions actuelles sont un peu plus faciles à gérer, même si elles n'ont pas beaucoup de sens dans certains cas (par exemple, les conventions de l'Union européenne). sqrt(-1)^0 étant égale à 1 alors que toutes les opérations portent sur des nombres réels n'a que peu de sens, voire aucun).

0 votes

Ce lien est intéressant à lire. J'aurais aimé que R min y max pour ignorer les NaN, mais pour que NaN^1 soit NaN. On ne peut pas toujours obtenir ce que l'on veut.

1 votes

Je crois que la version finale de la norme IEEE754-2008 contient en fait les deux éléments suivants pow y powr ainsi que pown pour élever un flottant arbitraire à une puissance intégrale. pow(qNaN, 0) y pown(qNaN, 0) sont définies comme suit 1 ; powr(qNaN, 0) signale l'exception de l'opération non valide et renvoie donc un qNaN dans le cadre de la gestion des exceptions par défaut du PC.

1 votes

Lecture très intéressante de l'histoire de l'IEEE 754. La préservation de NaN présente un autre avantage (pour min/max ou pour toute autre chose) : NaN peut être apparu dans un calcul précédent qui, dans d'autres circonstances, aurait donné une valeur double utilisable, qui aurait pu être comparée/utilisée/... NaN est alors considéré comme une valeur exceptionnelle, et simplement comme une erreur (pour une raison ou une autre, comme un débordement, un calcul qui a mal tourné). Préserver NaN permet au moins de voir à la fin qu'il y a eu une erreur quelque part, et ne donnera pas silencieusement une réponse incorrecte. La signalisation des NaN est également un moyen de piéger l'erreur lorsqu'elle se produit.

18voto

Martin Mächler Points 977

Oui, je suis en retard, mais en tant que membre du R Core qui a été impliqué dans cette conception, permettez-moi de rappeler ce que j'ai commenté plus haut. La préservation de NaN et la préservation de NA fonctionnent de manière "équivalente" dans R, donc si vous êtes d'accord que NA^0 devrait donner 1, NaN^0 |-> 1 est une conséquence.

En effet (comme d'autres l'ont dit), vous devriez vraiment lire les pages d'aide de R et non celles de C ou de IEEE, pour répondre à de telles questions, et SimonO101 a correctement cité

1 ^ y et y ^ 0 sont 1, toujours

et je suis presque sûr que j'ai été fortement impliqué (si ce n'est l'auteur) dans ce projet. Notez qu'il s'agit de bon Il n'est donc pas mauvais de pouvoir fournir des réponses non NAN, même dans les cas où d'autres langages de programmation agissent différemment. La conséquence d'une telle règle est que davantage de choses fonctionnent automatiquement et correctement ; dans l'autre cas, le programmeur R aurait été incité à faire lui-même plus de casses spéciales.

En d'autres termes, une règle aussi simple que celle décrite ci-dessus (qui renvoie un résultat non NaN dans tous les cas) est une bonne règle, car elle propage la continuité au sens mathématique : lim_x f(x) = f(lim x). Nous avons eu quelques cas où il était clairement avantageux (c'est-à-dire qu'il n'était pas nécessaire d'utiliser des caractères spéciaux, je répète ) d'adhérer à la règle "= 1" ci-dessus, plutôt que de propager NaN. Comme je l'ai dit plus haut, le sqrt(-1)^0 est également un tel exemple, car 1 est le résultat correct dès que l'on passe au plan complexe.

0 votes

Lol, pourquoi quelqu'un accepterait-il cela ? NA^0 devraient donner 1 s'ils pensent NaN^0 ne devrait pas ? NA est un surensemble de NaN . Vous vous êtes trompé dans la direction du if-else.

0 votes

C'est exactement ce qu'a dit l'OP !

0 votes

:) c'est juste - à la fois de vous devriez savoir mieux que cela

5voto

James Points 24725

Voici un raisonnement. A partir de Goldberg :

Dans la norme IEEE 754, les NaN sont souvent représentés par des flottants. l'exposant e_max + 1 et des significateurs non nuls.

Donc NaN est un nombre à virgule flottante, mais avec une signification particulière. L'élévation d'un nombre à la puissance zéro met son exposant à zéro, ce qui fait qu'il n'est plus NaN.

À noter également :

> 1^NaN
[1] 1

Un est un nombre dont l'exposant est déjà nul.

0 votes

Vous prétendez donc qu'ils voulaient éviter d'avoir à traiter des cas particuliers ? Mais les calculs en virgule flottante doivent déjà faire face à un certain nombre de cas particuliers causés par NaN (ainsi que +/- Inf , +/- 0 et nombres dénormalisés) , donc...

1 votes

Et s'il s'avérait que NaN était représenté par exemple par 2, selon votre logique 1+NaN Vous ne pouvez pas tirer de conclusions sur ce qu'un résultat donné pourrait être. devrait être de la façon dont vous choisissez de la représenter.

4voto

supercat Points 25534

D'un point de vue conceptuel, le seul problème avec NaN^0 == 1 est que les valeurs zéro peuvent être obtenues d'au moins quatre manières différentes, mais que le format IEEE utilise la même représentation pour trois d'entre elles. La formule ci-dessus a un sens pour le cas le plus courant (qui est l'un des trois), mais pas pour les autres.

BTW, les quatre cas que je reconnaîtrais seraient les suivants :

  • Un zéro littéral
  • Zéro non signé : différence entre deux nombres indiscernables
  • Infinitésimale positive : Le produit ou le quotient de deux nombres de signe correspondant, qui est trop petit pour être distingué de zéro.
  • Infinitésimal négatif : Le produit ou le quotient de deux nombres de signe opposé, qui est trop petit pour être distingué de zéro.

Certains d'entre eux peuvent être produits par d'autres moyens (par exemple, le zéro littéral pourrait être produit par la somme de deux zéros littéraux ; l'infinitésimal positif par la division d'un très petit nombre par un très grand, etc.)

Si une virgule flottante reconnaissait ce qui précède, elle pourrait utilement considérer qu'élever NaN à un zéro littéral donne un, et l'élever à tout autre type de zéro donne NaN ; une telle règle permettrait de supposer un résultat constant dans de nombreux cas où quelque chose qui pourrait être NaN serait élevé à quelque chose que le compilateur pourrait identifier comme un zéro constant, sans que cette supposition n'altère la sémantique du programme. Sinon, je pense que le problème est que la plupart des codes ne vont pas se préoccuper de savoir si x^0 pourrait serait NaN si x es NaN et il n'y a pas beaucoup d'intérêt à ce que le compilateur ajoute du code pour des conditions dont le code ne se préoccupe pas. Notez que le problème n'est pas seulement le code de calcul des x^0 mais pour tous les calculs basés sur ce qui serait constant si x^0 était.

0 votes

NaN est souvent utilisé pour indiquer que le résultat n'est pas dans le domaine réel, par exemple. sqrt(-1) . Dans votre fonction personnalisée, il pourrait s'agir de quelque chose de beaucoup plus exotique qu'un nombre complexe, qui n'aurait même pas nécessairement l'attribut ^ défini pour lui, auquel cas le "type" de zéro considéré n'a pas d'importance.

0 votes

@eddi : Si la signification sémantique de x^literalZero est défini comme "ignorer x et renvoyer 1", alors le résultat correct de sqrt(-1)^0 doit être égal à 1. On peut se demander si c'est la manière la plus souhaitable de définir l'opérateur d'exponentiation, mais je dirais que les langages devraient éviter de définir des cas particuliers dont le traitement nécessiterait du code supplémentaire. Soit dit en passant, le langage que vous utilisez distingue-t-il les cas où l'opérateur de droite est un entier de ceux où il est à virgule flottante ? Dans certains langages, (-2,0)^2 est égal à 4,0, mais (-2,0)^(2,0) n'est pas valide. Si le zéro est un entier...

0 votes

...alors je ne pense pas que la gestion des NaN de la norme IEEE-754 soit pertinente (puisqu'elle ne mentionne pas l'exponentiation par un nombre entier) et je ne serais pas favorable à ce qu'un langage code le cas zéro comme if (exponent==0) return (isNan(base) ? NaN : 1.0); au lieu de simplement if (exponent==0) return 1; .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X