CORRIGÉ du TD n°2 - Institut d`Optique Graduate School

publicité
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
Téléchargement