70 votes

Emuler un "double" en utilisant 2 "float".

J'écris un programme pour un matériel embarqué qui ne supporte que l'arithmétique à virgule flottante 32 bits à simple précision. L'algorithme que j'implémente, cependant, nécessite une addition et une comparaison en double précision 64 bits. J'essaie d'émuler double en utilisant un tuple de deux float s. Donc un double d sera émulé comme un struct contenant le tuple : (float d.hi, float d.low) .

La comparaison devrait être simple en utilisant un ordre lexicographique. L'addition, en revanche, est un peu délicate, car je ne suis pas sûr de la base à utiliser. Devrais-je utiliser FLT_MAX ? Et comment puis-je détecter un portage ?

Comment cela peut-il être fait ?


Editer (Clarté) : J'ai besoin des chiffres significatifs supplémentaires plutôt que de l'étendue supplémentaire.

106voto

njuffa Points 4520

Le double-float est une technique qui utilise des paires de nombres en simple précision pour obtenir une précision presque double de celle de l'arithmétique en simple précision, accompagnée d'une légère réduction de la plage des exposants en simple précision (en raison d'un débordement et d'un sous-écoulement intermédiaires aux extrémités de la plage). Les algorithmes de base ont été développés par T.J. Dekker et William Kahan dans les années 1970. Ci-dessous, j'énumère 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 et devrait donc être utile pour la tâche à accomplir.

https://hal.archives-ouvertes.fr/hal-00021443 Guillaume Da Graça, David Defour Implémentation d'opérateurs float-float sur du matériel graphique, 7ème conférence sur les nombres réels et les ordinateurs, RNC7.

http://andrewthall.org/papers/df64_qf128.pdf Andrew Thall Nombres à virgule flottante à précision étendue pour le calcul par le GPU.

11voto

Nemo Points 32838

Cela ne va pas être simple.

Un flottant (IEEE 754 simple précision) possède 1 bit de signe, 8 bits d'exposant et 23 bits de mantisse (en fait, 24).

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

Vous pouvez utiliser le bit de signe et 8 bits d'exposant d'un de vos flottants, mais comment allez-vous obtenir 3 bits d'exposant supplémentaires et 29 bits de mantisse de l'autre ?

Peut-être que quelqu'un d'autre peut trouver une solution intelligente, 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").

9voto

Mr Fooz Points 21092

Cela dépend un peu des types d'opérations que vous voulez effectuer. Si vous ne vous souciez que des additions et des soustractions, Résumé de Kahan peut être une excellente solution.

7voto

Matthew Slattery Points 21628

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

(Pour l'addition, le principe de base consiste à décomposer 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, à ajouter ou soustraire à la mantisse de l'autre partie en fonction des bits de signe, et éventuellement à renormaliser le résultat en décalant la mantisse et en ajustant l'exposant en conséquence. En cours de route, il y a beaucoup de détails minutieux à prendre en compte, afin d'éviter toute perte de précision inutile, et de traiter les valeurs spéciales telles que les infinis, les NaN et les nombres dénormalisés).

5voto

wallyk Points 33150

Compte tenu de toutes les contraintes de haute précision sur 23 magnitudes, je pense que la méthode la plus fructueuse serait d'implémenter un paquet arithmétique personnalisé.

Une étude rapide montre que Briggs double-double La bibliothèque C++ devrait répondre à vos besoins et même plus. Voir este L'implémentation par défaut est basée sur les éléments suivants double pour réaliser le calcul de 30 chiffres significatifs, mais il est facilement réécrit pour utiliser float pour obtenir 13 ou 14 chiffres significatifs. Cela peut être suffisant pour vos besoins si l'on prend soin de séparer les opérations d'addition avec des valeurs de magnitude similaire, en n'ajoutant les extrêmes ensemble que dans les dernières opérations.

Attention cependant, les commentaires mentionnent la manipulation du registre de contrôle x87. Je n'ai pas vérifié les détails, mais cela pourrait rendre le code trop peu portable pour votre usage.


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

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