Salta al contenuto
Note per Studenti Esercizio 1 · complemento a 2, esadecimale e IEEE 754

Esercizio 1complemento a 2, esadecimale e IEEE 754

Esame
In questa pagina 11

Testo (questionario di dicembre 2022 del corso di Fondamenti di Informatica UniPD, in Java; adattato da un tema d'esame in Java: domande a risposta multipla, qui con risposta motivata e verificata in Python). Teoria: Rappresentazione binaria dei datiBasi 2, 8 e 16; interi senza segno e in complemento a 2 con overflow; virgola mobile IEEE 754 e sue approssimazioni; caratteri ASCII, Unicode e UTF-8.Rappresentazione binaria dei dati →.

  1. Quanti simboli diversi si possono ottenere con un codice a 4 bit?
  2. Il numero binario 1111111 in complemento a 2 a 7 bit: quanto vale in base 10?
  3. Rappresentare −79-79 in complemento a 2 a 8 bit.
  4. Il numero 128128 è rappresentabile in complemento a 2 a 8 bit?
  5. Il numero 000 1011 0010 è un intero in complemento a 2 a 11 bit. Qual è la sua rappresentazione a 20 bit?
  6. Scrivere 241241 in esadecimale e convertire A1F0 in base 10.
  7. Qual è il numero successivo a 2,02{,}0 rappresentabile in IEEE 754 a singola precisione?
  8. Qual è il massimo int (32 bit) e che cosa succede sommando 1?
  9. In Java, che cosa fa l'enunciato int x = (int) Long.MAX_VALUE;: dà un errore, e quanto vale x?

1. Simboli di un codice a 4 bit

Ogni bit ha 2 valori e i bit sono indipendenti: 24=162^4 = 16 simboli.

2. 1111111 a 7 bit

Il bit più significativo vale −26-2^{6}, gli altri pesano +2k+2^{k}:

−64+32+16+8+4+2+1=−1.-64 + 32 + 16 + 8 + 4 + 2 + 1 = -1.

Regola rapida: tutti 1 è sempre −1-1, in qualunque larghezza.

3. −79-79 a 8 bit

Con n=8n=8 bit il campo è [−128, 127][-128,\,127], quindi −79-79 è rappresentabile. Per ottenerlo: 79=0100 111179 = 0100\,1111; si invertono i bit (1011 00001011\,0000) e si somma 1:

1011 0000+1=1011 0001.1011\,0000 + 1 = \mathbf{1011\,0001}.

Verifica: −128+32+16+1=−79-128 + 32 + 16 + 1 = -79.

4. 128128 a 8 bit

Il massimo positivo a 8 bit è 27−1=1272^7 - 1 = 127: non è rappresentabile. La stringa 1000 0000 esiste ma vale −128-128, non +128+128 (il campo è asimmetrico: un negativo in più).

5. Estensione del segno

Per passare a più bit si replica il bit di segno a sinistra. Qui il bit di segno è 00:

000 1011 0010  →  0000 0000 0000 1011 0010.000\,1011\,0010 \;\to\; 0000\,0000\,0000\,1011\,0010.

(Con un numero negativo si aggiungerebbero degli 11: 111 1111 a 7 bit =−1= -1 diventa 1111 1111 1111 1111 a 16 bit, ancora −1-1.)

6. Esadecimale

  • 241=15⋅16+1241 = 15\cdot16 + 1, cioè cifre 1515 e 11: F1.
  • A1F0: 10⋅163+1⋅162+15⋅16+0=40960+256+240=10\cdot16^3 + 1\cdot16^2 + 15\cdot16 + 0 = 40960 + 256 + 240 = 41456.

7. Numero successivo a 2,02{,}0 in singola precisione

2,0=1,0×212{,}0 = 1{,}0\times 2^{1}. In singola precisione la parte frazionaria ha 23 bit: il passo tra due numeri vicini con esponente 11 è 2−23⋅21=2−222^{-23}\cdot 2^{1} = 2^{-22}. Il successivo è 2,0+2−22≈2,000000242{,}0 + 2^{-22} \approx 2{,}00000024. Non è 2,12{,}1: tra 22 e 2,12{,}1 ci sono circa 400 000400\,000 numeri rappresentabili.

8. Massimo int e overflow

Con 32 bit il massimo è 231−1=2 147 483 6472^{31}-1 = 2\,147\,483\,647. Sommando 1 in aritmetica a 32 bit si ottiene 2312^{31}, che in complemento a 2 ha il bit di segno a 1: il risultato è −231=−2 147 483 648-2^{31} = -2\,147\,483\,648. In Java e in C questo overflow non produce errori; in Python gli interi non hanno limite e il risultato resta corretto.

9. Da long a int

Il cast (int) di un long tronca ai 32 bit meno significativi, senza errori né in compilazione né in esecuzione. Long.MAX_VALUE =263−1= 2^{63}-1 ha tutti i bit a 11 tranne il segno; i 32 bit bassi sono tutti 11 e, letti in complemento a 2 a 32 bit, valgono −1-1: x = -1. In C (int)LLONG_MAX dà lo stesso valore sulle macchine usuali (il risultato è definito dall'implementazione); in Python la conversione non esiste, gli interi non hanno limite.

Verifica in Python

python
import struct

def cmp2(n, bit):
    """rappresentazione di n in complemento a 2 su 'bit' bit (stringa)"""
    assert -(1 << (bit - 1)) <= n < (1 << (bit - 1)), "non rappresentabile"
    return format(n & ((1 << bit) - 1), f"0{bit}b")

def valore(s):
    """valore di una stringa di bit in complemento a 2"""
    return int(s, 2) - (1 << len(s)) if s[0] == "1" else int(s, 2)

def estendi(s, bit):
    return s[0] * (bit - len(s)) + s

print(2 ** 4)                              # 16
print(valore("1111111"))                   # -1
print(cmp2(-79, 8))                        # 10110001
print(-128 <= 128 <= 127)                  # False: 128 non sta in 8 bit
print(estendi("00010110010", 20))          # 00000000000010110010
print(format(241, "X"), int("A1F0", 16))   # F1 41456

x = struct.unpack(">I", struct.pack(">f", 2.0))[0]          # bit di 2.0 come intero
succ = struct.unpack(">f", struct.pack(">I", x + 1))[0]     # il successivo
print(succ, succ - 2.0 == 2 ** -22)        # 2.000000238418579 True

def somma32(a, b):                          # somma "alla C" su 32 bit
    s = (a + b) & 0xFFFFFFFF
    return s - (1 << 32) if s >> 31 else s

print(somma32(2 ** 31 - 1, 1))             # -2147483648
print(somma32(2 ** 63 - 1, 0))             # -1: i 32 bit bassi di Long.MAX_VALUE letti come int

Errori comuni

  • Scrivere −79-79 come "segno e modulo" (1100 1111): in complemento a 2 si inverte e si somma 1.
  • Credere che −128-128 e +128+128 siano entrambi rappresentabili a 8 bit.
  • Estendere un numero negativo con zeri invece che con il bit di segno.
  • Pensare che dopo 2,02{,}0 venga 2,12{,}1: i float sono a passo variabile e non rappresentano esattamente 0,10{,}1.

Versione ripasso

Questionario di dicembre 2022 (Fondamenti di Informatica, UniPD, in Java). Teoria: Rappresentazione binaria dei datiBasi 2, 8 e 16; interi senza segno e in complemento a 2 con overflow; virgola mobile IEEE 754 e sue approssimazioni; caratteri ASCII, Unicode e UTF-8.Rappresentazione binaria dei dati →.

  • 4 bit → 24=162^4 = 16 simboli.
  • 1111111 a 7 bit: −64+63=−1-64+63 = -1 (tutti 1 vale sempre −1-1).
  • −79-79 a 8 bit: 79=0100 111179 = 0100\,1111, inverti 1011 0000, +1+1 → 1011 0001 (campo [−128,127][-128, 127]).
  • 128128 a 8 bit: non rappresentabile (1000 0000 =−128= -128).
  • Estensione del segno: 000 1011 0010 → 0000 0000 0000 1011 0010 (si replica il bit di segno).
  • 241=241 = F1; A1F0 =40960+256+240=41456= 40960 + 256 + 240 = 41456.
  • Dopo 2,02{,}0 in singola precisione: 2,0+2−222{,}0 + 2^{-22} (23 bit di frazione, esponente 1), non 2,12{,}1.
  • Massimo int 231−12^{31}-1; +1+1 dà −231-2^{31} (overflow silenzioso in Java e C, non in Python).
  • (int) Long.MAX_VALUE: tronca ai 32 bit bassi, -1, nessun errore.

Errori comuni: segno e modulo al posto del complemento a 2; ±128\pm128 a 8 bit; estendere un negativo con zeri.

Teoria collegata