CALCOLO DEL MASSIMO COMUN DIVISORE Problema: "calcolare il Massimo Comun Divisore (M.C.D.) di due numeri naturali, A e B, secondo l'algoritmo cosiddetto delle sottrazioni successive". L'algoritmo "delle sottrazioni successive" funziona nel modo seguente. Si denoti con (A, B) il M.C.D. dei due numeri naturali A e B. Si hanno allora i tre casi seguenti: Se A è uguale a B, il comune valore di A e B è il loro M.C.D., cioè si ha (A, B) = A = B. Se A è maggiore di B, allora si ha (A, B) = (A B, B). Se A è minore di B, allora si ha (A, B) = (A, B A,). Per esempio: siano A = 60 e B = 42. Chiaramente si dovrebbe avere (A, B) = 6. Applicando l'algoritmo sopra esposto, si ha la catena di passaggi seguente: (A, B) = (60, 42) = (60 42, 42) = (18, 42) = (18, 42 18) = (18, 24) = (18, 24 18) = (18, 6) = (18 6, 6) = (12, 6) = (12 6, 6) = (6, 6) = 6 che è proprio lo M.C.D. di A e B. Ecco una stesura informale dell'algoritmo delle sottrazioni successive. Premessa: l'algoritmo usa esattamente due variabili intere A e B; entrambe sono variabili di ingresso; entrambe funzionano anche come variabili di uscita. 1. Leggi da stdin il numero naturale A 2. Leggi da stdin il numero naturale B 3. Se A è diverso da B, esegui i passi (a), (b) e (c) seguenti, altrimenti saltali e vai direttamente al passo (4): a. Se A è maggiore di B, sottrai B da A. b. Altrimenti, se A è minore di B, sottrai A da B. c. Ritorna al passo (3). 4. Scrivi su stdout il risultato A (o anche B, giacché sono già o sono diventati uguali). Ed eccone il codice C. Informatica 1 - Massimo Comun Divisore pp. 1 / 7
/ calcolo del Massimo Comun Divisore di due numeri naturali / / algoritmo delle sottrazioni successive / int A, B; / numeri interi di cui calcolare il M.C.D. / while (A!= B) { / ogniqualvolta A è diverso da B / if (A > B) { / se A è maggiore di B / A = A B; / sottrai B da A / } else { / altrimenti (cioè se A minore di B) / } / if / B = B A; / sottrai A da B / / nota bene: siccome siamo dentro il corpo del while, è impossibile che A sia uguale a B; il ramo else dello if contempla dunque solo il caso A < B, mentre il caso A == B all'interno del while non ha luogo / / A ora rappresenta il M.C.D. di A e B / printf ("Il M.C.D. vale &d\n", A); / andrebbe bene anche: printf ("Il M.C.D. vale &d\n", B); / Informatica 1 - Massimo Comun Divisore pp. 2 / 7
Problema: "calcolare il Massimo Comun Divisore di due numeri naturali, A e B, secondo il classico algoritmo di Euclide". L'algoritmo di Euclide (II o secolo A.C.) funziona nel modo seguente. Si denoti con (A, B) il M.C.D. dei due numeri naturali A e B, e si supponga che inizialmente A sia maggiore o uguale a B (se così non fosse, basterebbe scambiare A con B). Si hanno allora i due casi seguenti: Se il resto della divisione intera di A rispetto a B è nullo, allora il M.C.D. di A e B è proprio B, cioè si ha (A, B) = B. Altrimenti, il M.C.D. di A e B coincide con il M.C.D. di B e del resto della divisione intera di A rispetto a B, cioè si ha (A, B) = (B, A % B). Per esempio: siano A = 60 e B = 42; si noti come sia vero che A B. Chiaramente si dovrebbe avere (A, B) = 6. Applicando l'algoritmo di Euclide, si ha la catena di passaggi seguente: (A, B) = (60, 42) = (42, 60 % 42) = (42, 18) = (18, 42 % 18) = (18, 6), e siccome si ha 18 % 6 = 0, allora 6 è proprio lo M.C.D. di A e B. La dimostrazione della correttezza di questo celeberrimo algoritmo si trova in qualsiasi testo di aritmetica elementare. Essa fu data da Euclide circa il secondo secolo A.C. Si noti come l'algoritmo di Euclide sia molto più rapido dell'algoritmo delle sottrazioni successive. Esempio drastico: Algoritmo delle sottrazioni successive: (100, 1) = (99, 1) = (98, 1) = (si va avanti per 99 sottrazioni!) = (2, 1) = (1, 1) = 1 Algoritmo di Euclide: (100, 1), e siccome si ha 100 % 1 = 0, si sa subito che (100, 1) = 1 Un altro esempio: Algoritmo delle sottrazioni successive: (100, 15) = (85, 15) = (70, 15) = = (25, 15) = (10, 15) = (10, 5) = (5, 5) = 5 Algoritmo di Euclide: (100, 15) = (15, 10) = (10, 5) e siccome si ha 10 % 5 = 0, si ha che (100, 15) = 5 L'algoritmo di Euclide è dunque molto più efficiente di quello delle sottrazioni successive. Ecco una prima stesura informale dell'algoritmo di Euclide. Premessa: l'algoritmo usa almeno due variabili intere A e B; sono entrambe variabili di ingresso; B funziona anche da variabile di uscita. 1. Leggi da stdin il numero naturale A. 2. Leggi da stdin il numero naturale B. 3. Se A è minore di B, scambia i valori di A e B. 4. Se il resto della divisione intera di A rispetto a B non è nullo, esegui i passi (a), (b) e (c) seguenti, altrimenti saltali e vai direttamente al passo (5): a. Sostituisci il valore di B con quello del resto della divisione intera di A rispetto a B. b. Sostituisci il valore di A con il vecchio valore di B (cioè il valore che B aveva prima del passo (a)). c. Ritorna al passo (3). 5. Scrivi su stdout il risultato B. Informatica 1 - Massimo Comun Divisore pp. 3 / 7
Ecco una seconda stesura informale dell'algoritmo di Euclide, più dettagliata. Premessa: l'algoritmo usa esattamente tre variabili intere A, B e B'; A e B sono variabili di ingresso, B' è una variabile ausiliaria; B funziona anche come variabile di uscita. 1. Leggi da stdin il numero naturale A. 2. Leggi da stdin il numero naturale B. 3. Se A è minore di B, esegui i passi (a), (b) e (c) seguenti, altrimenti saltali e vai direttamente al passo (4): a. Salva temporaneamente il valore di B in una variabile ausiliaria B'. b. Assegna a B il valore di A. c. Assegna ad A il valore salvato nella variabile ausiliaria B'. 4. Se il resto della divisione intera di A rispetto a B non è nullo, esegui i passi (a), (b), (c) e (d) seguenti, altrimenti saltali e vai direttamente al passo (5): a. Salva temporaneamente il valore di B in una variabile ausiliaria B'. b. Assegna a B il risultato dell'espressione seguente: il resto della divisione intera di A rispetto a B. c. Assegna ad A il valore di B'. d. Ritorna al passo (4). 5. Scrivi su stdout il risultato B. Ed eccone il codice C. Informatica 1 - Massimo Comun Divisore pp. 4 / 7
/ calcolo del Massimo Comun Divisore di due numeri naturali / / Algoritmo di Euclide / int A, B, B1; / variabili del programma / if (A < B) { / scambia A con B / B1 = B; / assegna (salva) B a B1 / B = A; / assegna A a B / A = B1; / assegna B1 ad A / } / if / / scambio effettuato / while (A % B!= 0) { / ogniqualvolta A % B è diverso da 0 / B1 = B; / assegna (salva) B a B1 / B = A % B; / assegna A % B a B / A = B1; / assegna B1 ad A / / B ora rappresenta il M.C.D. di A e B / printf ("Il M.C.D. vale &d\n", B); Informatica 1 - Massimo Comun Divisore pp. 5 / 7
Come di vede, nella condizione del ciclo viene eseguito un calcolo di resto di divisione, che figura anche all'interno del corpo del ciclo. Si può eliminare questo doppione di calcolo, che è inefficiente, nel modo seguente. / calcolo del Massimo Comun Divisore di due numeri naturali / / Algoritmo di Euclide - con ottimizzazione di codifica / int A, B, B1; / variabili del programma / if (A < B) { / scambia A con B / B1 = B; / assegna (salva) B a B1 / B = A; / assegna A a B / A = B1; / assegna B1 ad A / } / if / / scambio effettuato / B1 = A % B; / assegna A % B a B1 / while (B1!= 0) { / ogniqualvolta B1 è diverso da 0 / A = B; / assegna B ad A / B = B1; / assegna B1 a B / B1 = A % B; / assegna A % B a B1 / / B ora rappresenta il M.C.D. di A e B / printf ("Il M.C.D. vale &d\n", B); Provare a simulare la nuova versione, ottimizzata, dell'algoritmo di Euclide! Infine, pensandoci un po' si vede che l'eventuale scambio iniziale dei valori A e B non è necessario, in quanto l'algoritmo stesso lo esegue automaticamente se A < B. Si ha pertanto il seguente codice C, ulteriormente ottimizzato. Informatica 1 - Massimo Comun Divisore pp. 6 / 7
/ calcolo del Massimo Comun Divisore di due numeri naturali / / Algoritmo di Euclide - con nuove ottimizzazioni / int A, B, R; / variabili del programma / R = A % B; / assegna A % B a R / while (R!= 0) { / ogniqualvolta R è diverso da 0 / A = B; / assegna B ad A / B = R; / assegna R a B / R = A % B; / assegna A % B a R / / B ora rappresenta il M.C.D. di A e B / printf ("Il M.C.D. vale &d\n", B); Provare a simulare anche questa nuova versione, meglio ottimizzata, dell'algoritmo di Euclide! E il Minimo Comune Multiplo? Come esercizio, provare a progettare l'algoritmo. Informatica 1 - Massimo Comun Divisore pp. 7 / 7