MC - SCHEDA 8 [schede: 1 2 3 4 5 6 7 8] [indice schede]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Matematica finita (combinazioni, complessità computazionale, ordinamento di
dati, teoria dei numeri)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Indice:
8.0 Premessa
8.1 Effetti combinatori (scelta di percorsi, moltiplicazione di matrici)
e complessità computazionale
es.1 es.2 es.3
8.2 Ricorsione. Algoritmi di ordinamento
es.4 es.5
8.3 Teoria dei numeri. Crittografia.
es.6 es.7
8.4 Commenti agli esercizi
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
===== 8.0 ==================== [inizio scheda]
In questa scheda sono affrontate, mediante alcuni esempi, aree matematiche
relativamente alle quali i rapporti col computer assumono alcune caratteri-
stiche diverse rispetto alle aree considerate in precedenza, e che in genere
sono poco presenti nel curricolo universitario di un insegnante di matemati-
ca. Il taglio della scheda sarà più "a livello adulto". Per alcuni
approfondimenti didattici che coinvolgono concetti di analisi (limite,
successioni, ...) e di probabilità e statistica (generatore di numeri
casuali, impieghi del calcolo combinatorio, analisi di dati sperimentali,...)
rinviamo ai materiali (schede di lavoro e software) "L'insegnamento della
Analisi Matematica" e "Probabilità, Statistica ed elaborazione automatica
delle informazioni".
===== 8.1 ==================== [inizio scheda]
Iniziamo affrontando direttamente alcuni esercizi.
** ES.1 *******
1) Apri (da MC) il programma QBasic PERCORSO.bas che serve per risolvere il
problema di trovare il percorso di minima percorrenza con cui si puo` passare
per un certo numero di localita`. Esamina i commenti in testa al listato del
programma ed esegui il programma. (l'istruzione DATA consente di incorporare
un file di dati all'interno del listato del programma stesso, file che viene
letto dall'istruzione READ)
2) In problemi di questo genere, in cui e` inevitabile eseguire molti calco-
li e molti confronti (una opportuna strategia puo` ridurli o facilitarli, ma
solo fino a un certo punto) e` decisivo il ruolo del computer.
Quanti sarebbero stati i percorsi possibili se vi fosse stata un'ulteriore
localita` da toccare?
E se le localita` fossero state N?
3) E` facile modificare il programma per estenderlo al caso di N localita`,
comunque si fissi N. Il tempo di calcolo, t(N), pero` cresce notevolmente
all'aumentare di N. La funzione N -> t(N) ha andamento lineare, polinomiale
o esponenziale (cioe` esistono F e G lineari/polinomiali/esponenziali t. c.
F(N) <= t(N) <= G(N)) ?
******* END es.1 ** [commenti]
** ES.2 *******
Consideriamo l'algoritmo per moltiplicare due matrici, che e` utilizzato
all'interno di Derive e del programma Matr considerati nella scheda 7.
Vogliamo esaminare come cresce il tempo di calcolo all'aumentare delle
dimensioni delle matrici. Il programma MOLTMATR.bas ci consente di fare
cio`. Apriamolo senza uscire dal QBbasic.
1) Il programma consente di misurare il tempo t(N) (in centesimi di secondi)
impiegato dal computer in uso per calcolare il prodotto tra due generiche
matrici quadrate di ordine N. Esamina dall'help le informazioni relative alla
funzione (non alla istruzione) TIMER e alla funzione RND.
2) Prova a trovare un modo per ricavare sperimentalmente qual e` l'andamento
di N -> t(N).
3) Come puoi stimare quanto valgono t(100) e t(200)?
4) Congetturato sperimentalmente l'andamento, confronta questa congettura con
quanto puoi dedurre analizzando direttamente l'algoritmo (in particolare il
sottoprogramma MOLT: -> menu Visualizza, opzione SUBs).
******* END es.2 ** [commenti]
Con un particolare computer si sono ottenuti per il programma dell'es.
precedente t: 10->6, 20->16, 25->33, 30->60, 40->125, 45->180, 50->247,
55->24, 60->423
t(20)/t(10)=3, t(40)/t(20)=7.8, t(50)/t(25)=7.5, ...
t(2N)/t(N) tende ad essere circa 8 (=2^3); ciò ci fa ritenere che l'andamen-
to sia polinomiale, di grado 3 (la parte principale è il temine di grado 3,
per cui t(N) tende a comportarsi come N^3).
Una analisi più accurata e` fattibile esaminando la pendenza di t(N):
se t(N) e` un polinomio di grado J la sua pendenza di passo h e` un polinomio
di grado J-1 (come e` facile verificare con semplici manipolazioni algebriche
per J fissato: prova a farlo).
Se calcolando ripetutamente la pendenza a partire dai dati sperimentali
prima o poi si arriva a una sequenza di dati presso che costante si puo` dire
che l'andamento e` polinomiale e se ne puo` individuare il grado; se le nuove
successioni di dati man mano ottenute continuano a crescere piu` o meno allo
stesso modo, si puo` concludere che l'andamento e` esponenziale.
** ES.3 *******
1) Entra in GRAFUN e, scelta la finestra A, introduci (Graf-PuntiCongiunti)
le coppie (N,t(N)) di cui sopra e registrale come Dat1.
Quindi esamina il punto 46 dell'help (su PEND e su XYLOG) e trasforma Dat1
in Dat2 contenente la "pendenza" di Dat1, e analogamente Dat2 in Dat3 (pen-
denza di Dat2) e Dat3 in Dat4 (pendenza di Dat3).
Trasforma anche Dat1 in Dat9 contenente il trasformato bilogaritmico di
Dat1.
Quindi rappresenta in scala automatica Dat1 nella finestra A, Dat2 in B,
Dat3 in C e Dat4 in D. Che cosa puoi dedurre dai loro andamenti?
2) Rappresenta Dat9 in D in scala automatica. Ha andamento pressocche' linea-
re: che cosa puoi dedurne?
Prova a individuare una funzione lineare F che tenda ad approssimare
questi dati.
3) Prova a dedurre da quanto trovato in 3) una approssimazione di t(N).
******* END es.3 ** [commenti]
Il problema della complessita` computazionale e` uno dei problemi piu`
attuali di ricerca (di matematici e informatici): come far fronte ai fenomeni
di "esplosione combinatoria".
Si tratta di un argomento che, anche nell'insegnamento secondario
superiore, come si può capire dagli esempi visti sopra, offre motivazioni
per la introduzione e l'uso significativo di vari concetti matematici,
occasioni per attivita` che collegano diverse aree matematiche e
informatiche, ...
===== 8.2 ==================== [inizio scheda]
Prima di proseguire leggi le voci Successioni e Calcolo Combinatorio degli
Oggetti Matematici.
** ES.4 *******
1) Definisci F(x)=x^3, G(x)=@F(x) (in Grafun @F e` il fattoriale) e H(x)=2^x
e traccia (nella finestra totale T) il grafico di F per input interi (batti
fi, invece che solo f, alla domanda "F, G, ... ?") in scala automatica tra 0
e 10 e poi, in scala invariata, quelli (per input interi) di G e H. Che cosa
puoi osservare?
2) Utilizzando il fattoriale si possono definire il coefficiente binomiale
e altre funzioni combinatorie. Vediamo come effettuare questi calcoli diret-
tamente con un linguaggio di programmazione.
Esegui ed esamina i programmi CBIN1.bas, CBIN2.bas e CBIN3.bas.
Per ciascuno cerca di individuare (sperimentalmente e teoricamente) la com-
plessita` temporale.
CBIN2.bas offre un esempio di sottoprogramma RICORSIVO.
******* END es.4 ** [commenti]
Un problema di cui e` importante valutare la complessita` temporale e` quello
dell'ordinamento dei dati (interessa l'archiviazione e la trattazione stati-
stica delle informazioni).
** ES.5 *******
1) Esamina il programma ORDIN.bas, cerca di comprendere come funzionano i tre
algoritmi di ordinamento contenuti (per minimizzazione, per inserzione,
per fusione) osservando la dimostrazione animata e analizzando i commenti dei
vari sottoprogrammi.
Valutane la complessita` computazionale, cercando di capire se i diversi
algoritmi hanno differenze di comportamento a seconda di come sono disposti
i dati (cioe` se hanno casi ottimi e pessimi).
(nel caso di dati introdotti a caso, la scelta del "seme" consente di genera-
re una particolare successione di numeri; scegliendo lo stesso seme la stessa
successione di dati puo` essere sottoposta a un altro algortimo)
2) In una situazione in cui si abbia a che fare con una grande banca di dati
in cui periodicamente vengono introdotte ulteriori quantita` di dati (e che
in tale occasione viene riordinata) quale algoritmo conviene?
(In MC e` presente anche una versione piu` bella esteticamente, ma meno
efficace per la comprensione degli algoritmi: dimordin.bas)
******* END es.5 ** [commenti]
===== 8.3 ==================== [inizio scheda]
Il computer consente di affrontare con tecniche nuove vari problemi aritmeti-
ci.
** ES.6 *******
1) Osserva ed esegui il programma TERNE.bas per generare terne pitagoriche.
L'esistenza delle terne pitagoriche ha indotto, generalizzando, ad altri
problemi, come quello noto come Ultimo Teorema di Fermat (n intero, n>2 ->
x^n+y^n=z^n non ha soluzioni tra gli interi positivi), dimostrato nel 1994.
Eulero aveva congetturato (nel 1778) piu` in generale che, se A e` intero po-
sitivo, A^N non puo` espressa come la somma di meno di N potenze di interi
positivi. Fino agli anni 60 si supponeva che questa congettura fosse vera,
e si era in cerca di una dimostrazione.
Lo sviluppo dei computer ha consentito di affrontare in modo nuovo il proble-
ma. Con un computer si possono calcolare molte somme di potenze velocemente
e si puo` o rafforzare la "supposizione" che la congettura sia vera o indi-
viduare un controesempio che ne mostri la falsita`.
Usa il programma Eulero.bas per determinare il controesempio individuato nel
1966 (riferendosi al caso N=5) ponendo fine alle ricerche di dimostrazioni
di questa versione generalizzata dell'ultimo teorema di Fermat.
2) Usa il programma Goldbach.bas, per studiare la congettura (di Goldbach)
che ogni numero pari maggiore di 2 sia la somma di due numeri primi diversi.
Il computer, finora, ha confermato questa congettura (ma non se ne ha una
dimostrazione: potrebbe prima o poi trovarsi un controesempio, anche se tutto
lascia supporre che la congettura sia vera ...)
******* END es.6 ** [commenti]
Un ultimo esempio, che mette in luce i collegamenti con i problemi di
CRITTOGRAFIA.
** ES.7 *******
Usa e analizza il programma CODSEGR.bas.
Prova a modificarlo in modo da rendere più difficile la scoperta
del procedimento di codifica.
Come potresti usare RND per una codifica più "segreta" (esamina
la funzione RANDOMIZE).
Lo studio di quali concetti matematici si presta a collegamenti con
questa problematica?
******* END es.7 ** [commenti]
===== 8.4 ==================== [inizio scheda]
**** Su alcuni quesiti: ****
** Su Es.1
Qui sotto è riprodotto Percorso.bas:
' Programma per determinare un percorso di minima percorrenza per passare
'per Torino, Como, Pavia, Brescia, Bologna partendo da e ritornando a Genova.
' Nella tabella sono indicate le distanze chilometriche, che vengono messe
'nella variabile indiciata d(.,.)
' Il percorso - che viene memorizzato nella variabile indiciata a(.) -
'viene espresso indicando le localita` con numeri: 1 per Genova, 2 per Torino,
'3 per Como, ...
PRINT
posti = 6
FOR i = 1 TO posti: FOR j = 1 TO posti
READ d(i, j)
NEXT: NEXT
' GE TO CO PV BS BO
DATA 0,170,185,125,230,295 : 'GE
DATA 170, 0,165,155,225,330 : 'TO
DATA 185,165, 0, 85,110,260 : 'CO
DATA 125,155, 85, 0,135,200 : 'PV
DATA 230,225,110,135, 0,190 : 'BS
DATA 295,330,260,200,190, 0 : 'BO
min = 100000: p = 0
i = 1
FOR j = 2 TO posti
FOR k = 2 TO posti
IF k <> j THEN
FOR l = 2 TO posti
IF l <> j AND l <> k THEN
FOR m = 2 TO posti
IF m <> j AND m <> k AND m <> l THEN
FOR n = 2 TO posti
IF n <> j AND n <> k AND n <> l AND n <> m THEN
d = d(i, j) + d(j, k) + d(k, l) + d(l, m) + d(m, n) + d(n, i)
p = p + 1
IF d <= min THEN min = d: a(1)= i: a(2)= j: a(3)= k: a(4)= l: a(5)= m: a(6)= n
END IF
NEXT
END IF
NEXT
END IF
NEXT
END IF
NEXT
NEXT
PRINT
PRINT "n.percorsi possibili ="; p
PRINT "percorso con percorrenza minima: ";
FOR i = 1 TO posti: PRINT a(i); : NEXT: PRINT a(1)
PRINT "percorrenza ="; min; "km"
Si ottiene:
n.percorsi possibili = 120
percorso con percorrenza minima: 1 4 6 5 3 2 1
percorrenza = 960 km
Il programma calcola la lunghezza di tutti i percorsi possibili, quindi
t(N) cresce come il numero di questi, ossia come N!.
N! cresce esponenzialmente. Infatti 2^(N-1) < N! = N*(N-1)*...*2*1 < N^N
(se N>2). Anzi, N! > Int(N/2) ^ Int(N/2) (se N>1): cresce più velocemente
di A^N comunque si prenda A.
(sono chiamate ESPONENZIALI le funzioni del tipo N -> h^N con hgt;1 e piu` in
generale quelle del tipo N -> G(N)^N per cui esistano K intero e hgt;1 tali
che per ogni N > k si abbia G(N) >= h)
** Su Es.2
1) Ecco MoltMatr.bas:
nmax = 60: DIM A(nmax, nmax), B(nmax, nmax)
Via:
PRINT "ordine max="; nmax
FOR i = 1 TO nmax: FOR j = 1 TO nmax: A(i, j) = RND: NEXT: NEXT
10
INPUT ; "ordine"; n
IF n > nmax THEN PRINT " -->> "; : GOTO Via
t1 = TIMER
MOLT A(), A(), B(), n, n, n
t2 = TIMER
PRINT TAB(15); FIX((t2 - t1) * 100); "(sec/100)"
GOTO 10
SUB MOLT (A(), B(), c(), m, h, n) STATIC
' c() è la matrice m*n prodotto di a() m*h per b() h*n
FOR i% = 1 TO m: FOR j% = 1 TO n
c = 0
FOR k% = 1 TO h: c = c + A(i%, k%) * B(k%, j%): NEXT
c(i%, j%) = c
NEXT j%, i%
END SUB
2) Un modo semplice per studiare l'andamento di t(n) è vedere come varia
t(n) al raddoppiare di n. Su un po' di esempi (vedi i dati riprodotti sotto)
si può osservare che tende a moltiplicarsi circa per 8. Quindi t(n) cresce
circa cubicamente. Altri metodi (riferibili ai dati riptodotti a destra,
da cui si capisce subito che l'andamento è più che lineare) sono
presentati in es.3.
ordine? 6 0 (sec/100) ordine? 10 6 (sec/100)
ordine? 12 5 (sec/100) ordine? 15 5 (sec/100)
ordine? 24 27 (sec/100) ordine? 20 16 (sec/100)
ordine? 48 219 (sec/100) ordine? 25 33 (sec/100)
ordine? 30 60 (sec/100)
ordine? 35 82 (sec/100)
ordine? 40 125 (sec/100)
ordine? 45 180 (sec/100)
ordine? 50 247 (sec/100)
ordine? 55 324 (sec/100)
ordine? 60 423 (sec/100)
3) Se per t(50) trovi ad es. 2.5 sec puoi stimare in 2.5*8= 20 sec t(100)
e in 160 sec (quasi 3 min) t(200).
4) Vengono effettuate circa m*n*h moltiplicazioni, addizioni, assegnazioni
e incrementi dei contatori. Per m=h=n=N, questo numero e` N^3.
** Su Es.3
1) Sotto sono rappresentati Dat1, Dat2, Dat3, Dat4 e Dat 9.
Si vede che al 3° passaggio alle pendenze si ottiene un grafico che
oscilla attorno a un certo valore. Le oscillazioni sono notevoli, a casua
della perdita di precisione che man mano aumenta facendo le differenze. Si
potrebbero fare prove per N maggiori per avere più cifre significative
e stime più precise. Comunque possiamo osservare che si è riusciti
ad abbattere l'andamento dei grafici. Il fenomeno dovrebbe quindi crescere
come N^h, con h pari circa a 3.
2) Se F(x) = ux^s+g(x) con g(x) infinito per x->INF di ordine inferiore,
se rappresento (Log(x),Log(y)), questa relazione, per x->INF, tende a confon-
dersi con (Log(x),Log(u)+s*Log(x)), cioe`, scrivendo X al posto di Log(x),
con (X,Log(u)+s*X), cioe` con una relazione lineare. La pendenza s e` l'espo-
nente della parte principale di F(x). Nel caso del nostro Dat9 dal grafico
si ha che s e` circa 3, a conferma dell'andamento cubico.
3) Cercando q tale che x -> q+3x approssimi il trasformato bilogaritmico,
cioe` q che approssimi Log(u), si trova (per tentativi o individuando due
punti della retta che approssima i dati - vedi figura) q = -2.8. Quindi u =
10^Log(u) = 10^-2.8 = 0.0016 = 0.002 circa.
In alternativa, compreso che l'andamento è cubico, possiamo eguagliare t(60)
ad u*60^3 e dedurne, con più precisone, u=0.00196.
Se si traccia il grafico di F si trova che i punti sperimentali sono in
buon accordo con esso. Ma una stima precisa del valore di u, ossia del
coefficiente direttivo di t(N), non è molto significativa. Un impiego dello
stesso computer in momenti diversi (a seconda di quanto esso è "impegnato")
puo' dar luogo ad andamenti diversi (ma comunque cubici, nell'ambito della
stessa sessione d'uso del programma).
** Su Es.4
1) I grafici mettono in luce il fatto gia` osservato che il fattoriale
cresce piu` velocemente di 2^N.
2) Ecco CBIN1.bas:
DEFDBL A-Z
PRINT
10 INPUT ; " n (<90)"; n: IF n <= 90 THEN GOTO 10
DIM c(n, n)
t = TIMER
FOR i = 0 TO n: c(i, 0) = 1: c(i, i) = 1: NEXT
FOR i = 2 TO n: FOR j = 1 TO i - 1
c(i, j) = c(i - 1, j - 1) + c(i - 1, j)
NEXT: NEXT
PRINT " t ="; INT((TIMER - t) * 100);
IF n < 11 THEN INPUT "stampo triangolo"; risp ELSE risp = 0: PRINT
IF risp = 1 THEN
FOR i = 0 TO n: FOR j = 0 TO i
PRINT TAB(j * 5 + 1); c(i, j);
NEXT: PRINT : NEXT
END IF
ERASE c
GOTO 10 Il triangolo (per n=10):
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
1 10 45 120 210 252 210 120 45 10 1
CBIN2.bas:
DECLARE SUB cbin (n!, k!, c!)
PRINT
10
INPUT "n,k"; n, k
t = TIMER
cbin n, k, c
PRINT c,
PRINT "t="; (TIMER - t) * 100
GOTO 10
SUB cbin (n, k, c)
IF k = n OR k = 0 THEN c = 1: EXIT SUB
cbin n - 1, k - 1, a
cbin n - 1, k, c
c = a + c
END SUB
CBIN3.bas:
...
SUB cbin (n, k, c)
c = 1
FOR i = 1 TO k
c = c * (n - i + 1) / i
NEXT
END SUB
Per CBIN1 (che mette in C(.,.) tutti i coefficienti binomiali) con un
particolare PC si ottiene t(44)=10, t(88)=39. Al raddoppiare di N t quadru-
plica. Quindi il tempo cresce come N^2. La cosa era del resto ovvia: i valori
calcolati crescono come l'"area" del triangolo, che ha base e altezza propor-
zionali a N, quindi come N^2. In modo piu` pedestre: gli elementi del trian-
golo sono 1+2+3+..+(N+1) = (1+N+1)*(N+1)/2 = N^2/2+...
CBIN2 calcola il coeff. bin. in modo ricorsivo: usa la stessa idea impiega-
ta in CBIN1 ma lascia al programma il calcolo dei valori: il sottoprogramma
Cbin richiama se stesso piu` volte procedendo cosi`:
1) se e` richiesto C(4,2) si predispone a calcolare C(3,1) e C(3,2)
2) per calcolare C(3,1) si predispone a calcolare C(2,0) e C(2,1)
3) C(2,0) sa che vale 1
4) per calcolare C(2,1) si predispone a calcolare C(1,0) e C(1,1)
5) C(1,0) sa che vale 1
6) C(1,1) sa che vale 1
7) quindi (con 5 e 6) calcola C(2,1) = C(1,0)+C(1,1)
8) quindi (con 3 e 7) calcola C(3,1) = C(2,0)+C(2,1)
8) per calcolare C(3,2) si predispone a calcolare C(2,1) e C(2,2)
9) per calcolare C(2,1) si predispone a calcolare C(1,0) e C(1,1)
10) C(1,0) sa che vale 1
11) C(1,1) sa che vale 1
12) quindi (con 10 e 11) calcola C(2,1)
13) C(2,2) sa che vale 1
14) quindi (con 12 e 13) calcola C(3,2)
15) quindi (con 8 e 14) calcola C(4,2)
I rientri utilizzati nella descrizione precedente danno una idea delle
chiamate di Cbin che man mano si inscatolano l'una nell'altra.
Quando il programma arriva a situazioni come 3) o 5) e 6), cioe` quando il
sottoprogramma si ferma alla riga: IF k = n OR k = 0 THEN c = 1: EXIT SUB
non procede con ulteriori chiamate, ma completa la chiamata precedente.
Completata una chiamata, i calcoli svolti al suo interno vengono dimenticati;
ad es. C(2,1) viene calcolato 2 volte, per trovare C(3,1) 3 C(3,2).
Per analizzare il comportamento temporale conviene considerare il caso peg-
giore, cioe` calcolare C(n,k) con k al "centro": quando k e` vicino a n o a
0 il sottoprogramma Cbin arriva prima ai casi di cui conosce il valore (i
casi del tipo C(i,i), corrispondenti ai lati non orizzontali del triangolo).
Si ottengono tempi che crescono sempre piu` velocemente. Il file
tempcbin.gfu contiene i tempi t(n) per il calcolo di C(n,n/2) (n pari) otte-
nuti con un particolare PC:
'coppie (n,t(n)), t(n)= tempo calcolo di C(n,n/2) con CBIN2 con un certo PC
7
10,5
12,16
14,49
16,165
18,692
20,2356
22,9068
Analizzandolo con Grafun, se ne trovo e rappresento graficamente più volte
la pendenza, osservo che non riesco ad abbatterne l'andamento. Trasformandolo
in scala semilogaritmica, ottengo un grafico che tende a essere lineare.
Quindi si tratta di una funzione esponenziale:
se f(x) = k*a^x e rappresento (x,Log(y)), cioe` (x,Log(k)+x*Log(a)),
ottengo una retta di pendenza Log(a).
Se ho messo il file in Dat1 e il suo trasformato in Dat2, rappresentati sotto
a sinistra e al centro, e metto in Dat3 la sua pendenza, rappresentata a
destra, dal grafico o esaminando Dat3 con RCL, trovo Log(a) = 0.30, da cui
a = 10^0.3 = 1.995 = (circa) 2:
Quindi il tempo cresce circa come 2^n.
La cosa poteva anche essere dedotta dalla struttura del programma:
ogni chiamata di Cbin effettua a sua volte altre due chiamate, e cosi` via
fino a che non si arriva ai casi noti (lati del triangolo). Se si prende k
al centro, la "distanza" dai lati cresce come n. Quindi le chiamate di Cbin
raddoppiano un numero di volte che cresce come n, cioe` il loro numero cresce
come 2^n.
CBIN3 calcola C(n,k) come n/1*(n-1)/2*...*(n-k+1)/k, con un numero di
operazioni che cresce come k. Nel caso pessimo (k=n) impiega un tempo che
cresce linearmente rispetto a n.
CBIN3 e` decisamente l'algoritmo piu` efficiente. CBIN1 e` utile se in-
serito in un programma in cui si devono calcolare piu` volte dei coeffi-
cienti binomiali: una volta che sono stati calcolati e memorizzati in una
variabile indiciata, nei successivi usi il tempo di accesso a un qualunque
C(i,j) sara` costante. CBIN2 e` decisamente da scartare.
** Su Es.5
SUB ORDMIN (a(), n)
FOR i = 1 TO n
MIN a(), i, n, posto
SWAP a(i), a(posto)
NEXT
END SUB
SUB MIN (a(), i, j, posto) STATIC ' a(posto)=min{a(i),...a(j)}
posto = i
FOR h = i + 1 TO j: IF a(h) < a(posto) THEN posto = h
NEXT h
END SUB
I primi passi dell'algoritmo:
1) Ricerca del minimo e suo scambio col 1° elemento
2) Ricerca del minimo a partire dal 2° elemento e suo scambio col 2° elemento
...
vvvvvvvvvvvvvvvvvvvvvv
ggggggg
sssssssssssssssssss
jjjjjjjjjj
wwwwwwwwwwwwwwwwwwwwwww
pppppppppppppppp
kkkkkkkkkkk
ccc
nnnnnnnnnnnnnn
qqqqqqqqqqqqqqqqq
uuuuuuuuuuuuuuuuuuuuu
a
mmmmmmmmmmmmm
llllllllllll
iiiiiiiii
bb
ffffff
xxxxxxxxxxxxxxxxxxxxxxxx
dddd
ooooooooooooooo
tttttttttttttttttttt
hhhhhhhh
eeeee
rrrrrrrrrrrrrrrrrr | a
ggggggg
sssssssssssssssssss
jjjjjjjjjj
wwwwwwwwwwwwwwwwwwwwwww
pppppppppppppppp
kkkkkkkkkkk
ccc
nnnnnnnnnnnnnn
qqqqqqqqqqqqqqqqq
uuuuuuuuuuuuuuuuuuuuu
vvvvvvvvvvvvvvvvvvvvvv
mmmmmmmmmmmmm
llllllllllll
iiiiiiiii
bb
ffffff
xxxxxxxxxxxxxxxxxxxxxxxx
dddd
ooooooooooooooo
tttttttttttttttttttt
hhhhhhhh
eeeee
rrrrrrrrrrrrrrrrrr |
a
bb
sssssssssssssssssss
jjjjjjjjjj
wwwwwwwwwwwwwwwwwwwwwww
pppppppppppppppp
kkkkkkkkkkk
ccc
nnnnnnnnnnnnnn
qqqqqqqqqqqqqqqqq
uuuuuuuuuuuuuuuuuuuuu
vvvvvvvvvvvvvvvvvvvvvv
mmmmmmmmmmmmm
llllllllllll
iiiiiiiii
ggggggg
ffffff
xxxxxxxxxxxxxxxxxxxxxxxx
dddd
ooooooooooooooo
tttttttttttttttttttt
hhhhhhhh
eeeee
rrrrrrrrrrrrrrrrrr |
SUB ORDINS (a(), n)
'Dopo aver ordinato {a(1),.., a(i)} ottengo un ordinamento di {a(1),.., a(i+1)
'INSERENDO a(i+1) al posto giusto: faccio retrocedere a(i+1) finché incontro
'elementi > di esso (l'avanzamento è realizzato attraverso 'scambi' di
'posto). Il primo insieme ordinato è {a(1)}_
FOR i = 2 TO n ' inserisco a(2), poi inserisco a(3), . , a(n)
FOR j = i TO 2 STEP -1 ' eventuale avanzamento di a(i)
IF a(j) >= a(j - 1) THEN j = 2 ELSE SWAP a(j), a(j - 1)
' quando non c'erano piu' scambi da fare, per uscire dal loop ho posto j%=2
NEXT
NEXT
END SUB
I primi passi dell'algoritmo:
1) Confronto il 2° elemento col 1°; se è minore lo inserisco davanti;
2) Confronto il 3° elemento con quelli che lo precedono fino a trovare un
elemento minore; lo inserico dopo questo;
3) Confronto il 4° elemento con quelli che lo precedono fino a trovare un
elemento minore; lo inserico dopo questo;
...
qqqqqqqqqqqqqqqqq
mmmmmmmmmmmmm
nnnnnnnnnnnnnn
ggggggg
hhhhhhhh
sssssssssssssssssss
a
tttttttttttttttttttt
rrrrrrrrrrrrrrrrrr
bb
jjjjjjjjjj
uuuuuuuuuuuuuuuuuuuuu
iiiiiiiii
xxxxxxxxxxxxxxxxxxxxxxxx
wwwwwwwwwwwwwwwwwwwwwww
ooooooooooooooo
llllllllllll
pppppppppppppppp
vvvvvvvvvvvvvvvvvvvvvv
ffffff
ccc
dddd
eeeee
kkkkkkkkkkk | mmmmmmmmmmmmm
qqqqqqqqqqqqqqqqq
nnnnnnnnnnnnnn
ggggggg
hhhhhhhh
sssssssssssssssssss
a
tttttttttttttttttttt
rrrrrrrrrrrrrrrrrr
bb
jjjjjjjjjj
uuuuuuuuuuuuuuuuuuuuu
iiiiiiiii
xxxxxxxxxxxxxxxxxxxxxxxx
wwwwwwwwwwwwwwwwwwwwwww
ooooooooooooooo
llllllllllll
pppppppppppppppp
vvvvvvvvvvvvvvvvvvvvvv
ffffff
ccc
dddd
eeeee
kkkkkkkkkkk |
mmmmmmmmmmmmm
nnnnnnnnnnnnnn
qqqqqqqqqqqqqqqqq
ggggggg
hhhhhhhh
sssssssssssssssssss
a
tttttttttttttttttttt
rrrrrrrrrrrrrrrrrr
bb
jjjjjjjjjj
uuuuuuuuuuuuuuuuuuuuu
iiiiiiiii
xxxxxxxxxxxxxxxxxxxxxxxx
wwwwwwwwwwwwwwwwwwwwwww
ooooooooooooooo
llllllllllll
pppppppppppppppp
vvvvvvvvvvvvvvvvvvvvvv
ffffff
ccc
dddd
eeeee
kkkkkkkkkkk |
SUB ORDFUS (x(), i, j)
IF i = j THEN EXIT SUB
m = (i + j) \ 2: ORDFUS x(), i, m: ORDFUS x(), m + 1, j
DIM y(j - i)
FUSIONE x(), i, m, x(), m + 1, j, y()
FOR n% = i TO j: x(n%) = y(n% - i): NEXT
ERASE y
END SUB
SUB FUSIONE (x(), i, h, y(), j, k, z())
' fusione di x(i)-x(h) e y(j)-y(k) in z(0),z(1), ...
n% = 0: s% = i: t% = j
WHILE s% <= h AND t% <= k
IF x(s%) < y(t%) THEN z(n%) = x(s%): s% = s% + 1 ELSE z(n%) = y(t%): t% = t% + 1
n% = n% + 1
WEND
FOR p% = s% TO h: z(n%) = x(p%): n% = n% + 1: NEXT
FOR p% = t% TO k: z(n%) = y(p%): n% = n% + 1: NEXT
END SUB
I primi passi dell'algoritmo:
1) Attraverso ripetuti dimezzamenti mi riconduco a confrontare due elenchi da
12, due elenchi da 6, due elenchi da 3, uno da 2 e uno da 1 elemento;
2) Ordinato l'elenco da 2 ordino quello da 1 (il che non richiede confronti);
3) Fondo i due elenchi ordinati da 2 e da 1; ottengo un elenco ordinato da 3;
...
5) Fondo i due elenchi ordinati da 2 e da 1; ottengo un nuovo elenco ordinato
da 3;
6) Fondo i due elenchi ordinati da 3; ottengo un elenco ordinato da 6;
...
12) Fondo i due elenchi ordinati da 3; ottengo un nuovo elenco ordinato da 6;
...
nnnnnnnnnnnnnn
iiiiiiiii
mmmmmmmmmmmmm
kkkkkkkkkkk
bb
eeeee
xxxxxxxxxxxxxxxxxxxxxxxx
wwwwwwwwwwwwwwwwwwwwwww
uuuuuuuuuuuuuuuuuuuuu
jjjjjjjjjj
tttttttttttttttttttt
ggggggg
qqqqqqqqqqqqqqqqq
a
ccc
hhhhhhhh
rrrrrrrrrrrrrrrrrr
pppppppppppppppp
ffffff
vvvvvvvvvvvvvvvvvvvvvv
sssssssssssssssssss
ooooooooooooooo
llllllllllll
dddd | iiiiiiiii
nnnnnnnnnnnnnn
mmmmmmmmmmmmm
kkkkkkkkkkk
bb
eeeee
xxxxxxxxxxxxxxxxxxxxxxxx
wwwwwwwwwwwwwwwwwwwwwww
uuuuuuuuuuuuuuuuuuuuu
jjjjjjjjjj
tttttttttttttttttttt
ggggggg
qqqqqqqqqqqqqqqqq
a
ccc
hhhhhhhh
rrrrrrrrrrrrrrrrrr
pppppppppppppppp
ffffff
vvvvvvvvvvvvvvvvvvvvvv
sssssssssssssssssss
ooooooooooooooo
llllllllllll
dddd |
iiiiiiiii
mmmmmmmmmmmmm
nnnnnnnnnnnnnn
kkkkkkkkkkk
bb
eeeee
xxxxxxxxxxxxxxxxxxxxxxxx
wwwwwwwwwwwwwwwwwwwwwww
uuuuuuuuuuuuuuuuuuuuu
jjjjjjjjjj
tttttttttttttttttttt
ggggggg
qqqqqqqqqqqqqqqqq
a
ccc
hhhhhhhh
rrrrrrrrrrrrrrrrrr
pppppppppppppppp
ffffff
vvvvvvvvvvvvvvvvvvvvvv
sssssssssssssssssss
ooooooooooooooo
llllllllllll
dddd |
...
iiiiiiiii
mmmmmmmmmmmmm
nnnnnnnnnnnnnn
bb
eeeee
kkkkkkkkkkk
xxxxxxxxxxxxxxxxxxxxxxxx
wwwwwwwwwwwwwwwwwwwwwww
uuuuuuuuuuuuuuuuuuuuu
jjjjjjjjjj
tttttttttttttttttttt
ggggggg
qqqqqqqqqqqqqqqqq
a
ccc
hhhhhhhh
rrrrrrrrrrrrrrrrrr
pppppppppppppppp
ffffff
vvvvvvvvvvvvvvvvvvvvvv
sssssssssssssssssss
ooooooooooooooo
llllllllllll
dddd | bb
eeeee
iiiiiiiii
kkkkkkkkkkk
mmmmmmmmmmmmm
nnnnnnnnnnnnnn
xxxxxxxxxxxxxxxxxxxxxxxx
wwwwwwwwwwwwwwwwwwwwwww
uuuuuuuuuuuuuuuuuuuuu
jjjjjjjjjj
tttttttttttttttttttt
ggggggg
qqqqqqqqqqqqqqqqq
a
ccc
hhhhhhhh
rrrrrrrrrrrrrrrrrr
pppppppppppppppp
ffffff
vvvvvvvvvvvvvvvvvvvvvv
sssssssssssssssssss
ooooooooooooooo
llllllllllll
dddd |
bb
eeeee
iiiiiiiii
kkkkkkkkkkk
mmmmmmmmmmmmm
nnnnnnnnnnnnnn
ggggggg
jjjjjjjjjj
tttttttttttttttttttt
uuuuuuuuuuuuuuuuuuuuu
wwwwwwwwwwwwwwwwwwwwwww
xxxxxxxxxxxxxxxxxxxxxxxx
qqqqqqqqqqqqqqqqq
a
ccc
hhhhhhhh
rrrrrrrrrrrrrrrrrr
pppppppppppppppp
ffffff
vvvvvvvvvvvvvvvvvvvvvv
sssssssssssssssssss
ooooooooooooooo
llllllllllll
dddd |
1) Dalle uscite sperimentali si capisce che:
MIN non ha casi ottimi/pessimi: al raddoppiare dei dati il tempo quadrupli-
ca sempre; t(N) e` un infinito di ordine 2. Teoricamente: l'algoritmo cerca
man mano il minimo di tutti di dati, dei dati dal 2^ in poi, dei dati dal 3^
in poi, ...; per cerare il minimo tra H dati fa H-1 confronti; quindi im-
piega un tempo k*N per trovare il 1^ dato, un tempo K*(N-1) per trovare il
2^, ..., cioe` in tutto k*(N + N-1 + N-2 + ...) = k/2*N^2 + ...
INS ha caso ottimo se i dati sono gia` in ordine crescente: il tempo cresce
linearmente; nel caso in cui i dati siano a caso (con distribuzione uniforme)
cresce piu` o meno quadraticamente; la crescita e` chiaramente quadratica (e
con tempi molto maggiori) nel caso in cui i dati siano decrescenti.
Questo e` anche il caso pessimo, infatti l'algortimo man mano legge un dato
e lo colloca al posto giusto rispetto ai dati letti in precedenza. Mentre se
i dati sono gia` in ordine crescente deve per ogni dato fare un solo confron-
to (lo confronta con il massimo tra i dati gia` letti e si ferma senza effet-
tuare spostamenti), se sono in ordine decrescente deve invece confrontare
ogni dato letto prima con il massimo di quelli gia` letti, poi con quello
precedente, ... e andarsi a collocare al primo posto: in modo analogo a come
si e` proceduto per MIN, si conclude che il tempo e` quadratico.
FUS, come si osserva dalle uscite, cresce in modo poco piu` che lineare in
tutti i casi. Nel caso crescente e in quello decrescente si hanno tempi leg-
germente inferiori rispetto alle distribuzioni casuali dei dati. Teoricamen-
te: come si intuisce sia dalla esecuzione animata che dalla analisi del sot-
toprogramma, l'algoritmo funziona fondendo in ordine coppie di segmenti or-
dinati di dati (dai segmenti si estrae man mano il minimo tra i due primi
elementi dei segmenti finche' uno di questi
4 9 1 3 5 2 8 viene esaurito); se i dati sono N=2^H, fon-
\ / \ / \ / | de segmenti lunghi 2, 4, 8, 16, ..., 2^H;
4 1 2 | in ognuna di queste fasi (ossia ad ogni li-
9 3 5 | vello del grafo a fianco, che se i dati fos-
\__ __/ \_ _/ sero stati 2^N sarebbe stato "simmetrico")
1 2 deve comunque fare almeno N/2 confronti e
3 5 meno di N confronti; le fasi sono H; quindi
4 8 i confronti in tutto sono tra H*N/2 e H*N;
9 / H = log2(N); quindi il tempo cresce come
\ / N*log(N) (la base non e` rilevante: log2(N),
\____ ____/ Log(N), ln(N), ... sono proporzionali).
1 Se la quantita` di dati non e` una potenza
2 di 2, il comportamento sara` intermedio tra
3 quello di due situazioni con quantita` pari
4 a una potenza di 2. Quindi in ogni caso
5 t(N) cresce come N*log(N)
8
2) Conviene ORDINS. Perché? Anche in questo caso, non esiste il modello o
la tecnica matematica migliore in assoluto. A seconda dei contesti la
strategia più efficace può cambiare.
** Su Es.6
1)
DEFDBL A-Z
max = 100
PRINT : PRINT "Terne pitagoriche (x^2+y^2=z^2; x, y <="; max; ")"
n.cifre = 15: prec.rel = 5 * 10 ^ -n.cifre
FOR x = 1 TO max: FOR y = x TO max
u = (x ^ 2 + y ^ 2) ^ .5#
GOSUB Ver.Int
IF intero = 1 THEN PRINT x; y; u, : intero = 0
NEXT: NEXT
END
Ver.Int:
IF ABS((INT(u) - u) / u) < prec.rel THEN ' parte intera inf.
intero = 1
ELSEIF ABS((INT(u + 1) - u) / u) < prec.rel THEN ' parte intera sup.
intero = 1
END IF
RETURN
Terne pitagoriche (x^2+y^2=z^2; x, y <= 100 )
3 4 5 5 12 13 6 8 10 7 24 25 8 15 17
9 12 15 9 40 41 10 24 26 11 60 61 12 16 20
12 35 37 13 84 85 14 48 50 15 20 25 15 36 39
16 30 34 16 63 65 18 24 30 18 80 82 20 21 29
20 48 52 20 99 101 21 28 35 21 72 75 24 32 40
24 45 51 24 70 74 25 60 65 27 36 45 28 45 53
28 96 100 30 40 50 30 72 78 32 60 68 33 44 55
33 56 65 35 84 91 36 48 60 36 77 85 39 52 65
39 80 89 40 42 58 40 75 85 40 96 104 42 56 70
45 60 75 48 55 73 48 64 80 48 90 102 51 68 85
54 72 90 56 90 106 57 76 95 60 63 87 60 80 100
60 91 109 63 84 105 65 72 97 66 88 110 69 92 115
72 96 120 75 100 125 80 84 116
DEFDBL A-Z
n.cifre = 15: prec.rel = 5 * 10 ^ -n.cifre
x1 = 25: x2 = 30
y1 = 81: y2 = 85
z1 = 106: z2 = 110
w1 = 131: w2 = 135
' Invece che: FOR x = 1 TO 135 : FOR y = x TO 135: FOR z = y to 135 : ...
' si sono scelti range piu` ristretti per ridurre i tempi; comunque la
' quaterna di interi x,y,z,w che si ottiene e` la prima per cui esiste u
' intero tale che x^5+y^5+z^5+w^5=u^5
PRINT "Ricerca di x,y,z,w per cui esiste u tale che x^5+y^5+z^5+w^5=u^5"
PRINT "negli intervalli:"
PRINT "x1,x2; y1,y2; z1,z2; w1,w2: "; x1; x2; " "; y1; y2; " "; z1; z2; " "; w1; w2
PRINT "Aspetta ..."
FOR x = x1 TO x2: FOR y = y1 TO y2: FOR z = z1 TO z2: FOR w = w1 TO w2
LOCATE , 1: PRINT "x,y,z,w,u"; x; y; z; w;
u = (x ^ 5 + y ^ 5 + z ^ 5 + w ^ 5) ^ .2#: GOSUB Ver.Int
IF intero = 1 THEN PRINT u: intero = 0
NEXT: NEXT: NEXT: NEXT
LOCATE , 1: PRINT SPACE$(60)
END
Ver.Int:
IF ABS((INT(u) - u) / u) < prec.rel THEN ' parte intera inf.
intero = 1
ELSEIF ABS((INT(u + 1) - u) / u) < prec.rel THEN ' parte intera sup.
intero = 1
END IF
RETURN
Ricerca di x,y,z,w per cui esiste u tale che x^5+y^5+z^5+w^5=u^5
negli intervalli:
x1,x2; y1,y2; z1,z2; w1,w2: 25 30 81 85 106 110 131 135
Aspetta ...
x,y,z,w,u 27 84 110 133 144
2)
' Programma per la verifica sperimentale della Congettura di Goldbach: ogni
' numero pari maggiore di 2 e` somma di due numeri primi diversi tra loro.
' Al momento (1997), ne' la congettura ne' la sua negazione sono state
' dimostrate
Via:
INPUT "ricerca dei numeri primi <= N; N="; max
DIM a(max): rad = SQR(max)
' lascio a(n)=0 se n e' primo (o e' 0), se no metto in a(n) un fattore primo di n
FOR fat = 2 TO rad
IF a(fat) = 0 THEN FOR i = fat * fat TO max STEP fat: a(i) = fat: NEXT
NEXT
WHILE 0 = 0
INPUT "1: elenco numeri primi, 2: fattorizzare, 3: Goldbach, 4: altro N, 5: fine"; risp
IF risp = 1 THEN
INPUT "elenco primi compresi tra h e k; h,k="; h, k
IF k > max THEN k = max: PRINT "prendo k="; max
IF h = 0 THEN h = 1
FOR i = h TO k: IF a(i) = 0 THEN PRINT i;
NEXT: PRINT
ELSEIF risp = 2 THEN
PRINT "n. da scomporre <="; max; : INPUT n
IF n > max THEN
PRINT "numero troppo grande"
ELSE
WHILE a(n) > 0: PRINT a(n): n = n / a(n): WEND
PRINT n
END IF
ELSEIF risp = 3 THEN
FOR i = 2 TO max STEP 2
v = 0
FOR j = 1 TO i - 1
IF a(j)= 0 THEN IF a(i-j)= 0 THEN PRINT i; "="; j; "+"; i-j; " # "; : j= i-1: v= 1
' se trovo la coppia di addendi pongo v=1 e esco dal ciclo ponendo j=i-1
NEXT
IF v = 0 THEN PRINT "falsa": i = max
IF i \ 100 = i / 100 THEN INPUT ; "", wwww$
NEXT: PRINT
ELSEIF risp = 4 THEN
ERASE a: GOTO Via
ELSEIF risp = 5 THEN
END
END IF
WEND
ricerca dei numeri primi <= N; N=? 1000
1: elenco numeri primi, 2: fattorizzare, 3: Goldbach, 4: altro N, 5: fine? 1
elenco primi compresi tra h e k; h,k=? 1,1000
1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71
73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157
163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241
251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347
349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439
443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547
557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643
647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751
757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859
863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977
983 991 997
1: elenco numeri primi, 2: fattorizzare, 3: Goldbach, 4: altro N, 5: fine? 2
n. da scomporre <= 1000 ? 996
3
2
2
83
1: elenco numeri primi, 2: fattorizzare, 3: Goldbach, 4: altro N, 5: fine? 3
2 = 1 + 1 # 4 = 1 + 3 # 6 = 1 + 5 # 8 = 1 + 7 # 10 = 3 + 7 # 12 = 1 +
11 # 14 = 1 + 13 # 16 = 3 + 13 # 18 = 1 + 17 # 20 = 1 + 19 # 22 = 3 +
19 # 24 = 1 + 23 # 26 = 3 + 23 # 28 = 5 + 23 # 30 = 1 + 29 # 32 = 1 +
31 # 34 = 3 + 31 # 36 = 5 + 31 # 38 = 1 + 37 # 40 = 3 + 37 # 42 = 1 +
41 # 44 = 1 + 43 # 46 = 3 + 43 # 48 = 1 + 47 # 50 = 3 + 47 # 52 = 5 +
47 # 54 = 1 + 53 # 56 = 3 + 53 # 58 = 5 + 53 # 60 = 1 + 59 # 62 = 1 +
61 # 64 = 3 + 61 # 66 = 5 + 61 # 68 = 1 + 67 # 70 = 3 + 67 # 72 = 1 +
71 # 74 = 1 + 73 # 76 = 3 + 73 # 78 = 5 + 73 # 80 = 1 + 79 # 82 = 3 +
79 # 84 = 1 + 83 # 86 = 3 + 83 # 88 = 5 + 83 # 90 = 1 + 89 # 92 = 3 +
89 # 94 = 5 + 89 # 96 = 7 + 89 # 98 = 1 + 97 # 100 = 3 + 97 # 102 =
1 + 101 # 104 = 1 + 103 # 106 = 3 + 103 # 108 = 1 + 107 # 110 = 1 +
109 ...
** Su Es.7
' cod e` la codifica "segreta" dei numeri del codice ASCII
' car$ e` un carattere battuto e n.asc e` il suo numero in codice ASCII
' car.new$ e` la sua codifica segreta e n.asc.new e` il suo numero in codice ASCII
PRINT
DIM cod(255)
FOR i = 0 TO 255
cod(i) = i + 3: IF cod(i) > 255 THEN cod(i) = cod(i) - 255
NEXT
10 INPUT "1: codifica, 2: decodifica"; cosa
SELECT CASE cosa
CASE 1
INPUT"messaggio: ", a$
PRINT "codifica: ";
FOR i = 1 TO LEN(a$)
car$ = MID$(a$, i, 1): n.asc = ASC(car$): n.asc.new = cod(n.asc)
car.new$ = CHR$(n.asc.new) : PRINT car.new$;
NEXT
PRINT
CASE 2
INPUT"codifica: ", a$
PRINT "messaggio: ";
FOR i = 1 TO LEN(a$)
car$ = MID$(a$, i, 1): n.asc = ASC(car$)
FOR n.asc.new =0 TO 255: IF n.asc= cod(n.asc.new) THEN EXIT FOR
NEXT
car.new$ = CHR$(n.asc.new) : PRINT car.new$;
NEXT
PRINT
CASE ELSE
END SELECT
GOTO 10
1: codifica, 2: decodifica? 1
messaggio: non mi piace la matematica
codifica: qrq#pl#sldfh#od#pdwhpdwlfd
1: codifica, 2: decodifica? 2
codifica: qrq#pl#sldfh#od#pdwhpdwlfd
messaggio: non mi piace la matematica
Questi tipi di codifica (basati su uno slittamento del codice ascii) sono
molto facili da individuare, come lo sono anche quelli basati su una
qualunque altra scelta di una funzione bigettiva da N<256 in N<256: tenendo
conto della frequenza delle varie lettere (individuabile con una analisi
statistica), della distribuzione della lunghezze delle parole e delle frasi,
dei vincoli esistenti (in genere, in italiano, ad esempio, prima di una H ci
può essere una C, una G o uno spazio; dopo una B non ci possono essere
C, F, G,
),
non è difficile individuare i cambiamenti di "nome".
Vediamo una delle molte "complicazioni" ideabili. Si potrebbe creare una
sequenza di, ad esempio, 5 valori di "slittamento" in modo che di volta in
volta cambi la ridenominazione, ma in modo che, per chi conosce la sequenza
(che funge da chiave di lettura), sia anche possibile effettuare la
decodifica. Vedi CodSegr2.bas in MC:
...
DIM cod(4,255)
d(0)=3: d(1)=7: d(2)=1: d(3)=27: d(4)=13
FOR j=0 TO 4: FOR i = 0 TO 255
IF i < 32 OR i > 126 THEN ' non modifichiamo i caratteri "strani"
cod(j,i) = i ' ma solo lettere e segni di interpunzione
ELSE
cod(j,i) = i + d(j): IF cod(j,i) > 126 THEN cod(j,i) = cod(j,i) - 126 + 31
END IF
NEXT: NEXT
...
id = 0
...
IF id > 4 THEN id = 0
car$ = MID$(a$, i, 1): n.asc = ASC(car$): n.asc.new = cod(id,n.asc)
car.new$ = CHR$(n.asc.new) : PRINT car.new$; : id = id + 1
...
id = 0
...
IF id > 4 THEN id = 0
car$ = MID$(a$, i, 1): n.asc = ASC(car$)
FOR n.asc.new =0 TO 255: IF n.asc= cod(id,n.asc.new) THEN EXIT FOR
NEXT
car.new$ = CHR$(n.asc.new) : PRINT car.new$; : id = id + 1
...
1: codifica, 2: decodifica? 1
messaggio: non mi piace la matematica
codifica: qvo;zl'q%nfl!(n#tb0rphu%pd
1: codifica, 2: decodifica? 2
codifica: qvo;zl'q%nfl!(n#tbOrphu%pd
messaggio: non mi piace la ma4ematica
Efficacissimo è il ricorso a RND e RANDOMIZE. Possiamo scegliere un seme
(ossia un numero intero) per individuare una successione di numeri tra 0 e 1
pseudo-casuale (ossia generata da un algoritmo particolare in modo che in
apparenza i numeri si susseguano in modo casuale) mediante RANDOMIZE
(INPUT "seme"; s : RANDOMIZE s). Trasformiamo i numeri man mano generati
da RND in numeri compresi tra 0 e 93 con D = FIX(RND*94) e modifichiamo il
programma di sopra mettendo "+D" al posto di "+d(j)". Se il ricevente
conosce il "seme" può decodificare il messaggio.
Quello della crittografia è un tema che, se non ci si mette a studiare la
crittografia a fondo, a far finta di far studiare e far capire agli alunni le
tecniche più sofisticate, ma si punta a studiarne il ruolo, a collocarlo
storicamente e, soprattutto, a far ideare agli alunni (ricorrendo alle
conoscenze che già hanno, alla esplorazione degli strumenti matematici e del
software che hanno a disposizione, ...) nuovi metodi di codifica, offre
spunti e motivazioni (culturali ed "emotive") agli alunni in direzione di
diverse attività ed aree matematiche (funzioni, successioni, iniettività
e invertibilità, algortimi, aritmetica modulare, variabili casuali, ...).
[inizio scheda] [schede: 1 2 3 4 5 6 7 8] [indice schede]