NaN - NaN

En informatique , NaN ( / n æ n / ), signifiant Not a Number , est un membre d'un type de données numérique qui peut être interprété comme une valeur indéfinie ou non représentable, en particulier en arithmétique à virgule flottante . L'utilisation systématique des NaN a été introduite par la norme à virgule flottante IEEE 754 en 1985, ainsi que la représentation d'autres quantités non finies telles que les infinis .

En mathématiques , zéro divisé par zéro n'est pas défini comme un nombre réel et est donc représenté par NaN dans les systèmes informatiques. La racine carrée d'un nombre négatif n'est pas un nombre réel et est donc également représentée par NaN dans les systèmes informatiques conformes. Les NaN peuvent également être utilisés pour représenter les valeurs manquantes dans les calculs.

Deux types distincts de NaN sont fournis, appelés NaN silencieux et NaN de signalisation . Les NaN silencieux sont utilisés pour propager les erreurs résultant d'opérations ou de valeurs invalides. Les NaN de signalisation peuvent prendre en charge des fonctionnalités avancées telles que le mélange de calculs numériques et symboliques ou d'autres extensions de l'arithmétique de base à virgule flottante.

Point flottant

Dans les calculs à virgule flottante, NaN n'est pas la même chose que infinity , bien que les deux soient généralement traités comme des cas particuliers dans les représentations à virgule flottante de nombres réels ainsi que dans les opérations à virgule flottante. Une opération invalide n'est pas non plus la même chose qu'un dépassement arithmétique (qui pourrait renvoyer un infini) ou un dépassement arithmétique (qui renverrait le plus petit nombre normal , un nombre dénormal ou zéro ).

Les NaN IEEE 754 sont codés avec le champ exposant rempli de uns (comme des valeurs infinies) et d'un nombre non nul dans le champ significand (pour les distinguer des valeurs infinies); cela permet la définition de plusieurs valeurs NaN distinctes, en fonction des bits définis dans le champ de mantisse, mais aussi de la valeur du bit de signe de tête (mais les applications ne sont pas tenues de fournir une sémantique distincte pour ces valeurs NaN distinctes).

Par exemple, un NaN IEEE 754 simple précision (32 bits) au niveau du bit serait

s111 1111 1xxx xxxx xxxx xxxx xxxx xxxx

s est le signe (le plus souvent ignoré dans les applications) et la séquence x représente un nombre non nul (la valeur zéro code des infinis). Le bit de poids fort de x est utilisé pour déterminer le type de NaN : "quiet NaN" ou "signaling NaN". Les bits restants encodent une charge utile (le plus souvent ignorée dans les applications).

Les opérations à virgule flottante autres que les comparaisons ordonnées propagent normalement un NaN silencieux ( qNaN ). La plupart des opérations à virgule flottante sur un NaN de signalisation ( sNaN ) signalent l'exception d'opération invalide ; l'action d'exception par défaut est alors la même que pour les opérandes qNaN et ils produisent un qNaN s'ils produisent un résultat à virgule flottante.

La propagation de NaN silencieux par des opérations arithmétiques permet de détecter des erreurs à la fin d'une séquence d'opérations sans tests approfondis pendant les étapes intermédiaires. Par exemple, si l'on commence par un NaN et que l'on ajoute 1 cinq fois de suite, chaque addition donne un NaN, mais il n'est pas nécessaire de vérifier chaque calcul car on peut juste constater que le résultat final est NaN. Cependant, selon la langue et la fonction, les NaN peuvent être retirés silencieusement d'une chaîne de calculs où un calcul de la chaîne donnerait un résultat constant pour toutes les autres valeurs à virgule flottante. Par exemple, le calcul x 0 peut produire le résultat 1, même lorsque x est NaN, donc vérifier uniquement le résultat final masquerait le fait qu'un calcul avant le x 0 a donné un NaN. En général, donc, un test ultérieur pour un indicateur invalide défini est nécessaire pour détecter tous les cas où des NaN sont introduits (voir la définition de fonction ci-dessous pour plus de détails).

Dans la section 6.2 de l'ancienne norme IEEE 754-2008 , il existe deux fonctions anormales (les fonctions maxNumet minNum, qui renvoient le maximum de deux opérandes censés être des nombres) qui favorisent les nombres - si un seul des opérandes est un NaN alors la valeur de l'autre opérande est renvoyée. La révision IEEE 754-2019 a remplacé ces fonctions car elles ne sont pas associatives (quand une signalisation NaN apparaît dans un opérande).

Comparaison avec NaN

Une comparaison avec un NaN renvoie toujours un résultat non ordonné, même lors de la comparaison avec lui-même. Les prédicats de comparaison sont soit de signalisation, soit de non-signalisation sur des opérandes NaN silencieux ; les versions de signalisation signalent l'exception d'opération invalide pour de telles comparaisons. Les prédicats d'égalité et d'inégalité sont sans signalisation, donc x  =  x renvoyant false peut être utilisé pour tester si x est un NaN silencieux. Les autres prédicats de comparaison standard signalent tous s'ils reçoivent un opérande NaN. La norme fournit également des versions sans signalisation de ces autres prédicats. Le prédicat détermine si une valeur est un NaN et ne signale jamais une exception, même si x est un NaN de signalisation. isNaN(x)

Comparaison entre NaN et toute valeur à virgule flottante x (y compris NaN et ±∞)
Comparaison NaN x NaN x NaN > x NaN < x NaN = x NaN x
Résultat Faux Faux Faux Faux Faux Vrai

Opérations générant NaN

Il existe trois types d'opérations qui peuvent renvoyer NaN :

  • La plupart des opérations avec au moins un opérande NaN.
  • Formes indéterminées :
    • Les divisions (±0) / (±0) et (±∞) / (±∞) .
    • Les multiplications (±0) × (±∞) et (±∞) × (±0) .
    • Reste x  % y lorsque x est un infini ou y est zéro.
    • Les additions (+∞) + (−∞) , (−∞) + (+∞) et les soustractions équivalentes (+∞) − (+∞) et (−∞) − (−∞) .
    • La norme a des fonctions alternatives pour les pouvoirs :
      • La norme powfonction et l'exposant entier pownfonction définie 0 0 , 1 et 0 comme 1 .
      • La powrfonction définit les trois formes indéterminées comme des opérations invalides et renvoie donc NaN.
  • Opérations réelles avec des résultats complexes , par exemple :

Les NaN peuvent également être explicitement attribués à des variables, généralement en tant que représentation des valeurs manquantes. Avant la norme IEEE, les programmeurs utilisaient souvent une valeur spéciale (telle que -99999999) pour représenter des valeurs indéfinies ou manquantes, mais il n'y avait aucune garantie qu'elles seraient traitées de manière cohérente ou correcte.

Les NaN ne sont pas nécessairement générés dans tous les cas ci-dessus. Si une opération peut produire une condition d'exception et que les interruptions ne sont pas masquées, l'opération provoquera une interruption à la place. Si un opérande est un NaN silencieux et qu'il n'y a pas non plus d'opérande NaN de signalisation, alors il n'y a pas de condition d'exception et le résultat est un NaN silencieux. Les affectations explicites ne provoqueront pas d'exception même pour les NaN de signalisation.

Silencieux NaN

Les NaN silencieux, ou qNaN, ne déclenchent aucune exception supplémentaire car ils se propagent dans la plupart des opérations. Les exceptions sont lorsque le NaN ne peut pas simplement être transmis inchangé à la sortie, comme dans les conversions de format ou certaines opérations de comparaison.

Signalisation NaN

Les NaN de signalisation, ou sNaNs, sont des formes spéciales d'un NaN qui, lorsqu'elles sont consommées par la plupart des opérations, devraient lever l'exception d'opération invalide puis, le cas échéant, être « silencieuses » dans un qNaN qui peut ensuite se propager. Ils ont été introduits dans IEEE 754 . Il y a eu plusieurs idées sur la façon dont ceux-ci pourraient être utilisés:

  • Remplir la mémoire non initialisée avec des NaN de signalisation produirait l'exception d'opération invalide si les données sont utilisées avant d'être initialisées
  • Utilisation d'un sNaN comme espace réservé pour un objet plus compliqué , tel que :

Lorsqu'il est rencontré, un gestionnaire d'interruption peut décoder le sNaN et renvoyer un index au résultat calculé. En pratique, cette approche se heurte à de nombreuses complications. Le traitement du bit de signe de NaNs pour certaines opérations simples (telles que la valeur absolue ) est différent de celui des opérations arithmétiques. Les pièges ne sont pas exigés par la norme. Il existe d'autres approches pour ce genre de problème qui seraient plus portables.

Opérations de charge utile

IEEE 754-2019 recommande la mise en œuvre des opérations getPayload , setPayload et setPayloadSignaling , en standardisant l'accès aux charges utiles pour rationaliser l'utilisation des applications. Selon le document de référence IEEE 754-2019, cette recommandation doit être interprétée comme « requise pour les nouvelles implémentations, sous réserve de compatibilité descendante ».

Définition de la fonction

Il existe des divergences d'opinion sur la définition appropriée du résultat d'une fonction numérique qui reçoit un NaN silencieux en entrée. Une vue est que le NaN devrait se propager à la sortie de la fonction dans tous les cas pour propager l'indication d'une erreur. Un autre point de vue, et celui adopté par les normes ISO C99 et IEEE 754-2008 en général, est que si la fonction a plusieurs arguments et que la sortie est uniquement déterminée par toutes les entrées non NaN (y compris l'infini), alors cette valeur devrait être le résultat. Ainsi par exemple la valeur renvoyée par hypot(±∞, qNaN)et hypot(qNaN, ±∞)est +∞.

Le problème est particulièrement aigu pour la fonction d' exponentiation = x y . Les expressions 0 0 , 0 et 1 sont considérées comme des formes indéterminées lorsqu'elles apparaissent comme des limites (tout comme ∞ × 0), et la question de savoir si la puissance zéro à zéro doit être définie comme 1 a divisé les opinions. pow(x, y)

Si la sortie est considérée comme indéfinie lorsqu'un paramètre est indéfini, alors pow(1, qNaN)devrait produire un qNaN. Cependant, les bibliothèques mathématiques ont généralement renvoyé 1 pour tout nombre réel y , et même lorsque y est un infini . De même, ils produisent 1 pour même lorsque x est 0 ou un infini. La justification du retour de la valeur 1 pour les formes indéterminées était que la valeur des fonctions aux points singuliers peut être considérée comme une valeur particulière si cette valeur est dans la limite la valeur pour tout sauf une petite partie d'une boule autour de la valeur limite des paramètres. La version 2008 de la norme IEEE 754 indique cela et devrait tous les deux renvoyer 1 car ils renvoient 1 tout ce qui est utilisé au lieu de NaN silencieux. De plus, ISO C99, et plus tard IEEE 754-2008, ont choisi de spécifier = 1 au lieu de qNaN ; la raison de ce choix est donnée dans la logique C : "En général, C99 évite un résultat NaN où une valeur numérique est utile. ... Le résultat de est +∞, car toutes les grandes valeurs à virgule flottante positives sont des entiers pairs." pow(1, y) pow(x, 0)pow(1, qNaN)pow(qNaN, 0)pow(−1, ±∞)pow(−2, ∞)

Pour satisfaire ceux qui souhaitent une interprétation plus stricte de la façon dont la fonction puissance doit agir, la norme 2008 définit deux fonctions puissance supplémentaires : , où l'exposant doit être un entier, et , qui renvoie un NaN chaque fois qu'un paramètre est un NaN ou que l'exponentiation serait donner une forme indéterminée . pown(x, n)powr(x, y)

Entier NaN

La plupart des formats d' entiers de taille fixe ne peuvent pas indiquer explicitement des données non valides. Dans un tel cas, lors de la conversion de NaN en un type entier, la norme IEEE 754 exige qu'une exception d' opération invalide soit signalée. Par exemple, en Java , de telles opérations lancent des instances de java.lang.ArithmeticException. En C , ils conduisent à un comportement indéfini , mais si l'annexe F est prise en charge, l'opération génère une exception à virgule flottante « invalide » (comme requis par la norme IEEE) et une valeur non spécifiée.

Le Math::BigIntpackage de Perl utilise "NaN" pour le résultat des chaînes qui ne représentent pas des entiers valides.

> perl -mMath::BigInt -e "print Math::BigInt->new('foo')"
NaN

Affichage

Différents systèmes d'exploitation et langages de programmation peuvent avoir différentes représentations sous forme de chaîne de NaN.

nan (C, C++ output)
NaN (ECMAScript, Rust)
NaN% 
NAN (Rust, C, C++ source code)
NaNQ (IBM XL and AIX: Fortran, C++ proposal n2290)
NaNS (ditto)
qNaN
sNaN
1.#SNAN (Excel)
1.#QNAN (Excel)
-1.#IND (Excel)
+nan.0 (Scheme)

Étant donné que, dans la pratique, les NaN codés ont un signe, un bit de silence/de signalisation et des « informations de diagnostic » facultatives (parfois appelées charge utile ), ceux-ci seront parfois également trouvés dans les représentations sous forme de chaîne de NaN. Quelques exemples sont:

  • Pour les langages C et C++, le bit de signe est toujours affiché par les fonctions de bibliothèque standard (par exemple -nan) lorsqu'elles sont présentes. Il n'y a pas d'affichage standard de la charge utile ni de l'état de signalisation, mais une valeur NaN silencieuse d'une charge utile spécifique peut être construite en fournissant la chaîne à une fonction d'analyse numérique (par exemple ) ou en fournissant la chaîne de séquence de caractères à ( ou pour sNaN), tous deux interprétés d'une manière définie par l'implémentation. nan(char-sequence)strtodnan()nans()
    • GCC et LLVM fournissent des implémentations intégrées de nan()et nans(). Ils analysent la séquence de caractères comme un entier strtoull(ou un équivalent de taille différente) avec sa détection de bases entières.
    • Le float-parser de la bibliothèque GNU C utilise la chaîne de séquence de caractères "d'une manière non spécifiée". En pratique, cette analyse a été équivalente à celle de GCC/LLVM pour jusqu'à 64 bits de charge utile.
    • Newlib n'implémente pas l' nan()analyse, mais strtod()accepte un format hexadécimal sans préfixe.
    • musl n'implémente aucune analyse de charge utile.

Toutes les langues n'admettent pas l'existence de plusieurs NaN. Par exemple, ECMAScript n'utilise qu'une seule valeur NaN.

Codage

Dans les formats de stockage à virgule flottante conformes à la norme IEEE 754 , les NaN sont identifiés par des modèles de bits spécifiques et prédéfinis uniques aux NaN. Le bit de signe n'a pas d'importance. Les NaN au format binaire sont représentés avec le champ exponentiel rempli de uns (comme les valeurs infinies) et d'un nombre non nul dans le champ significand (pour les distinguer des valeurs infinies). La norme IEEE 754 originale de 1985 ( IEEE 754-1985 ) ne décrivait que les formats binaires à virgule flottante et ne précisait pas comment l'état de signalisation/calme devait être étiqueté. En pratique, le bit le plus significatif du champ de mantisse déterminait si un NaN signalait ou était silencieux. Deux implémentations différentes, avec des significations inversées, en ont résulté :

  • la plupart des processeurs (y compris ceux du Intel et AMD de x86 famille, la famille Motorola 68000 , l' AIM PowerPC famille, ARM famille, le Sun SPARC famille, et le cas échéant de nouveaux MIPS processeurs) définissent le bit de signalisation / quiet non nulle si le NaN est calme, et à zéro si le NaN est en signalisation. Ainsi, sur ces processeurs, le bit représente un is_quietdrapeau ;
  • dans les NaN générés par le PA-RISC et les anciens processeurs MIPS, le bit de signalisation/calme est nul si le NaN est calme, et non nul si le NaN signale. Ainsi, sur ces processeurs, le bit représente un is_signalingdrapeau.

Le premier choix a été préféré car il permet à l'implémentation de calmer un NaN de signalisation en réglant simplement le bit de signalisation/calme à 1. L'inverse n'est pas possible avec le dernier choix car le réglage du bit de signalisation/calme à 0 pourrait donner un infini.

Les révisions 2008 et 2019 de la norme IEEE 754 font des exigences formelles et des recommandations pour l'encodage de la signalisation/état silencieux.

  • Pour les formats d'échange binaires, le bit le plus significatif du champ significand est exclusivement utilisé pour faire la distinction entre les NaN silencieux et les NaN de signalisation. De plus, ce devrait être un is_quietdrapeau. C'est-à-dire que ce bit est différent de zéro si le NaN est silencieux, et zéro si le NaN est en train de signaler.
  • Pour les formats d'échange décimaux, qu'ils soient codés en binaire ou en décimal, un NaN est identifié en ayant les cinq premiers bits du champ de combinaison après le bit de signe mis à un. Le sixième bit du champ est le is_signalingdrapeau. C'est-à-dire que ce bit est à zéro si le NaN est silencieux, et différent de zéro si le NaN est en train de signaler.

Pour la conformité IEEE 754-2008, la signification du bit de signalisation/de silence dans les processeurs MIPS récents est désormais configurable via le champ NAN2008 du registre FCSR. Cette prise en charge est facultative dans la version 3 de MIPS et requise dans la version 5.

L'état/la valeur des bits restants du champ de mantisse ne sont pas définis par la norme. Cette valeur est appelée la « charge utile » du NaN. Si une opération a une seule entrée NaN et la propage à la sortie, la charge utile du résultat NaN doit être celle de l'entrée NaN (ce n'est pas toujours possible pour les formats binaires lorsque la signalisation/état calme est codé par un is_signalingdrapeau, comme expliqué ci-dessus ). S'il y a plusieurs entrées NaN, la charge utile du résultat NaN doit provenir de l'un des NaN d'entrée ; la norme ne précise pas laquelle.

Les références

Normes

Liens externes