Bonjour,
je m'interroge sur la manière dont le processeur effectue des calculs sur des "long" (flottants ?) representés sur 64 bits (long int) alors qu'il me semble que la taille des registres est de 32 bits.
Bonjour,
je m'interroge sur la manière dont le processeur effectue des calculs sur des "long" (flottants ?) representés sur 64 bits (long int) alors qu'il me semble que la taille des registres est de 32 bits.
Bonjour,
Cela se passe exactement comme toi, tu le ferais sur papier : en plusieurs fois. En fait, c'est ton compilateur qui va générer une courte séquence d'instructions (donc un mini-programme) pour y parvenir.
Pour simplifier au maximum, tu peux considérer que le micro-processeur manipule chaque mot de 32 bits comme s'il s'agissait d'un seul chiffre, travaillant ainsi en « base 4294967295 ». Lorsqu'il fait une addition, la somme de deux nombres 32 bits tient au maximum sur 33 bits. Le bit excédentaire peut alors simplement être retenu dans le bit C (Carry) des flags du micro-processeur et être directement exploitée par d'autres instructions.
Dans le cas d'une multiplication, le résultat d'un produits de deux nombres 32 bits tient sur 64 bits, au maximum. Ton micro-processeur utilise 2 registres pour sauver le résultat, par exemple EDX et EAX, sur x86. Tu peux alors « poser EAX » et « retenir EDX » comme tu le ferais sur papier avec une multiplication ordinaire en décimal.
Ça veut dire que c'est surtout une question algorithmique. Je te conseille de jeter un œil à l'assembleur si la façon dont ces choses sont résolues t'intéresse. Tu peux également lire cette discussion.
Pas en utilisant les instructions d'addition de int du processeur en tout cas, mais tu peux écrire toi-même des routines de calcul adaptés à tes besoins. GMP est un exemple de bibliothèque permettant de travailler avec de grands entiers.
Si, c'est ce que je t'explique au dessus. Le dernier bit est considéré comme une retenue (ce qu'il est, d'ailleurs, au cours de l'opération) et donc il n'est pas perdu (heureusement), il est gardé dans les flags du CPU et c'est un fonctionnement tout-à-fait normal. En C, évidemment, c'est plus difficile à voir, mais c'est possible. D'une manière générale, si le résultat d'une addition non signée est inférieur à la plus grande des opérandes, c'est qu'il y a eu débordement et tu peux ajouter un « 1 » à gauche de ton résultat.
Maintenant, il est logique de conserver au cours du temps les résultats des opérations sur des registres du même format. Sinon, si l'on stockait le produit de deux nombres 32 bits sur un registre 64 bits, où stockerait-on le produit de deux nombres 64 bits ? En admettant que l'on ait des registres 128 bits dédiés à cela, où stockerait-on, alors, le produit de ces registres 128 bits ? Il n'y a pas de raison que ça s'arrête.
D'autre part, le premier des registres d'un micro-processeur est pratiquement toujours un « accumulateur », qui s'appelle d'ailleurs A, ou AX, ou EAX, etc. Le propre d'un accumulateur est de recevoir le résultat d'une opération et de servir immédiatement d'opérande pour l'opération suivante. Par exemple, dans « 5 + 6 + 3 + 9 + 2 », 5 + 6 = 11 ; 11 + 3 = 14 ; 14 + 9 = 23 ; 23 + 2 = 25. Cette manière de faire impose de fait que les opérandes et le registre de sortie soit du même format.
L'exemple criant est celui d'une calculatrice quatre opérations ordinaire. Quand tu t'en sers pour faire le calcul ci-dessus, c'est ton écran qui sert d'accumulateur. Si cet écran peut afficher, disons, sept chiffres, rien ne t'empêche de faire « 9999999 + 9999999 » et là, le résultat ne pourra pas être affiché, ni même contenu par la calculatrice.
Tu retrouveras donc le problème du débordement sur tous les calculateurs existants. À toi, soit de faire avec, soit de prévoir le cas en décomposant le calcul. Si tu es sûr d'avoir besoin de calculs exacts sur de très grands nombres, tu peux utiliser une bibliothèque telle que GMP, comme indiqué plus haut, mais le plus sage étant encore de s'assurer à l'avance que tes calculs tiendront toujours sur le format choisi (32 bits devraient être suffisants pour les applications courantes). Sinon, si c'est un problème que tu rencontres a posteriori, c'est qu'il y a probablement une erreur de conception.
ok, merci beaucoup pour toutes ces explications, Obsidian.
J'irai jetter un coup d'oeil sur le forum dédié à l'assembleur pour plus d'information sur les utilisations des registres.
Je me demande quelle est l'utilisation prévue de la base, du compteur et du registre "data", bien que ce sont des registres généraux, à tout faire.
C'est une question que tu peux effectivement poser dans le forum Assembleur x86. On scindera la discussion présente si le sujet dérive trop (pour l'instant, cela reste en relation avec ton post initial).
Intel a fait en sorte, autant que possible, que les noms de ces registres correspondent grosso-modo à leur fonction tout en suivant l'ordre alphabétique. Donc, sur 16 bits, AX = Accu (celui que l'on retrouve partout), BX = Index de Base (≠ BP), CX = Compteur, DX = Donnée. Ce n'est vrai que dans une certaine mesure, et ce n'est pas une règle générale. Sur 68000, par exemple, il y a huit registres A0 à A7 et huit autres D0 à D7.
Pour répondre à ta question : BX a un rôle dans les modes d'adressage. C'est le seul des quatre premiers registres (ceux en -X) qui pouvait servir de pointeur sur x86 16 bits. BP, pour Base Pointer, peut le faire aussi. Mais BP est généralement utilisé dans la définition d'un cadre de pile : en entrant dans une fonction, on sauvegarde le pointeur de pile dans BP, puis on décale ce pointeur de pile pour faire de la place aux variables locales. Ainsi quelque soit l'état de l'exécution, on accède à ces variables à l'aide d'un offset par rapport au pointeur de base BP. En outre, en cas de sortie en catastrophe (goto, exception C++,…) on peut restaurer l'état initial de la pile en remettant BP dans le pointeur de pile et, de là, quitter la fonction normalement.
Le registre DX « data », est le registre utilisé par défaut quand il y a une donnée à lire, après l'accumulateur AX. C'est pourquoi les instructions qui, par nature, renvoie une donnée de taille double de celle de leur opérandes (comme la multiplication), utilisent le couple DX:AX. Sinon, c'est le registre utilisé par défaut par les programmeurs car, en dehors de ces cas de figure, il n'est pratiquement jamais modifié par les différentes instructions.
Partager