Comment fonctionne la comparaison d'entiers en interne?

18

Par exemple, lorsque l'on compare deux entiers comme suit dans un langage de type C:

if (3 > 2) {
    // do something
}

Comment le jugement si 3 est supérieur à 2 (vrai) ou non (faux) est-il rendu en interne?

Niek
la source
19
La réponse actuelle est correcte dans le cas où la comparaison porte sur l'expression de variables, mais il n'y a pas de clause de non-responsabilité selon laquelle de nombreux compilateurs modernes regarderont votre morceau de code, détecteront que l'expression sera toujours vraie (à cause des littéraux) et ignorera simplement le iftout , passant directement au codage do something.
SJuan76
3
@Snowman, je ne suis pas d'accord. Toute enquête de programmation «comment ça marche» peut être condensée à cette question, mais cela ne fait pas d'eux des doublons.
user1643723
1
@ user1643723 C'est le cas lorsque la fonction en question est un opcode spécifique.
chrylis -on strike-
1
@ user1643723 La question porte sur la façon dont un ordinateur effectue une opération de base, et la réponse du haut traite des portes logiques et des tables logiques. Deux sujets qui sont couverts en détail dans la première réponse de la cible dupe, qui répond également à votre question.

Réponses:

61

Tout le long du terrier du lapin, hein? OK, je vais essayer.

Étape 1. Du C au langage machine

Le compilateur C transforme votre comparaison en opcodes stockés en langage machine . Le langage machine est une série de nombres que le CPU interprète comme des instructions. Dans ce cas, il y aurait deux opcodes: "soustraire avec carry" et "sauter si transporter". En d'autres termes, 2 est soustrait de 3 dans une instruction, et l'instruction suivante vérifie si elle a débordé. Celles-ci seraient précédées de deux instructions pour charger les numéros 2 et 3 dans des emplacements où ils peuvent être comparés.

MOV AX, 3    ; Store 3 in register AX
MOV BX, 2    ; Store 2 in register BX
SUB AX, BX   ; Subtract BX from AX
JC  Label    ; If the previous operation overflowed, continue processing at memory location "Label"

Chacun des éléments ci-dessus a une représentation binaire; par exemple, le code pour SUBest 2Dhexadécimal ou 00101101en binaire.

Étape 2. Opcodes vers ALU

Arithmétique opcodes aiment ADD, SUB, MULet DIVréaliser des opérations mathématiques de base entier en utilisant une unité logique ALU ou Arithmétique intégré dans le CPU. Les nombres sont stockés dans des registres par certains opcodes; d'autres opcodes demandent à la puce d'appeler l'ALU pour faire des calculs sur tout ce qui est stocké dans les registres à l'époque.

Remarque: À ce stade, nous sommes bien au-delà de tout ce qui pourrait inquiéter un ingénieur logiciel s'il travaille avec un 3GL comme C.

Étape 3. L'ALU, demi-additionneur et additionneur complet

Saviez-vous que toutes les opérations mathématiques que vous connaissez peuvent être réduites à une série d'opérations NOR ? Et c'est exactement ainsi que fonctionne l'ALU.

L'ALU sait uniquement comment travailler avec des nombres binaires et ne peut effectuer que des opérations logiques comme OR, NOT, AND et XOR. La mise en œuvre de l'addition et de la soustraction binaires est accomplie avec une série d'opérations logiques disposées d'une certaine manière, dans un sous-système appelé additionneur . Ces sous-systèmes sont composés d'un réseau de "demi-additionneurs" qui fonctionnent sur deux bits et déterminent leur somme sur un seul bit et un drapeau de report sur un seul bit. En les enchaînant, l'ALU peut effectuer des opérations sur des nombres de 8, 16, 32 etc. bits.

Demi-additionneur

Et la soustraction? La soustraction n'est qu'une autre forme d'addition:

A - B = A + (-B)

L'ALU calcule -Ben prenant le complément à deux de B. Une fois qu'il est converti en négatif, soumettre la valeur à l'additionneur entraînera une opération de soustraction.

Étape 4: La dernière étape: transistors sur puce

Les opérations des additionneurs sont mises en œuvre en utilisant une combinaison de composants électriques qui interagissent pour créer des "portes logiques", telles que celles trouvées dans la logique transistor-transistor ou TTL, ou dans CMOS . Cliquez ici pour quelques exemples pour voir comment ceux-ci sont câblés.

Sur une puce, bien sûr, ces "circuits" sont implémentés dans des millions de minuscules morceaux de matériau conducteur et non conducteur, mais le principe est le même que s'ils étaient des composants de taille réelle sur une planche à pain. Regardez cette vidéo qui vous montre tous les transistors sur une puce à travers la lentille d'un microscope électronique.

Quelques notes supplémentaires:

  1. Le code que vous avez écrit serait en fait précalculé par le compilateur et non exécuté au moment de l'exécution, car il est composé uniquement de constantes.

  2. Certains compilateurs ne compilent pas en code machine mais introduisent une autre couche, comme le bytecode Java ou le langage intermédiaire .NET. Mais au final, tout est exécuté via le langage machine.

  3. Certaines opérations mathématiques ne sont pas réellement calculées; ils sont recherchés dans des tables massives sur une unité de coprocessing arithmétique, ou contiennent une combinaison de recherche et de calcul ou d'interpolation. Un exemple serait la fonction pour calculer une racine carrée . Les processeurs PC modernes ont chacun une unité de coprocesseur à virgule flottante intégrée dans chaque cœur de processeur.

John Wu
la source
3
FWIW, faire référence au TTL peut être source de confusion car pratiquement aucun processeur moderne n'utilise la signalisation TTL, la plupart utilisant des FET CMOS et des tensions inférieures au lieu des BJT 5v.
whatsisname
2
CMOS serait certainement une meilleure référence que TTL, comme le suggère @whatsisname, car non seulement il est plus précis par rapport à ce qui se passe dans les processeurs modernes, mais il est également beaucoup plus simple conceptuellement.
Jules
3
@JackAidley, c'est ce que cette partie signifie: "En d'autres termes, 2 est soustrait de 3 dans une instruction, et l'instruction suivante vérifie si elle déborde."
KutuluMike
1
Nitpicking: Je suppose que ce CMPserait utilisé, non SUB- mais là encore, c'est plus ou moins un "où SUBle résultat est ignoré et seuls les indicateurs sont définis"
Hagen von Eitzen
5
Vos définitions de demi-additionneur et d'additionneur complet sont incorrectes. Un demi-additionneur prend deux entrées de 1 bit et retourne la somme et le report. Un additionneur complet prend une entrée de report supplémentaire mais n'est toujours qu'un seul bit. Il existe de nombreuses façons de créer un additionneur à N bits, la plus simple étant un additionneur à ondulation qui n'est qu'une chaîne de N additionneurs complets. En pratique, pour les N plus grands, cela a un très mauvais délai, donc des conceptions plus complexes sont utilisées dans les conceptions de CPU modernes.
Voo