Est-il prudent de supposer que la virgule flottante est représentée à l’aide des flottants IEEE754 en C?

La virgule flottante correspond à la mise en œuvre définie dans le C. Il n’y a donc aucune garantie.

Notre code doit être portable, nous discutons de l’acceptabilité ou non de l’utilisation des floats IEEE754 dans notre protocole. Pour des raisons de performances, il serait intéressant de ne pas avoir à effectuer de va-et-vient d’un format à un point fixe lors de l’envoi ou de la réception de données.

Bien que je sache qu’il peut y avoir des différences entre les plates-formes et les architectures en ce qui concerne la taille de long ou wchar_t . Mais je n’arrive pas à trouver de détails sur le float et le double .

Ce que j’ai trouvé jusqu’à présent, c’est que l’ordre des octets est peut-être inversé sur les plateformes big endian. Bien qu’il existe des plates-formes sans support de virgule flottante dans lesquelles un code contenant float et double ne serait même pas lié. Sinon, les plates-formes semblent se conformer à la norme IEEE754 simple et double précision.

Alors, est-il prudent de supposer que la virgule flottante est dans IEEE754 lorsqu’elle est disponible?

EDIT: En réponse à un commentaire:

Quelle est votre définition de “sûr”?

Par safe, je veux dire, le motif de bits sur un système signifie la même chose sur l’autre (après la rotation d’octets pour traiter l’endianité).

Pratiquement toutes les architectures utilisées actuellement, autres que les cartes perforées, y compris les architectures intégrées et les architectures de traitement de signaux exotiques, offrent l’un des deux systèmes à virgule flottante suivants:

  • IEEE-754.
  • IEEE-754 sauf pour bla . C’est-à-dire qu’ils implémentent principalement 754, mais à bas prix sur certains des éléments les plus coûteux et / ou difficiles.

Les rabais les plus courants:

  • Flushing denormals à zéro. Cela invalide certains théorèmes parfois utiles (en particulier, le théorème qui peut être représenté exactement par ab si 0 <= a/2 <= b <= a*2 ), mais dans la pratique, cela ne posera généralement pas de problème.
  • Défaut de reconnaître inf et NaN comme spéciaux. Ces architectures ne suivront pas les règles concernant inf et NaN tant FLT_MAX et ne FLT_MAX peut-être pas inf , produisant plutôt des nombres plus grands que FLT_MAX , qui seront généralement reconnus par NaN comme autres architectures.
  • Arrondir correctement la division et la racine carrée. Il est beaucoup plus facile de garantir que le résultat est compris entre 1 et 3 ulps du résultat exact par rapport à 1/2 ul. Un cas particulièrement courant consiste à implémenter la division en tant que multiplication réciproque, ce qui vous fait perdre un bit de précision.
  • Moins ou pas de chiffres de garde. Ceci est un rabais inhabituel, mais signifie que d’autres opérations peuvent avoir un ou deux coups d'arrêt.

BUUUUT ... même ceux à l' exception des architectes blah utilisent encore la représentation des nombres par IEEE-754. Outre les problèmes d'ordre des octets, les bits décrivant un float ou un double sur l'architecture A ont essentiellement la même garantie sur l'architecture B.

Donc tant que vous vous souciez de la représentation des valeurs, tout va bien. Si vous vous souciez de la cohérence des opérations entre plates-formes, vous devrez peut-être effectuer un travail supplémentaire.

EDIT : Comme Chux le mentionne dans les commentaires, une source supplémentaire d’incohérences entre les plates-formes est l’utilisation de la précision étendue, telle que la représentation interne 80 bits du x87. C’est l’opposé d’un pas cher, et (avec un traitement approprié) entièrement conforme à la fois à la norme IEEE-754 et à la norme C, mais cela entraînera également des résultats différents entre les architectures, et même entre les versions du compilateur et le suivi de code apparemment mineur et non apparenté. changements. Cependant: un exécutable x86 / x64 particulier NE produira PAS des résultats différents sur des processeurs différents en raison de la précision étendue.

Il y a une macro à vérifier (depuis C99):

C11 §6.10.8.3 Macros d’entités conditionnelles

__STDC_IEC_559__ La constante entière 1, destinée à indiquer la conformité aux spécifications de l’annexe F (arithmétique en virgule flottante CEI 60559).

IEC 60559 ( ISO / IEC / IEEE 60559 ) est un autre nom pour IEEE-754.

L’annexe F établit ensuite le mappage entre les types C flottants et les types IEEE-754:

Les types C flottants correspondent aux formats CEI 60559 comme suit:

  • Le type float correspond au format simple IEC 60559.
  • Le type double correspond au format double IEC 60559.
  • Le type double long correspond à un format étendu CEI 60559, 357) sinon à un format étendu non CEI 60559, sinon au format double CEI 60559.

Je suggère que vous deviez examiner plus attentivement votre définition de portable.

Je suggérerais également que votre définition de «sûr» est insuffisante. Même si la représentation binary (en tenant compte de l’endianité) est correcte, les opérations sur les variables peuvent se comporter différemment. Après tout, il existe peu d’applications à virgule flottante qui n’impliquent pas d’opérations sur des variables.

Si vous souhaitez prendre en charge toutes les architectures hôtes qui ont déjà été créées, le format de virgule flottante IEEE est insortingnsèquement dangereux. Vous devrez gérer des systèmes prenant en charge différents formats, des systèmes ne prenant pas du tout en virgule flottante, des systèmes pour lesquels les compilateurs disposent de commutateurs permettant de sélectionner des comportements en virgule flottante (certains comportements étant associés à des formats non IEEE), des processeurs dotés de un coprocesseur facultatif (la prise en charge des virgules flottantes dépend donc de l’installation ou non d’une puce supplémentaire, mais les variantes du processeur sont identiques), des systèmes émulant des opérations en virgule flottante dans un logiciel (certains de ces émulateurs sont configurables au moment de l’exécution), et systèmes avec une implémentation buggy ou incomplète de la virgule flottante (basée ou non sur IEEE).

Si vous êtes prêt à vous limiter au matériel informatique post-2000, votre risque est plus faible mais non nul. Pratiquement tous les processeurs de cette génération supportent IEEE sous une forme ou une autre. Cependant, vous devez toujours (comme avec les anciens processeurs) considérer les opérations en virgule flottante que vous souhaitez prendre en charge, ainsi que les compromis que vous êtes prêt à accepter. Différents processeurs (ou émulations logicielles) ont une implémentation de la virgule flottante moins complète que d’autres, et certains sont configurés par défaut pour ne pas prendre en charge certaines fonctionnalités. Il est donc nécessaire de modifier les parameters pour activer certaines fonctionnalités, ce qui peut avoir une incidence sur les performances ou l’exactitude de vos performances. code.

Si vous devez partager des valeurs à virgule flottante entre des applications (qui peuvent se trouver sur différents hôtes avec différentes fonctionnalités, construits avec différents compilateurs, etc.), vous devrez définir un protocole. Ce protocole peut impliquer le format IEEE, mais toutes vos applications devront être capables de gérer la conversion entre le protocole et leurs représentations natives.

Presque toutes les architectures courantes utilisent maintenant IEEE-754, cela n’est pas requirejs par la norme. Il existait jadis d’anciennes architectures non IEE-754, et certaines pouvaient encore l’être.

Si la seule exigence est l’échange de données réseau, mon conseil est le suivant:

  • Si __STDC_IEC_559__ est défini, utilisez uniquement l’ordre du réseau pour les octets et supposez que vous avez la norme IEE-754 pour les valeurs float et double.
  • Si __STDC_IEC_559__ n’est pas défini, utilisez un format d’échange spécial, qui pourrait être IEE-754 – un seul protocole – ou toute autre solution – nécessitant une indication de protocole.

Comme d’autres l’ont mentionné, il existe la macro __STDC_IEC_559__ , mais elle n’est pas très utile car elle n’est définie que par des compilateurs qui implémentent complètement l’annexe correspondante dans la norme C. Il existe des compilateurs qui n’implémentent qu’un sous-ensemble mais qui ont toujours (principalement) une prise en charge de virgule flottante IEEE utilisable.

Si vous ne vous préoccupez que de la représentation binary, vous devez écrire un test de fonctionnalité qui vérifie les modèles de bits de certains nombres flottants. Quelque chose comme:

 #include  #include  typedef union { double d; uint64_t i; } double_bits; int main() { double_bits b; bd = 2.5; if (bi != UINT64_C(0x4004000000000000)) { fprintf(stderr, "Not an IEEE-754 double\n"); return 1; } return 0; } 

Vérifiez quelques nombres avec différents exposants, mantisses et signes, et vous devriez être du côté de la sécurité. Puisque ces tests ne coûtent pas cher, vous pouvez même les exécuter une fois au moment de l’exécution.

Ssortingctement parlant, il n’est pas prudent d’assumer un support en virgule flottante; d’une manière générale, la grande majorité des plateformes le supportera. Les exceptions notables incluent les systèmes VMS (maintenant obsolètes) fonctionnant sur des puces Alpha

Si vous avez le luxe de vérifier l’exécution, considérez la paranoia , un outil de vérification en virgule flottante écrit par William Kahan .

Edit: votre application semble plus concernée par les formats binarys en ce qui concerne le stockage et / ou la sérialisation. Je suggérerais de vous limiter au choix d’une bibliothèque tierce prenant en charge cette fonctionnalité. Vous pourriez faire pire que Google Protocol Buffers .