Emuler “double” en utilisant 2 “float” s

J’écris un programme pour un matériel embarqué qui ne supporte que l’arithmétique à virgule flottante simple précision 32 bits. L’algorithme que je suis en train d’implémenter nécessite une addition et une comparaison en double précision sur 64 bits. J’essaie d’imiter le double type de données en utilisant un tuple de deux float s. Donc, un double d sera émulé comme une struct contenant le tuple: (float d.hi, float d.low) .

La comparaison doit être simple en utilisant un ordre lexicographique. L’ajout est cependant un peu délicat car je ne suis pas sûr de la base à utiliser. Devrait-il s’agir de FLT_MAX ? Et comment puis-je détecter un report?

Comment cela peut-il être fait?


Edit (Clarity): J’ai besoin des chiffres supplémentaires significatifs plutôt que de la plage supplémentaire.

double-float est une technique qui utilise des paires de nombres à simple précision pour obtenir près de deux fois plus de précision que l’arithmétique à simple précision, accompagnée d’une légère réduction de la gamme d’exposants à précision unique . Les algorithmes de base ont été développés par TJ Dekker et William Kahan dans les années 1970. Ci-dessous, je listerai deux articles assez récents qui montrent comment ces techniques peuvent être adaptées aux GPU. Cependant, une grande partie du matériel couvert dans ces articles est applicable indépendamment de la plate-forme.

http://hal.archives-ouvertes.fr/docs/00/06/33/56/PDF/float-float.pdf Guillaume Da Graça, David Defour Mise en place d’opérateurs de flotteurs sur matériel graphique, 7ème conférence sur les nombres réels et ordinateurs, RNC7.

http://andrewthall.org/papers/df64_qf128.pdf Andrew Thall Numéros à virgule flottante de précision étendue pour le calcul du GPU.

Cela ne va pas être simple.

Un flottant (IEEE 754 simple précision) a 1 bit de signe, 8 bits d’exposant et 23 bits de mantisse (enfin, 24 bits).

Un double (double précision IEEE 754) a 1 bit de signe, 11 bits d’exposant et 52 bits de mantisse (effectivement 53).

Vous pouvez utiliser le bit de signe et 8 bits d’exposant d’un de vos flotteurs, mais comment allez-vous obtenir 3 bits d’exposant et 29 bits de mantisse de l’autre?

Peut-être que quelqu’un d’autre peut trouver quelque chose d’intelligent, mais ma réponse est “c’est impossible”. (Ou du moins, “pas plus facile que d’utiliser une structure 64 bits et d’implémenter vos propres opérations”)

Cela dépend un peu des types d’opérations que vous souhaitez effectuer. Si vous ne vous souciez que des ajouts et des soustractions, Kahan Summation peut être une excellente solution.

Si vous avez besoin à la fois de précision et d’un large éventail, vous aurez besoin d’une implémentation logicielle de virgule flottante à double précision, telle que SoftFloat .

(En outre, le principe de base est de diviser la représentation (par exemple 64 bits) de chaque valeur en ses trois parties constitutives – signe, exposant et mantisse, puis décaler la mantisse d’une partie en fonction de la différence entre les exposants. soustraire de la mantisse de l’autre partie sur la base des bits de signe, et éventuellement renormaliser le résultat en décalant la mantisse et en ajustant l’exposant de manière correspondante. de précision et traitent des valeurs spéciales telles que les infinis, les NaN et les nombres dénormalisés.)

Ce n’est pas pratique. Si c’était le cas, chaque processeur 32 ou 32 bits intégré (ou compilateur) émulerait en faisant cela. En l’état actuel des choses, personne ne le fait. La plupart d’entre eux ne font que substituer le flottant au double.

Si vous avez besoin de la précision et non de la plage dynamic, le mieux serait d’utiliser un point fixe. Si le compilateur prend en charge 64 bits, ce sera également plus facile.

Compte tenu de toutes les contraintes pour une précision élevée sur 23 grandeurs, je pense que la méthode la plus fructueuse consisterait à implémenter un package arithmétique personnalisé.

Un rapide sondage montre que la bibliothèque C ++ de DoubleDouble de Briggs devrait répondre à vos besoins, puis à d’autres. Voir ceci . [*] L’implémentation par défaut est basée sur le double pour obtenir un calcul significatif de 30 chiffres, mais elle est facilement réécrite pour utiliser float pour atteindre 13 ou 14 chiffres significatifs. Cela peut suffire à vos besoins si l’on prend soin de séparer les opérations d’addition avec des valeurs d’amplitude similaires, en ajoutant uniquement des valeurs extrêmes lors des dernières opérations.

Attention cependant, les commentaires mentionnent de jouer avec le registre de contrôle x87. Je n’ai pas vérifié les détails, mais cela pourrait rendre le code non portable pour votre usage.


[*] La source C ++ est liée par cet article, mais seul le tar gzippé n’était pas un lien mort.

Une autre solution logicielle pouvant être utilisée: GNU MPFR
Il prend en charge de nombreux autres cas spéciaux et permet une précision arbitraire (mieux que le double de 64 bits) que vous auriez à prendre autrement en charge.

Ceci est similaire à l’ arithmétique double double utilisée par de nombreux compilateurs pour long double sur certaines machines qui ne supportent que le double calcul matériel. Il est également utilisé comme float-float sur les anciens GPU NVIDIA sans double support. De cette façon, le calcul sera beaucoup plus rapide que celui d’une bibliothèque logicielle à virgule flottante.

Cependant, dans la plupart des microcontrôleurs, il n’y a pas de support matériel pour les float , ils ne sont donc implémentés que dans les logiciels. À cause de cela, l’utilisation de float-float n’augmentera peut float-float être pas les performances et introduira un peu de mémoire pour économiser les octets supplémentaires de l’exposant.

Si vous avez vraiment besoin de la longue mantisse, essayez d’utiliser une bibliothèque de points flottants personnalisée. Vous pouvez choisir ce qui est suffisant pour vous, par exemple changer la bibliothèque pour adapter un nouveau type flottant de 48 bits si seulement 40 bits de mantisse et 7 bits d’exposant sont nécessaires. Pas besoin de passer du temps à calculer / stocker le 16 bits inutile. Mais cette bibliothèque devrait être très efficace car les bibliothèques du compilateur ont souvent une optimisation au niveau de l’assemblage pour leur propre type de flottant.