errore := function (arg) ## Riporta un messaggio di errore o informazione, senza ritornare ## Messaggio di default molto utile local TESTO; if Length(arg) > 0 then TESTO := arg[1]; else TESTO := "Very useful error message\n"; fi; Print(TESTO, "\n"); return; end; errore(""); errore("# Qui vediamo tre versioni dell'algoritmo di Euclide"); errore("# per il calcolo del massimo comun divisore di due numeri"); errore(""); errore("# La prima *MCDlento* fa solo il MCD,"); errore("# ma racconta ogni divisione che sta facendo"); errore("# La seconda *MCD* è meno verbosa,"); errore("# ma calcola anche i coefficienti della combinazione lineare"); errore(""); errore("# La terza *MCDcompleto*,"); errore("# fa proprio tutto, vedere per credere"); errore(""); MCDlento := function ( a, b) # Con questo comando sto definendo una funzione, che si chiama "MCDlento", # che si applica a due numeri a, b local r, numeroDiDivisioni; # All'interno di questa funzione voglio usare una variabile "r" per il resto, # e devo dirlo qui # Uso anche la variabile numeroDiDivisioni per tener conto di quel che dice il suo nome numeroDiDivisioni := 0; a := AbsInt(a); b := AbsInt(b); # Sostituisco a e b con i loro valori assoluti, tanto per il MCD # non cambia niente, come abbiamo visto in un esercizio while b > 0 do # il comando "while ... do" (che si chiude più sotto, con "od") # continua a ripetere le istruzioni fra qui e "od", finché si ha b > 0, # poi passa all'istruzione successiva numeroDiDivisioni := numeroDiDivisioni + 1; # ogni volta che faccio una divisione ne tengo conto r := EuclideanRemainder (a, b); # Ora r è il resto della divisione di a per b, divisione che posso fare # perché se sono qui, vuol dire che b > 0 Print("Ho diviso ", a, " per ", b, " e il resto è ", r, " (Divisione #", numeroDiDivisioni, ")\n"); # Questo comando "Print" serve solo a seguire cosa sta facendo il programma # man mano che ripete "while ... do od". a := b; b := r; # Avevo cominciato con a, b, ora butto via a, e lo rimpiazzo con r # dunque continuo con b, r od; # Questa è la fine del "while ... do". # Esco da "while ... do od" quando b = 0, # dunque il massimo comun divisore è a Print("Il massimo comun divisore è ", a, ", e ci sono volute ", numeroDiDivisioni, " divisioni\n"); # Annuncio il risultato return a; # e questo comando riporta "a" come risultato end; MCD := function (a, b) # Questa è una versione più completa, che calcola anche i coefficienti della combinazione lineare # Qui i commenti sono più radi local aorig, borig, segnoa, segnob, r, q, c11, c12, c21, c22, d1, d2; c11 := 1; c12 := 0; c21 := 0; c22 := 1; aorig := a; borig := b; segnoa := SignInt(a); segnob := SignInt(b); a := AbsInt(a); b := AbsInt(b); # Sostituisco a e b con i loro valori assoluti, tanto per il MCD # non cambia niente, come abbiamo visto in un esercizio # Stavolta però tengo conto dei valori originali di a e b, # e anche del loro segno, tutte cose che ci serviranno dopo. while b > 0 do r := EuclideanRemainder(a, b); q := EuclideanQuotient (a, b); # Qui devo tener conto anche del quoziente a := b; b := r; d1:= c11 - c21 * q; d2:= c12 - c22 * q; c11:= c21; c12 := c22; c21:= d1; c22 := d2; od; Print("Il massimo comun divisore fra ", aorig, " e ", borig, " è ", a, ", e si ha:\n"); Print(a, " = ", aorig, " * (", segnoa * c11, ") + ", borig, " * (", segnob * c12, ")\n"); # Si spiega il risultato return [a,c11, c12]; #Qui restituisco sia il MCD a, che i coefficienti della combinazione lineare end; MCDcompleto := function ( a, b) # Con questo comando sto definendo una funzione, che si chiama "MCDcompleto", # che si applica a due numeri a, b # Attenzione, i commenti non sono (ancora) aggiornati!! local aorig, borig, segnoa, segnob, r, q, c11, c12, c21, c22, d1, d2, numeroDiDivisioni; # All'interno di questa funzione voglio usare una variabile "r" per il resto, # e devo dirlo qui # Uso anche la variabile numeroDiDivisioni per tener conto di quel che dice il suo nome numeroDiDivisioni := 0; c11 := 1; c12 := 0; c21 := 0; c22 := 1; aorig := a; borig := b; segnoa := SignInt(a); segnob := SignInt(b); a := AbsInt(a); b := AbsInt(b); # Sostituisco a e b con i loro valori assoluti, tanto per il MCD # non cambia niente, come abbiamo visto in un esercizio # I segni in realtà non servono Print("Combinazione #-1: ", a, " * 1 + ", b, " * 0 = ", a, "\n"); Print("Combinazione #0: ", a, " * 0 + ", b, " * 1 = ", b, "\n"); while b > 0 do # il comando "while ... do" (che si chiude più sotto, con "od") # continua a ripetere le istruzioni fra qui e "od", finché si ha b > 0, # poi passa all'istruzione successiva numeroDiDivisioni := numeroDiDivisioni + 1; # ogni volta che faccio una divisione ne tengo conto r := EuclideanRemainder (a, b); q := EuclideanQuotient (a, b); # Ora r è il resto della divisione di a per b, divisione che posso fare # perché se sono qui, vuol dire che b > 0 # Qui devo tener conto anche del quoziente Print("Divisione #", numeroDiDivisioni, ": ", a, " = ", b, " * ", q, " + ", r, "\n"); # Questo comando "Print" serve solo a seguire cosa sta facendo il programma # man mano che ripete "while ... do od". a := b; b := r; # Avevo cominciato con a, b, ora butto via a, e lo rimpiazzo con r # dunque continuo con b, r d1:= c11 - c21 * q; d2:= c12 - c22 * q; c11:= c21; c12 := c22; c21:= d1; c22 := d2; # Aggiorno i coefficienti della combinazione lineare if r > 0 then Print("Combinazione #", numeroDiDivisioni, ": ", aorig, " * (", d1, ") + ", borig, " * (", d2, ") = ", b, "\n"); fi; # E ne annuncio lo stato corrente od; # Questa è la fine del "while ... do". # Esco da "while ... do od" quando b = 0, # dunque il massimo comun divisore è a Print("Il massimo comun divisore è ", a, ",\n ci sono volute ", numeroDiDivisioni, " divisioni,", "\n e la combinazione lineare è:\n", aorig, " * (", c11, ") + ", borig, " * (", c12, ") = ", a, "\n"); # Annuncio il risultato in forma completa return; # Nessun valore viene riportato dalla funzione, questo programma parla solamente end; MCDgenerico := function ( a, b) # Con questo comando sto definendo una funzione, che si chiama "MCDcompleto", # che si applica a due numeri a, b # Attenzione, i commenti non sono (ancora) aggiornati!! local aorig, borig, segnoa, segnob, r, q, c11, c12, c21, c22, d1, d2, numeroDiDivisioni; # All'interno di questa funzione voglio usare una variabile "r" per il resto, # e devo dirlo qui # Uso anche la variabile numeroDiDivisioni per tener conto di quel che dice il suo nome numeroDiDivisioni := 0; c11 := 1; c12 := 0; c21 := 0; c22 := 1; aorig := a; borig := b; ##segnoa := SignInt(a); segnob := SignInt(b); ##a := AbsInt(a); b := AbsInt(b); # Sostituisco a e b con i loro valori assoluti, tanto per il MCD # non cambia niente, come abbiamo visto in un esercizio # I segni in realtà non servono Print("Combinazione #-1: ", a, " * 1 + ", b, " * 0 = ", a, "\n"); Print("Combinazione #0: ", a, " * 0 + ", b, " * 1 = ", b, "\n"); while b <> 0 do # il comando "while ... do" (che si chiude più sotto, con "od") # continua a ripetere le istruzioni fra qui e "od", finché si ha b > 0, # poi passa all'istruzione successiva numeroDiDivisioni := numeroDiDivisioni + 1; # ogni volta che faccio una divisione ne tengo conto r := EuclideanRemainder (a, b); q := EuclideanQuotient (a, b); # Ora r è il resto della divisione di a per b, divisione che posso fare # perché se sono qui, vuol dire che b > 0 # Qui devo tener conto anche del quoziente Print("Divisione #", numeroDiDivisioni, ": ", a, " = ", b, " * ", q, " + ", r, "\n"); # Questo comando "Print" serve solo a seguire cosa sta facendo il programma # man mano che ripete "while ... do od". a := b; b := r; # Avevo cominciato con a, b, ora butto via a, e lo rimpiazzo con r # dunque continuo con b, r d1:= c11 - c21 * q; d2:= c12 - c22 * q; c11:= c21; c12 := c22; c21:= d1; c22 := d2; # Aggiorno i coefficienti della combinazione lineare if r <> 0 then Print("Combinazione #", numeroDiDivisioni, ": ", aorig, " * (", d1, ") + ", borig, " * (", d2, ") = ", b, "\n"); fi; # E ne annuncio lo stato corrente od; # Questa è la fine del "while ... do". # Esco da "while ... do od" quando b = 0, # dunque il massimo comun divisore è a Print("Il massimo comun divisore è ", a, ",\n ci sono volute ", numeroDiDivisioni, " divisioni,", "\n e la combinazione lineare è:\n", aorig, " * (", c11, ") + ", borig, " * (", c12, ") = ", a, "\n"); # Annuncio il risultato in forma completa return; # Nessun valore viene riportato dalla funzione, questo programma parla solamente end;