Comment convertir la signalisation NaN en NaN silencieux?

Je veux convertir NaN de signalisation en NaN silencieux en C. Quelqu’un pourrait-il suggérer une méthode?

Merci.

Je suppose que je vais développer mon commentaire et fournir une solution.

La sNaN ici dans la possibilité de lire / comparer le sNaN sans déclencher une exception. Après tout, on appelle cela “signalisation” pour une raison. Wikipedia dit que même les opérations de comparaison sur sNaN déclencheront une exception.

Donc, une utilisation directe de number != number ou isnan(value) ne fonctionne probablement pas car elle appelle des comparaisons et déclenchera une exception matérielle. (Je ne suis pas tout à fait sûr de savoir comment isnan(value) est implémenté.)

EDIT: Correction, on dirait que isnan() ne déclenchera jamais d’exception, même sur un NaN signalisation, ce qui rend inutile le rest de cette réponse.

Le prédicat isNaN (x) détermine si une valeur est un NaN et ne signale jamais une exception, même si x est un NaN de signalisation.

Cela signifie que cela peut être fait de la manière suggérée par Chrisoph dans les commentaires:

 if(isnan(value)) value = NAN; 

Voici ma réponse originale qui n’utilise pas isnan(value) :

Donc, la seule façon dont je peux penser à faire cela est d’aller dans la voie du bitwise.

En supposant que float correspond à la norme simple standard IEEE et int un entier de 32 bits, voici une solution: (Notez que je n’ai pas testé cela.)

 union{ int i; float f; } val; val.f = // Read the value here. // If NaN, force it to a quiet NaN. if ((val.i & 0x7f800000) == 0x7f800000){ val.i |= 0x00400000; } 

Notez que cette approche n’est pas complètement compatible C et invoquera un comportement défini par l’implémentation. Notez également que cette approche n’est pas particulièrement efficace en raison de la nécessité de déplacer des données entre les unités FP et entières.

Voici comment cela fonctionne:

  1. L’union sert évidemment à obtenir les bits du float dans un int .
  2. Tous les NaNs auront les bits dans l’ensemble 0x7f80000 . Le test if-statement vérifiera si tous ces bits sont définis.
  3. i |= 0x00400000; force le NaN à un NaN silencieux. Le bit 22 détermine si le NaN est silencieux ou silencieux. Le forcer à 1 en fera un NaN silencieux.

EDIT 2: Si vous ne pouvez pas utiliser les unions, voici quelques autres approches (chacune ayant ses propres inconvénients):

Méthode 1:

 float f = // Read the value here. int i = *(int*)&f; if ((i & 0x7f800000) == 0x7f800000){ i |= 0x00400000; } f = *(float*)&i; 

Inconvénient: il ne respecte pas le crénelage ssortingct, mais fonctionnera probablement encore.

Méthode 2:

 char buf[sizeof(float)]; float f = // Read the value here. *(float*)&buf = f; int i = *(int*)&buf; if ((i & 0x7f800000) == 0x7f800000){ i |= 0x00400000; } *(int*)&buf = i; f = *(float*)&buf; 

La même idée fonctionne avec memcpy() .

Inconvénient: si l’alignement est important, vous devez vous assurer que buf est aligné.

Méthode 3: implémentez votre propre isnan() :

Voir cette question: Où est le code source pour isnan?

Dans les commentaires, vous indiquez ce que vous voulez réellement faire:

Avant d’effectuer toute autre opération, je voudrais vérifier NaN, c’est-à-dire numéro! = nombre, mais cela ne fonctionnera pas pour la signalisation de NaN.

C’est à cela que isnan() macro isnan() C99: pas besoin de number != number . La norme C elle-même ne spécifie pas vraiment la sémantique de la signalisation de NaN – tout ce qu’elle dit est

un NaN de signalisation lève généralement une exception de virgule flottante lorsqu’il se produit comme un opérande arithmétique

dans la section 5.2.4.2.2 §3 et

Cette spécification ne définit pas le comportement des NaN de signalisation.

à l’annexe F, section F.2.1 §1.

Cependant, selon Wikipedia , IEEE 754 spécifie un prédicat isNaN () qui ne déclenche pas d’exception, même lorsqu’il est utilisé avec la signalisation NaN, et isnan() doit se comporter en conséquence sur les implémentations fournissant une sémantique à virgule flottante IEEE.