Si supponga che la mattonella in figura sia un quadrato di lato 1.
Se si vuole coprire un pavimento quadrato, avente il lato di lunghezza 2, si devono aggiungere altre 3 mattonelle disponendole come quelle gialle in figura:
Continuando ad incrementare la lunghezza del lato del quadrato, per coprire un pavimento quadrato di lato 3 bisogna aggiungere 5 mattonelle, disponendole come quelle verdi in figura:
Da questo esempio si può osservare che il quadrato di un numero N si può ottenere dalla somma dei primi N numeri dispari.
Ad esempio il quadrato Q del numero 4 è ottenuto dalla somma dei primi 4 numeri dispari: 1 + 3 + 5 + 7.
Affinchè il programma funzioni anche nel caso N=0, nella somma si consideri che il primo addendo sia 0, così che il quadrato di 4 si può anche scrivere:
Q = 0 + 1 + 3 + 5 + 7
Il procedimento di calcolo consiste nell'acquisire in una variabile N il valore del numero da elevare al quadrato. Poi si genera una sequenza dei primi N numeri dispari in una variabile D. Ogni numero dispari viene sommato alla variabile Q, che inizialmente contiene 0.
Le tre variabili individuate vengono memorizzate nei registri interni della CPU. Si decidono le seguenti posizioni:
la variabile ... | viene memorizzata nel registro ... |
Q | BX |
N | CX |
D | AX |
I valori iniziali delle variabili, supponendo di voler calcolare il quadrato di N = 4 sono:
(variabile Q) BX ← 0
(variabile N) CX ← 4
(variabile D) AX ← 1
Con questi valori iniziali si procede al calcolo del quadrato:
Operazione | Simboli | valori in memoria |
Si somma a Q il primo numero dispari D e si memorizza il risultato in Q: | Q ← Q + D | (Q) BX: 1 |
Si calcola il prossimo numero dispari: | D ← D + 2 | (D) AX: 3 |
Si contano i dispari che restano da sommare: | N ← N - 1 | (N) CX: 3 |
Se la quantità di dispari rimasti (N) è 0 allora il procedimento termina | N>0? (Sì) | flag Z: falso |
Si somma a Q il numero dispari contenuto in D | Q ← Q + D | (Q) BX: 4 |
Si calcola il prossimo numero dispari: | D ← D + 2 | (D) AX: 5 |
Si conta quanti dispari restano da sommare: | N ← N - 1 | (N) CX: 2 |
Se la quantità di dispari rimasti (N) è 0 il procedimento termina | N>0? (Sì) | flag Z: falso |
Si somma a Q il numero dispari contenuto in D | Q ← Q + D | (Q) BX: 9 |
Si calcola il prossimo numero dispari: | D ← D + 2 | (D) AX: 7 |
Si conta quanti dispari restano da sommare: | N ← N - 1 | (N) CX: 1 |
Se la quantità di dispari rimasti (N) è 0 il procedimento termina | N>0? (Sì) | flag Z: falso |
Si somma a Q il numero dispari contenuto in D | Q ← Q + D | (Q) BX: 16 |
Si calcola il prossimo numero dispari: | D ← D + 2 | (D) AX: 9 |
Si conta quanti dispari restano da sommare: | N ← N - 1 | (N) CX: 0 |
Se la quantità di dispari rimasti (N) è 0 il procedimento termina | N>0? (Sì) | flag Z: vero |
Sono stati sommati 4 dispari. Il procedimento è terminato. Il quadrato di N si trova in BX (Q) |
Scrivere il programma in Assembler:
.model small
.data
Q dw ? ; nella variabile Q si memorizzerà il quadrato di N
N dw 4 ; calcolare il quadrato di N
.code
inizio:
MOV AX, @data ; inizializza il registro data segment
MOV DS, ax
MOV BX, 0 ; Porta Q in BX
MOV DX, N ; Porta N in DX
MOV AX, 1 ; Primo numero dispari
MOV CX, DX ; Il registro CX è un contatore
ripeti:
ADD BX, AX ; somma i numeri dispari
ADD AX, 0002 ; passa al successivo numero dispari
DEC CX ; conta una somma
JCXZ fine ; se il conteggio è giunto a 0 il procedimento termina
JMP ripeti ; altrimenti si ripete
fine:
mov ax, 4c00h ; uscita dal programma
int 21h ; si restituisce il controllo al sistema operativo
end inizio ; fine della traduzione. Il punto di inizio del programma è indicato dalla label «inizio».
Salvare il programma con il nome Quadrato.asm
Produrre il file oggetto: tasm quadrato.asm
Produrre il file eseguibile: tlink Quadrato.obj
Avviare il debugger: td Quadrato.exe
Si apre la finestra in cui è in esecuzione il debugger.
Nella finestra si possono riconoscere le seguenti sezioni:
Nel riquadro del codice si osserva l'elenco delle istruzioni:
Indirizzo | istruzione macchina | istruzione Asm |
cs:0000 | B8 39 14 | mov ax, 1439 |
cs:0003 | 8E D8 | mov ds, ax |
cs:0005 | BB 00 00 | mov bx, 00 |
cs:0008 | 8B 16 02 00 | mov dx, [0002] |
cs:000C | BB 01 00 | mov ax, 0001 |
cs:000F | 8B CA | mov cx, dx |
cs:0011 | 03 D8 | add bx, ax |
cs:0013 | 05 02 00 | add ax, 0002 |
cs:0016 | 49 | dec cx |
cs:0017 | E3 02 | jcxz 001B |
cs:0019 | EB F6 | jmp 001 |
cs:001B | B8 00 4C | mov ax, 4c00 |
cs:001E | CD 21 | int 21 |
Il registro IP punta alla prossima istruzione da eseguire. Tale istruzione è marcata con un triangolino.
I registri della CPU:
AX=0000 BX=0000 CX=0000 DX=0000 SI=0000 DI=0000 BP=0000 SP=FFEE DS=1427 ES=1427 SS=1437 CS=1437 IP=0000
Il registro delle flag:
c=0 (carry) z=0 (zero) s=0 (segno) o=0 (overflow) p=0 (parità a=0 (auxiliary carry) i=1 (interrupt) d=0 (direzione)
Premendo il tasto F7 si esegue l'istruzione e si può osservare che il puntatore alla prossima istruzione è avanzato e nel registro ax è stato trasferito il valore che si deve assegnare alla base del segmento dati
Dando ripetutamente il comando F7 (Trace) si esegue un'istruzione alla volta e al termine di ciascuna si può osservare lo stato dei registri.
Evitare di eseguire l'istruzione di uscita dal programma (int 21)
Per ripetere l'esecuzione bisogna riportare nel registro IP l'offset della prima istruzione del programma: Cliccare su IP per evidenziarlo, premere il tasto destro su IP e scegliere Change. Scrivere l'offset della prima istruzione e premere invio.
Visualizzare il segmento Dati: View → Dump, Premere il tasto destro sulla finestra Dump e scegliere il comando goto. Inserire l'offset della variabile N. Premendo nuovamente il tasto destro sulla finestra Dump scegliere il comando change. Inserire un nuovo valore da assegnare alla variabile N. Riportare IP all'inizio del programma. Rieseguire il programma passo-passo e verificare la correttezza del risultato.
Modificare un'istruzione: clic sull'istruzione MOV AX, 4C00 per selezionarla. Clic con il tasto destro sull'istruzione selezionata e scegliere il comando Assemble …. Inserire l'istruzione per trasferire il valore contenuto nel registro in cui si trova il valore della radice quadrata di N all'offset della variabile Q. Eseguire il programma passo-passo, dopo aver aggiustato il registro IP, e verificare la correttezza dell'operazione.
Per calcolare la radice quadrata di un numero N si devono contare quanti numeri dispari sono contenuti nel numero N
Per ipotesi il numero di cui si vuole calcolare la radice quadrata è stato memorizzato nel registro AX. Al termine del programma il risultato sarà disponibile nel registro DX.
.model small
.data
R DW 0
N DW 19
.code
inizio:
MOV AX, @data
MOV DS, AX
MOV AX, N
MOV DX, 1
MOV CX, 1
ripeti:
SUB AX, CX
JL fine
INC DX
ADD CX, 2h
JMP ripeti
fine:
MOV AX, 4C00h
int 21h
end inizio
Assemblare e linkare il programma. Avviare il debugger
La radice quadrata del numero inizialmente contenuto in AX è disponibile in DX.
Verificare il programma passo passo
Prima di eseguire il programma una seconda volta bisogna porre il contenuto del registro IP a valore 0, l'indirizzo della prima istruzione del programma.
L'istruzione all'offset 0010 è jl 0018 (jump if less to 0018) significa che se l'operazione aritmetica precedente ha dato risultato minore di zero (nell'istruzione il confronto con 0 è sottinteso) bisogna proseguire con l'esecuzione del programma a partire dall'istruzione all'offset 0112 altrimenti bisogna continuare con l'istruzione successiva. Quando il risultato è minore di zero quali flag vengono modificate?
Calcolare il valore rappresentato dal codice binario contenuto in AX.
Memorizzare il risultato nella variabile R