dimanche 27 février 2022

Chapitre 95 : Assembleur ARM 32bits : calculs en multiprécision

 

Dans ce chapitre, je me suis lancé dans l’écriture de routines de calcul avec un grand nombre de chiffres. Il existe des librairies pour effectuer ce genre de calcul comme gmp et que j’ai déjà utilisée.

Mais ici, l’intérêt est de comprendre le fonctionnement des routines et la possibilité de les modifier ou d’en écrire des nouvelles plus optimisées ou plus utiles directement en assembleur.

Ces routines posent aussi des problèmes intéressants et la version proposée ici est la dernière après de nombreux essais et évolutions.

Tout d’abord, il faut choisir une structure de représentation de ces grands nombres. J’ai décidé d’écrire une structure qui contient le nombre d’entiers de 32 bits qui composent un nombre, le signe du nombre par un entier de 32 bits puis la table des entiers qui seront appelés des chunks par la suite. Cette table aura un nombre maximum de chunks donnée par la constante NBCHUNKMAXI.

Voici la description de la structure :

/* Définition pour multiEntier */

.struct 0

multi_taille: // nombre de chunk

.struct multi_taille + 4

multi_signe: // signe 0 positif, -1 négatif

.struct multi_signe + 4

multi_chunk: // debut des chunks

.struct multi_chunk + 4 * NBCHUNKMAXI // nombre de chunks maxi

multi_fin:



Ainsi le nombre 4294967297 (soit 0x100000001) est représenté par 2,0,1,1 car il contient 2 chunks, est positif Le premier chunk vaut 1 et le deuxième vaut aussi 1 mais il représente la valeur 1 * 2 puissance 32 soit 4294967296

Le nombre 1 sera représenté par 1,-1,1 soit un chunk de signe négatif et de valeur 1.

Pour simplifier la gestion de la mémoire, tous les nombres utilisés devront être déclarés avant leur utilisation. Les nombres utilisés en interne dans les routines seront déclarés sur la pile.

Vous trouverez les fichiers nécessaires à la compilation et au lien dans le répertoire :

https://github.com/vincentARM/Arm-assembly/tree/master/Chapitre95

Les routines se trouvent dans le fichier utilCalcul.s et un exemple de calcul dans le fichier testCalcul.s. la compilation s’effectue en saisissant make PGM=testcalcul, le résultat se trouvera dans le répertoire build.

Attention : il peut rester des anomalies dans ces routines car j’ai pu oublier des cas de tests. (me signaler éventuellement les cas d’erreurs pour correction)

La première routine est celle qui permet d’initialiser un nombre avant son utilisation : initMultiEntier. Elle attend en paramètre l’adresse d’une zone réservée et le nombre de chunks qui seront initialisés à zéro. Ce nombre alimentera la zone multi_taille, la zone multi_signe sera mise à 0, et une boucle initialisera les chunks à partir de l’adresse multi_chunk.

Nous retrouverons ce type de boucle dans presque toutes les routines puisqu’il faudra traiter tous les chunks d’un nombre.

Pour tester cette sousroutine dans le programme testcalcul, il nous faut avoir une routine d’affichage de ce type de nombre. Celle ci fait appel à une routine de conversion d’un nombre en une chaîne de caractères : convertirMultiVersChaine qui fait appel à d’autres sous routines (voir les commentaires pour les explications).

Ensuite nous trouvons les sousroutines pour initialiser un grand nombre à partir d’un entier, ou à partir d’une chaîne de caractères.

Enfin nous trouvons les routines d’addition de soustraction de multiplication et de division. A partir de ces routines, il est possible de les compléter pour effectuer d’autres calculs (puissance,modulo etc.)

Vous trouverez des exemples d’utilisation des routines principales dans le programme testCalcul.s