Institut d'Optique Graduate School “Initiation auCalcul Scientifique (avec Matlab)” 1ère année, Année 2016-2017 Corrigé (exemples de solution), TD n° 2 Initiation à la programmation avec Matlab I. Années bissextiles (une solution possible) II.) construitMat.m (Une solution possible...) function M=construitMat(N) % construitMat: construit la matrice "MN" du TD n°S2, question §II % USAGE: M=construitMat(N) % N: scalaire entier positif, la taille de la matrice à créer. % M: matrice N x N de termes M(i,j)=cos((j-1)*(pi*(i-1/2)/N)) % pour i et j dans {1, ..., N}. function NbJ=NbrJoursDansAnnee(aaaa) % NbrJoursDansAnnee - retourne le nombre de jours dans l'année pour le calendrier grégorien % USAGE: NbJ=NbrJoursDansAnnee(aaaa) % aaaa: scalaire numérique entier représentant l'année (sur 4 chiffres). % NbJ : scalaire numérique, nombre de jours contenus dans l'année ou bien % NaN si la date est antérieure au calendrier grégorien. % % Les années bissextiles sont calculées suivant les règles du calendrier % grégorien mis en place le 15 octobre 1582 par le pape Grégoire XIII à % partir des recommandations de l'astronome et mathématicien Aloysius Lilius. % M=ones(N,N); % préallocation de la matrice à la taille finale (remplissage avec 1) % (Évite de nombreuses requêtes d'allocation mémoire (C "malloc") et de recopie de % partie de la matrice que l'on aurait de manière interne si la matrice avait une % taille croissante au fur et à mesure des itérations de la boucle for qui suit, % ce qui améliore notablement l'efficacité du calcul) if aaaa<=1582 NbJ=NaN; % date antérieure à la mise en place du calendrier grégorien! else if mod(aaaa,4)==0 && ~(mod(aaaa,100)==0 && mod(aaaa,400)~=0) % <=> div/4 sauf si div/100 et pas /400 NbJ=366; % Année bissextile! else NbJ=365; % Cas général end end % construction de la matrice par colonne: for j=2:N M(:,j)=cos((j-1)*x); % remplissage de la colonne n°j d'un coup! end % Remarque: la colonne n°j=1 étant une colonne de 1 (i.e. cos(0*x)), % elle est déjà remplie par la préallocation par "ones", % et il n'est donc pas utile de la recalculer, d'où un % départ à 2 de l'indice de boucle. end % end function NbrJoursDansAnnee (Facultatif) end % end function construitMat (Facultatif) >> NbrJoursDansAnnee(1700) ans = 365 >> NbrJoursDansAnnee(1600) ans = 366 >> NbrJoursDansAnnee(1500) ans = NaN >> construitMat(4) ans = 1.0000 0.9239 1.0000 0.3827 1.0000 -0.3827 1.0000 -0.9239 0.7071 -0.7071 -0.7071 0.7071 0.3827 -0.9239 0.9239 -0.3827 M=construitMat(100); figure,imagesc(M),axis image,colorbar ylabel('i'),xlabel('j'),title('M_N') i >> NbrJoursDansAnnee(2014) ans = 365 >> NbrJoursDansAnnee(2016) ans = 366 >> NbrJoursDansAnnee(2000) ans = 366 >> NbrJoursDansAnnee(1900) ans = 365 x=pi*((1:N)-0.5)/N; % variable locale pour simplifier l'écriture % et éviter un recalcul inutile dans la boucle. III. Factorisation d'un nombre entier (un exemple de programme) function vfp=FactoriseEntier(n) % factoriseEntier - détermine la décomposition en facteurs premiers d'un entier % USAGE: vfp=factoriseEntier(n) % n : nombre scalaire entier positif, le nombre entier à factoriser. % n négatif ou non entier déclenche une erreur. % n supérieur à 2^53==flintmax (le plus grand entier vraiment codable en 'double float') déclenche également une erreur. % ATTENTION: des arguments de l'ordre de 2^53-1=~9E15 conduisent à des calculs longs (de l'ordre de % ~quelques secondes) et requièrent de grande quantité de mémoire vive. Il est préférable % que n ne dépasse pas ~1E14 pour limiter les temps de calcul et la mémoire requise. % vfp: vecteur d'entiers, les facteurs premiers de n, en ordre ascendant. % (Il sera par convention retourné un vecteur vide pour n valant 0 ou 1) if ~isnumeric(n) || ~isreal(n) || ~isscalar(n) || mod(n,1)~=0 || n<0 || n>2^53 error('L''argument n n''est pas un nombre scalaire entier positif plus petit que 2^53') % Arrêt de la fonction avec message d'erreur dans la Command Window en cas de violation des spécifications sur n end % Ici, n est nécessairement correct puisque la fonction ne s'est pas arrêtée sur un appel de error dans le if ci-dessus... m=floor(sqrt(n)); vp=primes(m); % les nombres premiers <= sqrt(n). % ATTENTION: le calcul ci-dessus peut être lourd si n est grand (>~1E14). % NOTA: primes(0) et primes(1) retournent un vecteur vide. nt=n; % n ‘de travail’ (on conservera le n originel inchangé) vfp=zeros(1,0); % initialisation de vfp comme vecteur (ligne) vide. for p=vp % pour tous les nombres premiers <= sqrt(n) while mod(nt,p)==0 % tant que nt est divisible par p (p est le nbr premier <= sqrt(n) "courant") vfp=[vfp p]; nt=nt/p; end if nt==1;break;end % évite de tester les nombres premiers plus grands si la décomposition est déjà finie! end if nt>1 % cas de l'existence de l'unique facteur premier >sqrt(n) dans la factorisation de n vfp=[vfp nt]; % on concatène ce dernier facteur premier au vecteur des autres facteurs end ASSERT((n<2 && isempty(vfp)) || (n>=2 && prod(vfp)==n)) % on affirme(vérifie) que le produit des termes trouvés vaut bien n (ou que vfp est vide pour n=0 ou 1) >> FactoriseEntier(2) % test simple ans = 2 >> FactoriseEntier(16) % test simple ans = 2 2 2 2 >> FactoriseEntier(9) % test simple ans = 3 3 >> FactoriseEntier(40) % cas général simple ans = 2 2 2 5 >> FactoriseEntier(200) % cas général simple ans = 2 2 2 5 5 >> FactoriseEntier(9999) % cas général ans = 3 3 11 101 >> FactoriseEntier(103) % nombre premier ans = 103 >> FactoriseEntier(2*103) % nbr composite avec un facteur > sqrt(n) Il peut souvent y avoir des erreurs de programmation sur ce cas ans = 2 103 >> FactoriseEntier(2^19-1) ans = 524287 >> FactoriseEntier(2^23-1) ans = 47 178481 >> FactoriseEntier(2^53-1) ans = 6361 69431 % (nombre de Mersenne) % (nombre de Mersenne) % (nombre de Mersenne) ~Plus grand nombre entier codable en “double float” (⇒ plusieurs secondes de calcul!) 20394401 >> FactoriseEntier(1) % cas particulier ans = Empty matrix: 1-by-0 >> FactoriseEntier(0) % cas particulier ans = Empty matrix: 1-by-0 >> FactoriseEntier(1.2) % cas interdit (nombre non entier) Error using FactoriseEntier (line 14) L'argument n n'est pas un nombre scalaire entier positif plus petit que 2^53 >> FactoriseEntier([99 999 9999]) % cas interdit (vecteur) Error using FactoriseEntier (line 14) L'argument n n'est pas un nombre scalaire entier positif plus petit que 2^53 >> FactoriseEntier(-999) % cas interdit (nombre négatif) Error using FactoriseEntier (line 14) L'argument n n'est pas un nombre scalaire entier positif plus petit que 2^53 >> FactoriseEntier(2E16) % cas interdit (nombre entier trop grand pour être correctement manipulé en “double”) Error using FactoriseEntier (line 14) L'argument n n'est pas un nombre scalaire entier positif plus petit que 2^53