mardi 1 septembre 2020

Chapitre 88 : Assembleur ARM 64 bits : affichage des nombres en virgule flottante : algorithme grisu

 

Dans plusieurs chapitres précédents, lors de manipulations de nombres en virgule flottante, j’ai du faire appel à l’instruction printf du langage C pour afficher les résultats.

Cet été j’ai recherché sur internet des algorithmes pour effectuer la conversion directement en langage assembleur mais uniquement en 64 bits. J’ai commencé par trouver un algorithme dragon4 (voir ) mais son adaptation me semblait complexe. Mais ce site aussi renvoyait sur un document pdf (https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf ) qui proposait 3 algorithmes pour convertir les floats.

J’ai donc épluché ce document et commencé par écrire un premier programme pour étudier en détail le premier algorithme proposé : grisu.

Cet algorithme fait appel à une table des puissances de 10 converties en une structure utilisable par l’algorithme. Donc j’ai du écrire un premier programme (genTableDeTableORI64.s) qui convertit toutes les puissances de 10 entre 10E-309 et 10E307 dans le format décrit dans le document ci dessus.

Curieusement, bien que la norme IEEE754 suppose des puissances de 10 au delà de cette plage, le compilateur as refuse les floats avec des puissances inférieure à -309 et supérieure à +307. Ici, j’ai fait un programme simple qui affiche les résultats que j’ai ensuite recopiés dans un fichier à insérer dans le programme grisu64.s.

Dans ce programme, j’ai repris les idées développées par Florian Loitsch : structure des données, calcul du coefficient pour accéder à la puissance 10 de la table, multiplication, et éclatement du résultats en 3 zones pour l’affichage.

Cela m’a permis d’éclaircir certains points, et d’effectuer les tests pour arriver à un résultat satisfaisant. Bon d’accord l’affichage est plutôt brut mais les résultats trouvés sont corrects (mais avec une perte de précision).

Exemple :

Affichage de 0f12345E-10 :

123450000000000005536E-26

Affichage de Pi : 0f314159265358979323E-17 :

31415926535897931160E-19

Affichage de -0.3 :

-29999999999999993976E-20

Pour ce programme, la table des puissance de 10 contient 309 + 307 = 616 postes, ce qui est beaucoup. Mais le document en référence propose un deuxième algorithme grisu2 qui utilise une table avec des puissance de 10 avec un pas de 8, ce qui réduit le nombre de poste à 78 postes.

D’autres part, en 64 bits la multiplication proposée peut être réduite à une seule instruction umulh. Puis l’analyse de l’algorithme fait apparaître qu’il n’ait nécessaire que d’avoir 4 valeurs avec la structure proposée. Donc il est possible de n’utiliser que des registres 64 bits pour gérer ces valeurs sans avoir à les stocker en mémoire.

Le programme grisu2NV2_64.s met en pratique ces idées. De l’entrée de la valeur à convertir contenue dans le registre d0 à l’extraction des chiffres du résultat, il n’y a aucun appel à une sous routine !! tous les calculs sont effectués dans la même routine. Ensuite les affichages en nombre entiers, nombres décimaux et nombre en notation scientifique (xEexposant) sont effectués par une seule sous-routine. Cela allège le programme mais complique la lisibilité !!

Bien sûr la table des puissances de 10 utilisée est différente et elle est plus petite.

Les résultats sont corrects mais je ne garantie pas leur exactitude pour tous les cas. 

Pi :

3.141592653589793
 

affichage décimal :

-0.3

 

Notation scientifique

-1.234e+306

 

Ce programme doit pouvoir être amélioré (par exemple en améliorant l’affichage de certains nombres comme 1E23 ou 1E53 )et encore optimisé !!

Aucun commentaire:

Enregistrer un commentaire