Esempio 17: media di n numeri da input con ciclo

Un altro esempio per approfondire l’utilizzo dei cicli in asm. Questa volta vediamo un altro classico problema per i programmatori in erba: la media di n numeri inseriti da tastiera con n a sua volta scelto in input dall’utente in input.

Il problema in analisi è un classico per chi inizia a programmare con qualsiasi linguaggio di programmazione ad alto livello. Si presta molto bene anche per approfondire asm e i cicli.

Lettura

La prima parte di lettura del numero di elementi di cui fare la somma è molto semplici per chi è arrivato a questo punto del nostro percorso. Scegliamo un registro generico qualsiasi per ricevere il numero, ad es. rax. Vi ricordo la lettura GET_DEC col parametro 4 per leggere 32bit, 8 per leggere 64bit. Se inseriamo 4 con i registri a 64bit funziona lo stesso ma utilizzeremo meno bit del registro a 64bit.

    PRINT_STRING "Inserisci quanti numeri vuoi sommare"
    GET_DEC 8,rax  ; cin >>  n 

Più interessante è ricordare sempre che i registri sono utilizzati dalla cpu per tutti gli scopi necessari al funzionamento del pc. Ancora prima dell’esecuzione del nostro programma, tali registri possono aver ospitato valori, indirizzi o altro di processi andati in esecuzione prima. Ecco perché, come con qualsiasi linguaggio di programmazione ad alto livello, bisogna sempre inizializzare i registri o le variabili ai valori utili, nella maggior parte dei casi con lo zero. Qui è da mettere zero nei registri rcx che ci servirà da contatore e rdx che ci servirà da accumulatore. Invece di usare la opCode mov registro, 0 ho usato la opCode di xor registro, registro poiché ottiene lo stesso risultato ma con meno cicli di cpu. Lo studente che non gradisce le ottimizzazioni può certamente usare l’altra modalità più intuitiva.

Ciclo

Il ciclo vero e proprio è molto semplice. Ci serve una etichetta esplicativa per contrassegnare il frammento di codice da ripetere per ogni passaggio del ciclo. Il ciclo, di fatto, è il classico do-while. Ho il contatore da incrementare, il registro rdx che accumula le somme dei numeri letti e posizionati sul registro rbx, la condizione per tornare sopra il ciclo con un salto o uscire qualora la condizione venisse meno. In questo caso dal ciclo dobbiamo uscire quando il contatore è arrivato al numero complessivo altrimenti se minore deve saltare all’inizio del ciclo e leggere un altro numero e così via. JL, jump less, è proprio la condizione while(contatore < numero){…}.

ciclo:    
    GET_DEC 8,rbx  ; cin >>  num
    inc rcx ; contatore elementi inseriti i++
    add rdx, rbx
    cmp rcx,rax 
    jl ciclo

Media

Il frammento successivo si occupa di calcolare la media con la divisione intera. Come visto nelle altre lezioni, bisogna preparare i registri rax e rdx per accogliere il dividendo e il resto rispettivamente. Mentre il divisore può essere posto in un registro qualsiasi. Il quoziente sarà poi sovrascritto in rax stesso.

    mov rax, rdx
    xor rdx, rdx
    div rcx

Il codice completo:

%include "io64.inc"

section .text
global CMAIN
CMAIN:
    mov rbp, rsp; for correct debugging
    PRINT_STRING "Inserisci quanti numeri vuoi sommare"
    GET_DEC 8,rax  ; cin >>  n   
    
    ;inizializzo/pulisco a zero i registri che mi occorrono 
    xor rcx, rcx  ; equivale a mov ecx, 0 ovvero ecx=0
    xor rdx, rdx 
    
ciclo:    
    GET_DEC 8,rbx  ; cin >>  num
    inc rcx ; contatore elementi inseriti i++
    add rdx, rbx
    cmp rcx,rax 
    jl ciclo
    
    ;preparo i registri per la divisione es. 40 / 4
    ;il 40 che stava in dx lo muovo in ax
    ;sbianco dx per il resto
    ;i lrisultato quoziente sarà ancora in ax
    mov rax, rdx
    xor rdx, rdx
    div rcx
    
    NEWLINE
    PRINT_STRING "media= "
    PRINT_DEC 4,rax
    
   
    xor rax, rax
    ret

Ultima modifica 14 Febbraio 2022