// By Daniele Mancuso
// -------------------------------------------------------------- //
//|      ATTUALMENTE IL PROGRAMMA OPERA SU NUMERI NON NEGATIVI   |//
//|--------------------------------------------------------------|//
//|        Divisione intera calcolata mediante ricorsione        |//
//|                         ---                                  |//
//|                        | 0 se m=0 or (m-n)<0                 |//
//|             div(m,n)= <                                      |//
//|                        | 1+div[(m-n),n]                      |//
//|                         ---                                  |//
//|--------------------------------------------------------------|//
//|  Moltiplicazione tra interi  realizzata mediante ricorsione  |//
//|                         ---                                  |//
//|                        | 0 se i=0 or j=0                     |//
//|             mul(i,j)= <                                      |//
//|                        | i+mul[i,(j-1)]                      |//
//|                         ---                                  |//
//|--------------------------------------------------------------|//
//|     Resto della divisione calcolato mediante la formula      |//
//|                                                              |//
//|                     r=mod(m,n)=[m-(n*q)]                     |//
//|                                                              |//
//|      dove q Š il quoziente della divisione tra m ed n        |//
//|______________________________________________________________|//


.constant
        OBJ_REF 50
.end-constant


.method div(m,n)                // -------------------------------------------- //
        LDCW    OBJ_REF         //| Applico il metodo delle sottr. Successive  |//
        ILOAD   m               //| quindi calcolo la differenza tra dividendo |//
        ILOAD   n               //| e divisore, la duplico per poterne control-|//
        ISUB                    //|  lare la negativit… senza eliminare il suo |//
        DUP                     //|  valore dallo stack.  Se tale valore Š non |//
        IFLT    zero            //|   negativo effettuo una nuova iterazione   |//
        ILOAD   n               //|  usandolo come dividendo. Ogni iterazione  |//
        INVOKEVIRTUAL div       //| la cui differenza tra dividendo e divisore |//
        BIPUSH  1               //|  Š non negativa incrementa di 1 il valore  |//
        IADD                    //| in cima allo stack che al termine conterr… |//
        GOTO    fine            //|  il quoziente. L'iterazione termina quando |//
zero:   BIPUSH  0               //|  la differenza (il dividendo) diventa <=0. |//
fine:   IRETURN                 //|   In tal caso il valore restituito Š zero  |//
.end-method                     //|____________________________________________|//


.method mul(i,j)                // -------------------------------------------- //
        LDCW    OBJ_REF         //| Controllo se moltiplicando o moltiplicatore|// 
        ILOAD   j               //|    sono uguali a zero. In tal caso esco    |//
        DUP                     //| immediatamente restituendo zero altrimenti |//
        IFEQ    fine            //| inizio le iterazioni decrementando via via |//
        BIPUSH  1               //|  il moltiplicatore ed eseguendo il metodo  |//
        ISUB                    //|             in modo ricorsivo              |//
        ILOAD   i               //|                                            |//
        DUP                     //|                                            |//
        IFEQ    fine            //|    Il risultato si crea via via nelle      |//
        INVOKEVIRTUAL mul       //| iterazioni sommando il moltiplicando a se  |//
        ILOAD   i               //| stesso tante volte quante Š il valore del  |//
        IADD                    //|  moltiplicatore. Le iterazioni terminano   |//
fine:   IRETURN                 //|     quando quest'ultimo giunge a zero      |//
.end-method                     //|____________________________________________|//


.method mod(q,m,n)              // -------------------------------------------- //
        ILOAD   m               //|                                            |//
        LDCW    OBJ_REF         //|   Tale metodo non ha bisogno di commenti   |//
        ILOAD   n               //|           basta ricordare la formula       |//
        ILOAD   q               //|                                            |//
        INVOKEVIRTUAL mul       //|             r=mod(m,n)=[m-(n*q)]           |//
        ISUB                    //|                                            |//
        IRETURN                 //| dove q Š il quoziente della div. tra m ed n|//
.end-method                     //|____________________________________________|//


.main
.var
        m                       // D I V I D E N D O //
        n                       //  D I V I S O R E  //
        q                       // Q U O Z I E N T E //
        r                       //     R E S T O     //
.end-var
        LDCW    OBJ_REF
        LDCW    OBJ_REF
        IN                      // Carico il dividendo e lo salvo perchŠ mi servir… in //
        DUP                     //  seguito per il calcolo del resto della divisione   //
        ISTORE  m
        IN                      //  Effettuo la stessa operazione per il divisore, ma  //
        DUP                     // controllando che sia anche diverso da zero. In caso //
        ISTORE  n               //  contrario salto al segmento di codice "zero" che   //
        DUP                     // restituir… il valore -1 sia come quoziente che come //
        IFEQ    zero            // resto:risultato non ottenibile in condizioni normali//
        INVOKEVIRTUAL div       //  Se il divisore Š diverso da zero invoco il metodo  //
        DUP                     
        ISTORE  q               //  Conservo il quoziente  della divisione e lo passo  //
        ILOAD   m               //  come parametro, insieme a dividendo e divisore al  //
        ILOAD   n               //        metodo delegato al calcolo del resto         //
        INVOKEVIRTUAL mod
        ISTORE  r
        GOTO    fine
zero:   BIPUSH  -1
        DUP
        ISTORE  q
        ISTORE  r
fine:   ILOAD   q
        OUT                     // OUTPUT QUOZIENTE //
        ILOAD   r
        OUT                     //   OUTPUT RESTO   //
        HALT
.end-main



===========================Altre Proposte====================================

I metodi che eseguono la moltiplicazione e la divisione sono: 

.method  mul(m, n) 
       ILOAD n 
rit:   IINC m  -1 
       ILOAD m 
       IFEQ fine 
       ILOAD n 
       IADD 
       GOTO rit 
fine: IRETURN 
.end-method 

.method div(m,n) 
.var 
i 
.end-var 
       BIPUSH 0 
       ISTORE i 
rit:   ILOAD m 
       ILOAD n 
       ISUB 
       DUP 
       ISTORE m 
       IFLT fine 
       IINC i  1 
       GOTO rit 
fine: ILOAD i 
       IRETURN 
.end-method 


VERSIONI DIFFERENTI:

method  mul(m, n) 
       ILOAD n 
rit:   IINC m  -1 
       ILOAD m 
       IFEQ fine 
       ILOAD n 
       IADD 
       GOTO rit 
fine: IRETURN 
.end-method 

.method div(m,n) 
       BIPUSH 0 
rit:   ILOAD m 
       ILOAD n 
       ISUB 
       DUP 
       ISTORE m 
       IFLT fine 
       BIPUSH 1 
       IADD 
       GOTO rit 
fine: IRETURN 
.end-method 






ho notato che il metodo mul (m,n) se invocato con la
variabile m inizializzata a 0 da risultati errati.
 
Penso che cosi' dovrebbe andare meglio:
 
.method  mul(m, n) 
         ILOAD m 
         IFEQ term
         GOTO iniz
term: BIPUSH 0
         GOTO fine
iniz:   ILOAD n 
rit:     IINC m  -1 
         ILOAD m 
         IFEQ fine 
         ILOAD n 
         IADD 
         GOTO rit 
fine:   IRETURN 
.end-method 

[By Mongelli]

-----------------------

Questo codice rispetto al precedente semplicemente esegue i controlli
su entrambi gli operandi, e secondo me é anche un po' più ordinato.

.method mul (j,k)
     ILOAD J
     DUP
     IFEQ Zero
     ILOAD K
     IFEQ Zero
Loop:IINC K -1
     ILOAD K
     IFEQ End
     ILOAD J
     IADD
     Goto Loop
Zero:BIPUSH 0
End: IRETURN
.end-method

--

Questa versione non ha molto di più rispetto a quella precedente,
semplicemente un controllo sul dividendo. In teoria si dovrebbe fare
anche un controllo sul divisore nel caso in cui sia zero, ma in pratica poi un
metodo deve restituire sempre un valore finito, quindi non ci resta che
presupporre che il divisore sia sempre diverso da zero.

.method div (j,k)
     ILOAD J
     IFEQ Zero
     BIPUSH 0
Loop:ILOAD J
     ILOAD K
     ISUB
     DUP
     ISTORE J
     IFLT End
     BIPUSH 1
     IADD
     GOTO Loop
Zero:BIPUSH 0
End: IRETURN
.end-method


Oppure possiamo fare lo stesso un controllo sul divisore per evitare un
ciclo infinito che bloccherebbe il sistema, e nel caso in cui sia zero far
restituire zero (non é proprio corretto, ma sempre meglio che il blocco
della macchina).

.method div (j,k)
     ILOAD J
     IFEQ Zero
     ILOAD K
     IFEQ Zero
     BIPUSH 0
Loop:ILOAD J
     ILOAD K
     ISUB
     DUP
     ISTORE J
     IFLT End
     BIPUSH 1
     IADD
     GOTO Loop
Zero:BIPUSH 0
End: IRETURN
.end-method

[Giorgio Stampa]
