Numéros signés et non signés

17

Comment l'ALU dans un microprocesseur ferait-il la différence entre un nombre signé, -7 qui est désigné par 1111 et un nombre non signé 15, également désigné par 1111?

noorav
la source
3
Voir la réponse à la question connexe: cs.stackexchange.com/a/30047/28999 . Par ailleurs, signé -7 n'est pas représenté comme 1111. C'est -1. Ensuite, par exemple 1111 - 0001 = 1110 dans le cas signé et non signé (-2 vs 14)
Albert Hendriks
2
@AlbertHendriks Pour être honnête, certains ordinateurs plus anciens utilisent une "représentation de la grandeur du signe" (un bit de signe et bits de magnitude), et nous utilisons toujours ce style pour, par exemple, les flottants IEEE. Ils sont simplement inélégants et difficiles à travailler par rapport au complément à deux. n1
Draconis
1
La principale différence réside dans le comportement des opérateurs GreaterThan / lessThan et si le décalage vers la droite remplit le bit le plus élevé. Lorsque vous multipliez et divisez, le résultat est le même.
Rob
2
@Rob Ce n'est pas tout à fait correct. L'addition, la soustraction et la multiplication sont toutes les mêmes entre complément non signé et complément à deux - en supposant que vos entrées et sorties sont de la même taille. La division n'est pas la même 6/2 est 3, mais -2/2 est -1. Et de nombreux processeurs ont des instructions de multiplication où les deux entrées sont de taille identique, mais la sortie est deux fois plus grande, auquel cas non signé et complément à deux ne sont pas les mêmes non plus.
kasperd

Réponses:

14

La réponse courte et simple est: ce n'est pas le cas. Aucun processeur ISA grand public moderne ne fonctionne comme vous le pensez.

Pour le CPU, c'est juste un motif de bits. C'est à vous, le programmeur, de garder une trace de ce que signifie ce modèle de bits.

En général, les ISA ne font pas de distinction entre les différents types de données en matière de stockage. (Ignorer les registres à usage spécial tels que les registres flottants dans une FPU.) Ce n'est qu'un modèle insignifiant de bits vers le CPU. Cependant, les normes ISA n'ont différents types d'instructions qui peuvent interpréter le motif de bits de différentes façons. Par exemple, des instructions arithmétiques telles que , , , interprètent le modèle binaire comme une sorte de nombre, alors que des instructions logiques telles que , , l' interpréter comme un tableau de booléens. Ainsi, c'est au programmeur (ou à l'auteur de l'interpréteur ou du compilateur si vous utilisez un langage de niveau supérieur) de choisir les bonnes instructions.MULDIVADDSUBANDORXOR

Il peut très bien y avoir des instructions distinctes pour les numéros signés et non signés, par exemple. Certaines ISA ont également des instructions pour l'arithmétique avec des décimales codées binaires.

Cependant, notez que j'ai écrit "ISA grand public moderne" ci-dessus. Il existe en fait des normes ISA non traditionnelles ou historiques qui fonctionnent différemment. Par exemple, l'ISA CISC 48 bits d'origine d'IBM AS / 400 ainsi que l'ISA RISC 64 bits actuel du système désormais appelé IBM i, distinguent les pointeurs des autres valeurs. Les pointeurs sont toujours balisés et incluent les informations de type et la gestion des droits. Le CPU sait si une valeur est un pointeur ou non, et seul le noyau i / OS privilégié est autorisé à manipuler librement les pointeurs. Les applications utilisateur ne peuvent manipuler les pointeurs qu'elles possèdent que pour pointer vers la mémoire qu'elles possèdent en utilisant un petit nombre d'instructions sûres.

Il y avait également des conceptions ISA historiques qui incluaient au moins une forme limitée de connaissance du type.

Jörg W Mittag
la source
Notez que le bytecode Java compte également comme un ISA. Et il se soucie à peu près des types de données ...
John Dvorak
Le bytecode Java compte en quelque sorte comme un ISA, dans le sens où il a été implémenté dans du silicium. Cependant, la vérification de type basique de ce type est une vérification effectuée par le chargeur de classe, de sorte que les types peuvent être ignorés lors de l'exécution. Et bien sûr, le bytecode Java n'a pas de types non signés en premier lieu.
Pseudonyme du
@Pseudonym: Eh bien,, techniquement ne dispose char, qui est un type non signé 16 bits. Bien sûr, il n'y a toujours pas d'instructions arithmétiques non signées dans le bytecode Java, car toutes les charvaleurs sont automatiquement promues int(signées 32 bits) pour l'arithmétique.
Ilmari Karonen
42

Version courte: il ne sait pas. Il n'y a aucun moyen de le savoir.

Si 1111représente -7, alors vous avez une représentation de la magnitude du signe , où le premier bit est le signe et le reste des bits est la magnitude. Dans ce cas, l'arithmétique est quelque peu compliquée, car un ajout non signé et un ajout signé utilisent une logique différente. Donc, vous auriez probablement un SADDet un UADDopcode, et si vous choisissez le mauvais, vous obtenez des résultats absurdes.

Le plus souvent, cependant, 1111représente -1, dans ce qu'on appelle une représentation à deux compléments . Dans ce cas, l'ALU ne se soucie simplement pas que les numéros soient signés ou non! Par exemple, prenons l'opération de 1110 + 0001. En arithmétique signée, cela signifie "-2 + 1", et le résultat devrait être -1 ( 1111). En arithmétique non signée, cela signifie "14 + 1", et le résultat devrait être 15 (1111 ). Donc, l'ALU ne sait pas si vous voulez un résultat signé ou non signé, et il s'en fiche. Il fait simplement l'ajout comme s'il n'était pas signé, et si vous souhaitez le traiter comme un entier signé par la suite, c'est à vous de décider.

EDIT: Comme Ruslan et Daniel Schepler le soulignent à juste titre dans les commentaires, certains opérandes ont encore besoin de versions distinctes signées et non signées, même sur une machine à deux. L'addition, la soustraction, la multiplication, l'égalité et tout cela fonctionne bien sans savoir si les nombres sont signés ou non. Mais la division et toute comparaison supérieure / inférieure doivent avoir des versions distinctes.

EDIT EDIT: Il y a aussi d'autres représentations, comme son complément , mais celles-ci ne sont plus utilisées, donc vous ne devriez pas avoir à vous en soucier.

Draconis
la source
Ah, gotcha. Merci pour cela :)
noorav
10
Dans la représentation du complément à deux, trois opérations arithmétiques sont indépendantes de la signature: addition, soustraction et multiplication (avec un produit de la même longueur que les opérandes). Seule la division doit être traitée différemment pour les opérandes signés.
Ruslan
4
Il y a aussi une comparaison: < <= >= >sont différents pour les opérandes signés par rapport aux opérandes non signés ==et !=sont indépendants de la signature.
Daniel Schepler
La multiplication a souvent des variétés signées et non signées: 0xFFFFFFFF * 0xFFFFFFFF est 0xFFFFFFFE00000001 si non signé et 0x0000000000000001 si signé. Les processeurs comme Intel renvoient le résultat dans 2 registres, et le registre supérieur diffère pour les signés et les non signés. Le registre du bas est 1 dans les deux situations.
Rudy Velthuis
9

L'un des grands avantages des mathématiques à complément à deux, que toutes les architectures modernes utilisent, est que les instructions d'addition et de soustraction sont exactement les mêmes pour les opérandes signés et non signés.

De nombreux processeurs n'ont même pas d'instructions de multiplication, de division ou de module. S'ils le font, ils doivent avoir des formes distinctes signées et non signées de l'instruction, et le compilateur (ou le programmeur en langage assembleur) choisit celle appropriée.

Les processeurs ont également généralement des instructions différentes pour les comparaisons signées ou non signées. Par exemple, x86 peut suivre un CMPavec JL(Aller si moins que) si la comparaison doit être signée, ou JB(Aller si ci-dessous) si la comparaison doit être non signée. Encore une fois, le compilateur ou le programmeur choisirait la bonne instruction pour le type de données.

Quelques autres instructions viennent souvent dans des variantes signées et non signées, telles que le décalage à droite ou le chargement d'une valeur dans un registre plus large, avec ou sans extension de signe.

Davislor
la source
1
Même la multiplication est la même pour les entiers non signés et signés (complément à deux), tant que vous n'avez pas besoin du résultat pour avoir plus de bits que les entrées . Si vous faites quelque chose comme la multiplication 8 × 8 → 16 bits (ou 16 × 16 → 32 bits, etc.), cependant, vous devez signer étendre les entrées (ou les résultats intermédiaires) .
Ilmari Karonen
@IlmariKaronen C'est vrai; ARM A32 / A64 sont des jeux d'instructions qui ont de nombreuses formes de l'instruction multiply, y compris la multiplication-add agnostique qui écrit uniquement les bits de poids faible, mais aussi smulhet umulhqui ne renvoient que les bits supérieurs de la multiplication et les instructions signées et non signées qui renvoie le résultat dans un registre deux fois plus large que les opérandes source.
Davislor
6

Ce n'est pas le cas. Le processeur s'appuie sur le jeu d'instructions pour lui dire quel type de données il regarde et où les envoyer. Il n'y a rien à propos des 1 et des 0 dans l'opérande lui-même qui peut intrinsèquement signaler à l'ALU si les données sont un caractère, un flottant, un entier, un entier signé, etc. Si ce 1111 va sur un circuit électrique qui attend un complément de 2 secondes, ça va à interpréter comme un complément à 2s.

Jay Speidell
la source
Il n'y a rien de tel qu'au charniveau matériel. Peut-être une fois, à l'époque des téléimprimeurs mécaniques. Mais aujourd'hui, un charest tout simplement un certain nombre dans la mesure où le matériel est concerné. La raison pour laquelle différents nombres correspondent à différentes formes de lettres sur votre écran est que ces nombres sont utilisés pour sélectionner différents bitmaps ou différentes routines de dessin à partir d'un grand tableau (c'est-à-dire à partir d'une "police").
Solomon Slow
3

Je voudrais apporter un complément aux réponses déjà apportées:

Dans la plupart des autres réponses, il est noté que dans l'arithmétique à deux compléments, le résultat est le même pour les nombres signés et non signés:

-2 + 1 = -1     1110 + 0001 = 1111
14 + 1 = 15     1110 + 0001 = 1111

Cependant , il existe des exceptions:

Division:
  -2 / 2 = -1     1110 / 0010 = 1111
  14 / 2 = 7      1110 / 0010 = 0111
Comparison:
  -2 < 2 = TRUE   1110 < 0010 = TRUE
  14 < 2 = FALSE  1110 < 0010 = FALSE
"Typical" (*) multiplication:
  -2 * 2 = -4     1110 * 0010 = 11111100
  14 * 2 = 28     1110 * 0010 = 00011100

(*) Sur de nombreux processeurs, le résultat d'une multiplication de deux nombres à n bits a une largeur de (2 * n) bits.

Pour de telles opérations, les CPU ont des instructions différentes pour l'arithmétique signée et non signée.

Cela signifie que le programmeur (ou le compilateur) doit utiliser d'autres instructions pour l'arithmétique signée et non signée.

Le CPU x86 par exemple a une instruction nommée divpour faire une division non signée et une instruction nommée idivpour faire une division signée.

Il existe également différentes instructions "conditionnelles" (sauts conditionnels, set-bit-on-condition) ainsi que des instructions de multiplication pour l'arithmétique signée et non signée.

Martin Rosenau
la source