corrigeTP1_ulma401.mws
Transcription
corrigeTP1_ulma401.mws
ULMA 401 Corrigé de la feuille de travaux pratiques N˚1 Exercice 1. Numéro de sécurité sociale. 43 Exercice 2. Nombres parfaits. (a) Ecrire une fonction qui teste si un nombre est parfait: On parcourt tout les entiers plus petits strictement que n et on additionne ceux qui divisent n: > parfait := proc(n) local s, d; s:=0; for d from 1 to n-1 do if n mod d = 0 then s:=s+d; end if; end do; return evalb(s=n); end proc; (a) Vérifions que les numéros d’Alice, Bob et Oscar sont valables: Un nombre est divisible par 97 si et seulement si son reste modulo 97 vaut 0. Alice: > (2530775073004+83) mod 97; 0 Bob: > (1870985123598+15) mod 97; 0 Oscar: > (1980412526354+94) mod 9; 0 On en déduit que les numéros d’Alice, Bob et Oscar sont valides. (b) On essaie sur des exemples: - Erreur sur un seul chiffre: > (1530775073004+83) mod 97; 47 - Interversion de deux chiffres: > (2350775073004+83) mod 97; 88 On souhaite retrouver un numéro de sécurité sociale sachant qu’il s’écrit 2 xx 07 35 231 584 19 où xx sont deux chiffres. Premiére méthode: on essaie toute les valeurs possibles de xx de 00 à 99, en remarquant que 2xx0735231584= 2000735231584+xx*10000000000 local s, d; s := 0; > for xx from 0 to 99 do if (2000735231584+10000000000*xx+19) mod 97 = 0 then print(xx); end if; end do; 6 28 496 Comme précédemment nous pouvons utiliser l’instruction select: > select(parfait,[seq(i,i=1..1000)]); 43 Il est aussi possible de faire la recherche directement avec l’instruction "select" qui permet de chercher dans une liste: > select(xx->(2000735231584+10000000000*xx+19) mod 97 = 0, [seq(i,i=0..99)]); [43 ] Deuxième méthode: on remarque que xx est solution de l’équation (2000735231584+xx*10000000000 +19) mod 97 = 0 dont une solution est donnée par xx=-(2000735231584+19)*10000000000^(-1) mod 97 > print((-(2000735231584+19)*10000000000^(-1)) mod 97); parfait := proc(n) for d to n − 1 do if n mod d = 0 then s := s + d end if end do; return evalb(s = n ) end proc (b) En déduire la liste des nombres parfaits inférieurs à 1000 > for i from 1 to 1000 do if parfait(i) then print(i); end if; end do; [6, 28, 496 ] (c) Vérifier que 8128 est parfait > parfait(8128); true > #parfait(2^12*(2^13-1)); > parfait2 := proc(a) local s, d, n; n:=2^(a+1)-1; s:=0; for d from 1 to n do if n mod d = 0 then s:=s+d; end if; end do; n:=n*2^a; s:=s*(2^(a+1)-1)-n; return evalb(s=n); end proc; parfait2 := proc(a) local s, d, n; n := 2^(a + 1 ) − 1; s := 0; for d to n do if n mod d = 0 then s := s + d end if end do; n := n∗2^a; s := s∗(2^(a + 1 ) − 1 ) − n; return evalb(s = n ) end proc > parfait2(12); true (e) > select(parfait2,[seq(i,i=1..18)]); [1, 2, 4, 6, 12, 16, 18 ] Exercice 3. Critère de divisibilités. (a) divisibilité par 9: Pour simplifier on écrit d’abord une fonction qui calcule la somme des chiffres. > sommechiffres:= proc (n) local s,m; s:=0; m:=n; while m>0 do s:=s+(m mod 10); m:=iquo(m,10); end do; s; end proc; sommechiffres := proc(n) if m = 9 then m:=0; end if; m; end proc; modneuf := proc(n) local m; m := n; while 10 ≤ m do m := sommechiffres(m) end do; if m = 9 then m := 0 end if; m end proc > modneuf(963); 0 > modneuf(1729); 1 (b) divisibilité par 11: Pour cela nous commençons par écrire une fonction qui retourne la somme alternée des chiffres: > sommealtchiffres:= proc (n) local s,m,e; s:=0; m:=n; e:=1; while m>0 do s:=s+e*(m mod 10); e:=-e: m:=iquo(m,10); end do; s; end proc; sommealtchiffres := proc(n) local s, m, e; s := 0; m := n; e := 1; while 0 < m do s := s + e∗(m mod 10 ); e := −e; m := iquo(m, 10 ) end do; s local s, m; s := 0; m := n; while 0 < m do s := s + (m mod 10 ); m := iquo(m, 10 ) end do; s end proc > sommealtchiffres(519); end proc > sommechiffres(789); > sommealtchiffres(7193); 24 Pour tester la divisibilité par neuf nous itérons la somme des chiffres jusqu’à ce qu’il n’y ait plus qu’un chiffre. > modneuf := proc (n) local m; m:=n; while m>=10 do m:=sommechiffres(m); end do; > sommealtchiffres(-12); 13 -12 0 Pour tester la divisibilité par 11 nous itérons la valeur absolue de la somme alternée des chiffres jusqu’à ce qu’il n’y ait plus qu’un chiffre. > divonze := proc (n) local m; m:=n; while m>=10 do m:=abs(sommealtchiffres(m)); end do; if m = 9 then m:=0; end if; evalb(m=0); end proc; divonze := proc(n) local m; m := n; while 10 ≤ m do m := abs(sommealtchiffres(m)) end do; if m = 9 then m := 0 end if; evalb(m = 0 ) 0.015 > t:=time():igcd(a,b);time()-t; 1 0. (d) igcdex permet d’obtenir u et v tel que a*u+n*v=1. nous avons donc a*u mod n =1 > invmod:= proc(a,n) local u,v; if igcdex(a,n,’u’,’v’) <>1 then print ("Error, a et n ne sont pas premier entre eux"); return 0; end if; return u; end proc; invmod := proc(a, n) local u, v; if igcdex(a, n, ’u’, ’v’) ≠ 1 then end proc > divonze(1111); true > divonze(12345); false Remarque: pour obtenir le reste modulo 11, il suffit de tenir compte du signe à chaque étapes. Exercice 4. Algorithme d’Euclide. print("Error, a et n ne sont pas premier entre eux" ); return 0 end if; return u end proc > invmod(7,37); 16 (a) > eucl:= proc(aa,bb) local r,a,b; a:=aa; b:=bb; while b<>0 do r:=a mod b; a:=b; b:=r; end do; a; end proc; > 16*7 mod 37; eucl := proc(aa, bb) local r, a, b; a := aa; b := bb; while b ≠ 0 do r := a mod b; a := b; b := r end do; a end proc > eucl(21,34); 1 > eucl(24,36); 12 (b) > r:=rand(10^1000):a:=r():b:=r(): t:=time():eucl(a,b);time()-t; 1 1 (e) L’équation a*x*+b*y=c a des solutions si et seulement si c est un multiple du pgcd d de a et b. Dans ce cas il existe u, v telque a*u+b*v=d et il suffit de multiplier par c/d. La solution générale est donnée par x=u*c/d+l*b/d y=v*c/d-l*a/d ou l est un entier. > equa:= proc(a,b,c) local u,v,d; d:=igcdex(a,b,’u’,’v’); if c mod d <> 0 then print ("Pas de solution"); return []; end if; return [u*c/d+l*b/d,v*c/d-l*a/d]; end proc; equa := proc(a, b, c) local u, v, d; d := igcdex(a, b, ’u’, ’v’); if c mod d ≠ 0 then print("Pas de solution" ); return [ ] end if; return [u∗c / d + l∗b / d, v∗c / d − l∗a / d ] end proc > equa(11,13,5); [30 + 13 l, −25 − 11 l ] > 11*(30+13*l)+13*(-25-11*l); 5 Exercice 5. Ecrire une fonction qui teste naïvement si un nombre est premier. > estpremier:= proc(n) local i; for i from 2 to floor(sqrt(n)) do if n mod i = 0 then return false; end if; end do; return true; end proc; estpremier := proc(n) local i; for i from 2 to floor(sqrt(n )) do if n mod i = 0 then return false end if end do; return true end proc > estpremier(101); true Exercice 6. Déterminer les nombres premiers inférieurs à n en utilisant le crible d’Eratosthène. Remarque: pour être un crible d’Eratosthène, le programme ne doit pas faire de division, de multiplication et de modulo, mais seulement des additions et des soustractions. > eratosthene:= proc(n) local T,p,i; T:=[seq(true,i=1..n)]; T[1]:=false; for p from 2 to floor(sqrt(n)) do if T[p] then for i from p+p by p to n do T[i]:=false; end do; end if; end do; select(i->T[i],[seq(i,i=1..n)]); end proc; eratosthene(100); eratosthene := proc(n) local T, p, i; T := [seq(true, i = 1 .. n )]; T[1 ] := false; for p from 2 to floor(sqrt(n )) do if T[p ] then for i from 2∗p by p to n do T[i ] := false end do end if end do; select(i → T[i ], [seq(i, i = 1 .. n )]) end proc [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 ] Exercice 7. Petit théorème de Fermat. (a) > estpremier(97); true (b) > t:=time(): (1234^1234567 mod 7): time()-t; 4.351 > t:=time(): (1234&^1234567 mod 7): time()-t; 0. (c) On vérifie que le petit théorème de Fermat est vrai por toutes les bases entre 1 et 96: > for a from 1 to 96 do if a &^ 96 mod 97 <> 1 then print("erreur :",a); end if; end do; (d) > testpseudo:= proc(a,n) return evalb(a&^(n-1) mod n=1); end proc; testpseudo := proc(a, n) return evalb(‘&^‘(a, n − 1 ) mod n = 1 ) end proc (e) > estpseudopremier:= proc (n,N) local r,b,i; r:=rand(1..n); for i from 1 to N do b:=r(); while gcd(b,n)<>1 do b:=r(); end do; if not testpseudo(b,n) then return false; end if; end do; return true; end proc; estpseudopremier := proc(n, N) local r, b, i; r := rand(1 .. n ); for i to N do b := r( ); while gcd(b, n ) ≠ 1 do b := r( ) end do; if not testpseudo(b, n ) then return false end if end do; return true end proc > estpseudopremier(150,10); false > estpseudopremier(17,10); true (f) > estpseudopremier(561,10); true > estpseudopremier(1105,10); true > estpremier(561); false > estpremier(1105); false (g) > t:=time(): estpremier(10^11+3): time()-t; 1.327 > t:=time(): isprime(10^11+3): time()-t; 0.001 > t:=time(): estpseudopremier(10^11+3,100): time()-t; 0.021 > t:=time(): isprime(10^60+7): time()-t; 0.002 > t:=time(): estpseudopremier(10^60+7,100): time()-t; 0.646 Exercice 8. Calcul du pgcd > gcd_factor:=proc(a,b) local fa, fb, g, i, j, G,t; t:=time(); fa:=ifactors(a)[2]; fb:=ifactors(b)[2]; g:=[]; for i from 1 to nops(fa) do for j from 1 to nops(fb) do if fa[i][1]=fb[j][1] then g:=[op(g),[fa[i][1],min(fa[i][2],fb[j][2])]]; fi; od; od; G:=map(x->x[1]^x[2],g); return mul(G[i],i=1..nops(G)); end: > a:=rand(10^20)():b:=rand(10^20)():t:=time():gcd_factor(a,b):t ime()-t; 0.003 > a:=rand(10^30)():b:=rand(10^30)():t:=time():gcd_factor(a,b):t ime()-t; 2.457 > a:=rand(10^30)():b:=rand(10^30)():t:=time():eucl(a,b):time()t; 0. avec la factorisation, ca commence a devenir difficile avec 30 chiffres, alors qu’avec l’algorithme d’Euclide, on a vu à l’exercice 4 qu’on pouvait traiter 1000 chiffres sans problèmes. Cela montre qu’il faut eviter à tout prix la factorisation quand on programme car c’est un problème difficile. Exercice 9. Théorème chinois (a) Si m et n sont premiers entre eux, il existe u, v telque u*m+v*n=1, donc x=u*x*m+v*x*n donc x=u*m*b+v*n*a [mod n*m] > chinois:= proc(a,b,m,n) local u,v; if igcdex(m,n,’u’,’v’)<>1 then return "n et m ne sont pas premier entre eux"; end if; return (u*b*m+v*n*a) mod m*n; end proc; chinois := proc(a, b, m, n) local u, v; if igcdex(m, n, ’u’, ’v’) ≠ 1 then return "n et m ne sont pas premier entre eux" end if; return (u∗b∗m + v∗n∗a ) mod m∗n end proc (b) On compare chinois et chrem sur l’example x=3 [11] et x=7 [15] > chinois(3,7,11,15); 157 > chrem([3,7],[11,15]); 157 (c) Généralisation : > chinois_gen:=proc(A,M) #A et M sont des vecteurs et le système à résoudre est donné par les equations x est congru à A[i] modulo M[i]. Bien sur les M[i] sont supposés premiers entre eux deux à deux. local g,i; g:=[A[1],M[1]]; for i from 2 to nops(A) do g:=[chinois(g[1],A[i],g[2],M[i]),M[i]*g[2]]; od; return g[1]; end: > chrem([1,2,3,4],[11,17,4,89]); > chinois_gen([1,2,3,4],[11,17,4,89]); 17359 17359 Exercice 10. Ecrire une fonction qui calcule l’indicateur d’Euler L’indicateur d’Euler de n est le nombre d’entiers plus petits que n et premiers à n. > eulerphi:=proc(n) local i, s; s:=0; for i from 0 to n-1 do if (igcd(i,n)=1) then s:=s+1; end if; end do; return s; end proc; eulerphi := proc(n) local i, s; s := 0; for i from 0 to n − 1 do if igcd(i, n ) = 1 then s := s + 1 end if end do; return s end proc > eulerphi(24); 8 > eulerphi(124); 60