[Arithmétique] - [Affichage] - [Addition] - [Soustraction] - [Multiplication] - [Division]

.:: Rubrique Arithmétique >> Addition ::.

Maintenant passons aux choses sérieuses... l'addition ! vous êtes prêt? c'est parti
Etudions d'abord la méthode de résolution d'une addition qu'on apprend en primaire: un petit exemple pour commencer? oui mais en héxadécimal:

1 | 1 | 1 |  |  |
|  |  | E | 5 | h
+ | F | F | 4 | 3 | h
1 | 0 | 0 | 2 | 8 | h

|=> 0xE5+0xFF43=0x10028

ça parait tout simple comme ça? et bien on va voir... il suffit de traduire cet algorithme en assembleur:

Déjà on définit nos deux nombres _NOMBRE1 et _NOMBRE2:
_NOMBRE1 = 0xE5
_NOMBRE2 = 0xFF43

On considère pour simplifier les choses que _NOMBRE2 est le nombre le plus grand.

De plus, il va falloir enregistrer le résultat dans une variable on va choisir la variable _NOMBRE2 car c'est celle qui nécessite le plus de mémoire. Le résultat va donc écraser la valeur initiale de _NOMBRE2 et pour ne pas avoir de problème de conflit (car le résultat sera d'au maximum un quartet plus long que _NOMBRE2) on alloue à _NOMBRE2 un octet suplémentaire.

Mais que se PASTIS? je RICARD KRONENBOURG LABEL...

Ce qui nous donne en assembleur:

Instructions x86 | X

    	_NOMBRE1:

    		db 0x01		;Longueur du nombre1 en octet (LONG)
    		db 0xE5		;Le nombre1 (DATA)

    	_NOMBRE2:

    		db 0x02		;Longueur du nombre2 en octet (LONG)
    		db 0x43, 0xFF 	;Le nombre2 (DATA)
    		db 0x00		;L'octet suplémentaire

Maintenant passons a l'algorithme:

|- * On initialise p à 0 (ce sera notre compteur);
|- * On initialise r à 0 (ce sera notre retenu);
|- * On boucle tant que p < min(_NBR1.LONG, _NBR2.LONG)
____|- * s = ((BYTE)_NBR1.DATA[p]) + ((BYTE)_NBR2.DATA[p]) + r;
____|- * r = octet de poids fort de s;
____|- * On incrémente p;
|- * On ajuste la somme si _NBR1.LONG != _NBR2.LONG;
| |- * On ajoute le reste final;

Ce qui donne... traduit en asm:

    	_ADDITION:

    		mov di, _NOMBRE1 	;on pointe avec di sur l'offset de _NOMBRE1
    		mov ch, [ds:di] 	;on récupère la longueur du nombre le plus court qui va nous servir de compteur
    		mov si, _NOMBRE2 	;on pointe avec si sur l'offset de _NOMBRE2
    		mov cl, [ds:si] 	;on récupère la longueur du nombre le plus long qui va nous servir de compteur
    		xor dx, dx 		;registre qui nous servira pour stocker la retenue.
    		xor bx, bx

    	_BOUCLE_ADD:

    		inc di
    		inc si
    		xor ax, ax

    		test ch, ch 		;on teste si ch == 0
    		je _SUITE_ADD 		;si oui on saute

    		dec ch
    		mov al, [ds:di] 	;valeur d'un octet de _NOMBRE1

    	_SUITE_ADD:

    		mov bl, [ds:si] 	;valeur d'un octet de _NOMBRE2
    		add ax, bx
    		add ax, dx 		;on additionne ax et la retenue
    		mov dl, ah 		;on récupère la retenue
    		mov [ds:si], al 	;on sauve la nouvelle valeur de al

    		dec cl
    		test cl, cl 		;on teste si cl != 0
    		jne _BOUCLE_ADD 	;si oui on saute

    		test dl, dl 		;on teste si dl != 0
    		jne _RETENUE_ADD 	;si oui on saute

    		ret 			;si non on retourne au programme principal

    	_RETENUE_ADD:

    		inc si
    		mov [ds:si], dl 	;on sauve la retenue dl

    		mov si, _NOMBRE2 	;on pointe avec si sur l'offset de _NOMBRE2
    		mov cl, [ds:si] 	;on récupère la longueur du nombre le plus long qui va nous servir de compteur
    		inc cl
    		mov [ds:si], cl 	;on sauve la nouvelle longueur de _NOMBRE2

    		ret

Et maintenant un petit test pour vérifier: (je n'ai pas pris les mêmes nombres que l'exemple pour vous montrer que ça marche très bien pour des grands nombres)

_NOMBRE1 = 0123456789ABCDEF (16 chiffres)
et
_NOMBRE2 = 0FEDCBA9876543210FEDCBA987654321 (32 chiffres)

Amusez-vous à calculer ça avec la calculette de WINDOWS... on peut pas.

Le compte est bon !!!!

Et voilà c'est terminé pour l'addition... demain, la multiplication ?... non?

Voici les différentes rubriques:

- Instructions des x86.

- Arithmétique.
  - Affichage.
  - Addition.
  - Soustraction.
  - Multiplication.
  - Division.

Daemonium Albus,
blaizard@caramail.com