1's complement
Il complemento a 1 (in inglese one's complement) di un numero
binario è un metodo per codificare numeri con segno : i numeri positivi si
esprimono secondo la struttura binaria naturale, per cui:
2dec = 00000010
127dec = 01111111
e i numeri negativi con il complemento a 1:
-2dec = 11111101
-127dec = 1000000
Il bit 7 è l' indicatore del segno (0= positivo, 1 =
negativo)
Dal punti di vista strutturale il complemento a 1 di un numero binario N è:
~ N = 2n - 1 -N
L' impiego di un bit come segno fa si che i numeri rappresentabili vanno da
( 2n-1 - 1) a +(2n-1 -
1), ovvero, per un numero su 8 bit, da -127 a +127.
Dal punto di vista operativo, la realizzazione del complemento a 1 del
numero, che è l' inversione dei bit che compongono il numero:
~ n = n ^ FFh
Vediamo lo stato dei singoli bit, che l' XOR con 1 va ad invertire:
Posizione nel byte |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
1E |
0 |
0 |
0 |
1 |
1 |
1 |
1 |
0 |
~ 1E = E1 |
1 |
1 |
1 |
0 |
0 |
0 |
0 |
1 |
I PIC dispongono di un opcode specifico: comf,
per cui:
comf n,d ;
complemento a 1 di n nella destinazione d (W o il file n)
L'informazione del segno è contenuta nel valore stesso e questo permette di sommare valori positivi e negativi tra di loro direttamente.
La somma di due numeri rappresentati in complemento a 1 dà il risultato corretto sommandogli
il riporto; si ha overflow se i riporti generati nelle due posizioni più significative
sono diversi.
La sottrazione si effettua semplicemente sommando il complemento a 1 del
sottraendo.
Una notazione in complemento a 1 ha, però, due aspetti di impraticità: il
primo riguarda il fatto che lo zero può essere rappresentato sia come 00000000
(che è un numero "positivo") sia come 11111111 che è un numero
"negativo"), fatto incongruo con l' aritmetica dove lo 0 non ha
segno.
Il secondo punto riguarda la somma di due valori di segno opposto, dove perché si
deve tenere conto del riporto.
Se vogliamo effettuare l' operazione a - b, essa è eseguibile
come somma: a + (-b) = a + ~ b.
Ad esempio : 10 - 4 = 10 + (-4)
In binario:
10dec = 00001010
4dec = 00000100 per cui ~4dec
= 111110111
Allora:
0000 1010 +
1111 1011 =
-------------
1110
0101 che è, considerando solo il nibble
basso) 5 e non 6
Occorre considerare il riporto 1
e sommarlo al risultato per ottenere 10 - 4 = 6.
2' complement
La soluzione sta nell' uso del complemeno a 2 (in inglese two's
complement), definizione usata anche per indicare l'operazione di negazione
(inversione del segno).
In pratica, se il numero è positivo, il bit di peso maggiore sarà 0, che
rappresenta il segno positivo, seguito dal numero sotto forma normale.
Ad esempio:
+ 10 → 01010 = 0 x (-24) + 1 x 23 + 0 x
22 + 1 x 21 + 0 x 20
Con n bit i numeri positivi rappresentabili vanno da 0 a
2n-1-1. Così, su 8 bit si potranno
rappresentare numeri da 0 a +127 (00000000 - 01111111).
Se il numero N è negativo, il bit di peso maggiore sarà 1, seguito dalla rappresentazione binaria
di 2n-1+ N. Ad esempio:
- 5 → 1 x (-23) + 0 x 22 + 1 x
21 + 0 x 20
Con n bit i numeri negativi rappresentabili vanno da 0 a
2n-1. Così, su 8 bit si potranno rappresentare
numeri da 0 a -128 (00000000 - 10000000).
Schematicamente:
binario : 0 1
2 3 125 126 127 128 129
253 254 255
+---+---+---+-...-+---+---+----+----+--...-+---+---+
2's comp: 0 1 2 3 125 126 127 -128 -127
-3 -2 -1
|------
positivi -------| |------ negativi -----|
Possiamo visualizzare meglio la situazione immaginando che i numeri siano
disposti su una circonferenza:
binario: 128 129
253 254 255 0 1 2 3
125 126 127
+----+-...-+----+----+---+---+---+---+-...-+---+----+
2's comp:-128 -127 -3 -2 -1 0
1 2 3 125 126 127
Il complemento a 2 consente di effettuare addizione e sottrazione senza la
necessità di considerare il segno di un numero per determinare quale delle due operazioni sia
necessaria; nell' hardware si utilizza il solo circuito sommatore, sia per l'addizione che per la sottrazione.
Infatti:
a - b = a + (-b)
Così 2-3 = 2 +(-3) = -1:
2 = 00000010
+ -3 = 11111101
---- --------
-1 = 11111111
e -2-3 = -2 +(-3) = -5
-2 = 11111110
+ -3 = 11111101
---- --------
-5 = 1 11111011
e 10-15 = 10 +(-15) =
10 =
00001010
+ -15 = 11111101
---- --------
5 = 1 11111011
Da notare la presenza di un riporto nelle ultime due somme, riporto utile
per sequenze di più operazioni.
Il complemento a 2, in mancanza di una istruzione specifica nel set del
processore, si realizza in diversi modi, ad esempio con un XOR:
- n = (n ^ FFh) + 1
Così, ad esempio, il complemento a 2 di 1Eh:
- 1Eh = (1Eh ^ FFh) + 1 = E1 + 1 = E2
Altro sistema è usare una differenza :
- n = (FFh - n +1)
Così:
- 1Eh = FFh -1Eh + 1 = E1 + 1 = E2
In effetti, la prima parte delle operazioni viste è la
realizzazione del complemento a 1 del numero, che è l' inversione dei bit che
compongono il numero:
~ n = n ^ FFh
per cui la negazione di un valore può essere effettuata con:
- n = ~ n + 1
In base a quanto detto, si potrà usare una semplice macro, che, però, è già
presente nel set di pseudo opcodes supportati da MPASM:
NEGF
MACRO file,
dest
comf
file,1 ; comp.
1 di file in file
incf
file,dest
; +1
ENDM
Va notato che il set di istruzioni del core a 16 bit (PIC18F)
contiene l' istruzione nativa negf
e quindi non richiede altre azioni.
Una alternativa:
comf file,w ;
comp. 1 di file in W
addlw
1
; +1
e se il numero è già in W:
sublw
0 ;
comp. 2 di file in W
Per PIC con core a 12 bit (Baseline) l' istruzione sublw
o addlw non
esistono. Occorre adeguare con:
addwf file,w ;
W = W + file
subwf
file,w
; W = file - W = file -(W + file) = -W
Nel caso di numeri a 16 bit occorre un piccolo algoritmo:
;-------------------------------------------------
; Complemento a 2 di numero a 16 bit
;-------------------------------------------------
;
; numero in aargb1 aargb0
; risultato in aargb1 aargb0
compl16 comf aargb1,f
comf
aargb0,f
incf
aaargb1,f
skpnz
incf
aargb0,f
retlw
0
|