1
Corrigé de l’exercice 12.
# version itérative
def palindrome(chaine):
i, n = 0, len(chaine) - 1
while i < n and chaine[i] == chaine[n]:
i += 1
n -= 1
return n <= i
# version récursive
def palindrome(chaine):
if len(chaine) <= 1:
return True
if chaine[0] != chaine[-1]:
return False
else:
return palindrome(chaine[1:-1])
# variante
def palindrome(chaine):
return chaine == chaine[::-1]
def champernowne(n):
x = '0.'
k = 0
while len(x) <= n+2:
k += 1
x += str(k)
return x[0:n+2]
print(champernowne(75))
0.123456789101112131415161718192021222324252627282930313233343536373839404142
print(cosinus(1, 1e-5))
print(cosinus(1, 1e-14))
print(math.cos(1))
print(cosinus(math.pi/4, 1e-5))
print(cosinus(math.pi/4, 1e-14))
print(math.sqrt(2)/2)
0.5403025793650793
0.5403023058681398
0.5403023058681398
0.7071068056832942
0.7071067811865475
0.7071067811865476
Corrigés des exercices 3
def pythagoriciens(n):
return [(x, y, z) for x in range(1, n) for y in range(x, n)
for z in range(y, n) if x**2 + y**2 == z**2]
print(pythagoriciens(101))
print("Au total, on trouve {} triplets.".format(len(pythagoriciens(101))))
[(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),
(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), (42, 56, 70), (45, 60, 75), (48, 55, 73), (48, 64, 80),
(51, 68, 85), (54, 72, 90), (57, 76, 95), (60, 63, 87), (60, 80, 100),
(65, 72, 97)]
Au total, on trouve 52 triplets.
1^2 = 1
1^2 + 2^2 = 5
1^2 + 2^2 + 3^2 = 14
1^2 + 2^2 + 3^2 + 4^2 = 30
1^2 + 2^2 + 3^2 + 4^2 + 5^2 = 55
1^2 + 2^2 + 3^2 + 4^2 + 5^2 + 6^2 = 91
1^2 + 2^2 + 3^2 + 4^2 + 5^2 + 6^2 + 7^2 = 140
1^2 + 2^2 + 3^2 + 4^2 + 5^2 + 6^2 + 7^2 + 8^2 = 204
1^2 + 2^2 + 3^2 + 4^2 + 5^2 + 6^2 + 7^2 + 8^2 + 9^2 = 285
1^2 + 2^2 + 3^2 + 4^2 + 5^2 + 6^2 + 7^2 + 8^2 + 9^2 + 10^2 = 385
1^2 + 2^2 + 3^2 + 4^2 + 5^2 + 6^2 + 7^2 + 8^2 + 9^2 + 10^2 + 11^2 = 506
[...]
def parfait(n):
return sum([d for d in range(1, n) if n % d == 0]) == n
def liste_parfaits(n):
return [i for i in range(2, n) if parfait(i)]
4 Programmation en Python pour les mathématiques
print(liste_parfaits(10000))
def somme(n):
diviseurs = [d for d in range(1, n) if n % d == 0]
if sum(diviseurs) == n:
print('{} = '.format(n) + ' + '.join(str(d) for d in diviseurs))
for i in liste_parfaits(10000):
somme(i)
6 = 1 + 2 + 3
28 = 1 + 2 + 4 + 7 + 14
496 = 1 + 2 + 4 + 8 + 16 + 31 + 62 + 124 + 248
8128 = 1 + 2 + 4 + 8 + 16 + 32 + 64 + 127 + 254 + 508 + 1016 + 2032 + 4064
def crible(prems):
if prems == []:
return []
return [prems[0]] + crible([p for p in prems[1:] if p % prems[0] != 0])
print(crible(range(2, 1000)))
[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]
Corrigés des exercices
2
Corrigé de l’exercice 27.
import os
import sys
def parcours(repertoire):
arborescence = os.walk(repertoire)
if __name__ == "__main__":
try:
parcours(sys.argv[1])
except IndexError:
parcours(os.getcwd())
if __name__ == "__main__":
N = 14
base = [[0, 0], [2, 0]]
nomFichier = "pythagore"
boite = [-8, -1, 6, 9]
zoom, marge, ratioY, trait = 30, 1.02, 1, 0.1
graphique = Plot(nomFichier, boite, zoom, marge, ratioY)
graphique.preambule()
graphique.cadre()
pythagore(base, 0.9, pi/6, N)
graphique.fin()
graphique.exportePDF()
graphique.affichePS()
90°
import numpy as np
import matplotlib.pyplot as plt 135° 45°
1.4
theta = np.linspace(0, 1 + 1.0 1.2
0.6 0.8
int(38*np.pi), 1000) 0.2 0.4
180° 0°
r = 1 + np.cos(20 * theta / 19) / 3
fig = plt.figure()
ax = Axes3D(fig)
X = np.arange(-3, 3, 0.07)
Y = np.arange(-3, 3, 0.07)
X, Y = np.meshgrid(X, Y)
Z = X * Y / (X**2 + Y**2)
ax.plot_surface(X, Y, Z, linewidth=0.1, rstride=1, cstride=1, cmap=cm.jet)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
0.6
0.4
0.2
0.0 Z
0.2
3
2
1 0.4
0
X 1
2 0.6
3 2 1 0 1 2 3
3
Y
Corrigés des exercices
3
Corrigé de l’exercice 40.
Maintenant, on effectue 7 multiplications matricielles (n 3 multiplications élémentaires) mais
18 additions (n 2 additions élémentaires).
Les multiplications matricielles étant plus coûteuses, théoriquement on gagne en efficacité
pour les grandes matrices. On obtient en effet une complexité en Θ(n log2 n ) au lieu de Θ(n 3 ).
Si la taille des matrices n’est pas une racine de 2, on complète avec des zéros.
On crée donc une fonction qui calcule la puissance de 2 directement supérieure :
def next_pow_2(x):
return 2**(ceil(log(x)/log(2)))
Puis une fonction qui découpe une matrice en quatre blocs carrés après avoir complété avec
des zéros :
matrice.py
def coupe_en_4(self):
[r,c] = self.D
t = max(next_pow_2(r),next_pow_2(c))
m = Mat([t,t], lambda i,j: self[i,j] if (i < r and j < c) else 0)
s = t//2
A = Mat([s, s], lambda i,j: m[i ,j ])
B = Mat([s, s], lambda i,j: m[i ,j + s])
C = Mat([s, s], lambda i,j: m[i + s,j ])
D = Mat([s, s], lambda i,j: m[i + s,j + s])
return(A,B,C,D)
Enfin, on applique les calculs de S TRASSEN récursivement jusqu’à une limite de 32 (qui cor-
respond théoriquement à la limite d’efficacité de l’algo par rapport au nombre d’additions qui
deviennent trop gourmandes) et on découpe la matrice obtenue selon la taille attendue :
matrice.py
def strassen(self,other):
ld = self.D + other.D
t = max(map(next_pow_2,ld))
if t <= 32:
return self*other
a,b,c,d = self.coupe_en_4()
e,f,g,h = other.coupe_en_4()
[li,co] = a.D
Corrigés des exercices 9
p1 = a.strassen(f - h)
p2 = (a + b).strassen(h)
p3 = (c + d).strassen(e)
p4 = d.strassen(g - e)
p5 = (a + d).strassen(e + h)
p6 = (b - d).strassen(g + h)
p7 = (c - a).strassen(e + f)
w = p4 + p5 + p6 - p2
x = p1 + p2
y = p3 + p4
z = p1 + p5 - p3 + p7
def fs(i,j):
if i < li:
if j < li:
return w.F(i,j)
else:
return x.F(i,j - li)
elif j < li:
return y.F(i - li,j)
else:
return z.F(i - li,j - li)
return Mat(self.D, fs)
def contour(m):
[li,co] = m.D
return Mat([li - 2, co - 2],
lambda i,j : floor(sqrt((m[i,j-1]-m[i,j+1])**2 +
(m[i-1,j]-m[i+1,j])**2))
)
ou
def contour(m):
[li,co] = m.D
return Mat([li - 2, co - 2],
lambda i,j : 255 - floor(sqrt((m[i,j-1]-m[i,j+1])**2 +
(m[i-1,j]-m[i+1,j])**2))
)
On obtient alors au choix, avec cette fois Lena de trois-quarts qui a plus de sauts de niveaux :
10 Programmation en Python pour les mathématiques
Ce qui donne :
Bits.py
def mul_russe(self,other):
"""Algo de la multiplication du paysan russe"""
op1,op2 = self.norm(),other.norm()
if op1[0] == 1:
return -((-op1).mul_russe(op2))
if op2[0] == 1:
return -(op1.mul_russe(-op2))
def aux(acc,x,y):
if x == Bits([0,0]):
return acc
return aux(acc + (Bits([0,0]) if x.pair() else y), Bits(x[:-1]),
Bits(y.bits + [0]))
return aux(Bits([0,0]),op1,op2)
op1,op2 = self.norm(),other.norm()
if op1.signe() == 1:
return -((-op1).mul_karat(op2))
if op2.signe() == 1:
return -(op1.mul_karat(-op2))
long = max(len(op1), len(op2))
op1 = Bits([0 for i in range(len(op1), long)] + op1.bits)
op2 = Bits([0 for i in range(len(op2), long)] + op2.bits)
if long <= 2:
return Bits([0, op1[1] & op2[1]])
m0 = (long + 1) >> 1
m1 = long >> 1
p0 = x0.mul_karat(y0)
p1 = (x0 - x1).mul_divis(y0 - y1)
p2 = x1.mul_divis(y1)
return z0 + z1 + z2
Vous remarquerez que les deux dernières multiplications sont moins efficaces avec cette im-
plémentation : en effet, nos additions sont coûteuses contrairement à ce qui se passe sur ma-
chine.
#mul_russe
In [48]: %timeit (n * n)
1000 loops, best of 3: 525 µs per loop
#mul_karat
In [51]: %timeit (n * n)
100 loops, best of 3: 3.14 ms per loop
#mul_divis
In [54]: %timeit (n * n)
100 loops, best of 3: 7.08 ms per loop
#mul_primaire
In [57]: %timeit (n * n)
1000 loops, best of 3: 576 µs per loop
12 Programmation en Python pour les mathématiques
1 1 1 1 1 1 1
365 + − + − + − + +···
4 116 957 7 491 59 020 194 220 1 310 238
On obtient ainsi que tous les 4 ans il faut rajouter un jour, en enlever 1 tous les 116 ans, en
rajouter 1 tous les 957 ans, etc.
1,0000000000000000000000000000000000000000000000000000|
0,0000000000000000000000000000000000000000000000000000|1
--------------------------------------------------------
1,0000000000000000000000000000000000000000000000000000|1
et 2**53 + 2 :
1,0000000000000000000000000000000000000000000000000000|
0,0000000000000000000000000000000000000000000000000001|0
--------------------------------------------------------
1,0000000000000000000000000000000000000000000000000001|0
On a effectué ce « saut » hors de la zone d’erreur car on a atteint la base. Ainsi la valeur finale de
b permet de déterminer la base de calcul du système qui est en général 2. Un contre-exemple
notoire est le logiciel Maple qui travaille en base 10.
De manière plus rigoureuse, on peut raisonner dans Vβ l’espace des VF de base β. Notons R la
fonction d’arrondi.
Les lignes 4 à 6 construisent une suite a i = R(2a i −1 ) avec a 0 = 1.0 mais est-on sûr que l’on a
toujours a i = 2i dans ces conditions ?
On démontre d’abord par récurrence que a i = R(2i ) = 2i tant que i vérifie 2i 6 βp − 1 : 2i =
2 × 2i −1 est un entier qui s’écrit avec moins de p chiffres de la base β et en deçà de βp − 1, on
peut passer d’un flottant à son successeur par des pas inférieurs à 1.
Alors R(a i + 1.0) = a i + 1.0 : pas d’arrondi.
Corrigés des exercices 13
Puis R(R(a i + 1.0) − a i ) = R(a i + 1.0 − a i ) = 1.0 : la condition de la première boucle est donc
vérifiée tant que 2i < βp . Que se passe-t-il après ?
Dès que βp − 1 est atteint, les choses changent.
Considérons la première itération i s telle que 2i s > βp .
On a
a i s = R(2 × a i s −1 ) = R(2 × 2i s −1 ) < R(2 × βp ) 6 R(β × βp ) = βp+1
car d’une part a i s −1 = 2i s −1 , d’autre part a i s −1 6 βp − 1 < βp et enfin 2 6 β.
Ainsi
βp 6 a i s < βp+1
L’exposant de la forme normale de a i s est donc p et le successeur d’un VF v vérifie (en notant
n = p − 1 la longueur de la pseudo-mantisse) :
– elle nous montre bien que nous changeons de monde : un test du style if (a + 1.0)-
a /= 1.0 paraîtrait bien hors de propos si nous raisonnions avec des réels ;
– nous avons vu que l’on pouvait raisonner rigoureusement sur les VF ;
– nous pouvons malgré tout retenir la trame intuitive de la démonstration : tant que notre
nombre entier est représentable avec p chiffres, on reste exact. Les problèmes arrivent
lorsqu’on n’a plus assez de place pour stocker tous les chiffres : il y a de la perte d’infor-
mation...
– Ce genre de raisonnement se retrouve très souvent pour travailler sur les erreurs com-
mises : il faudra donc en retenir la substantifique moelle...
import numpy
class ODE(object):
def __init__(self, f, h):
self.f = lambda u, t: numpy.asarray(f(u, t), float) # 1ère modification
self.h = h
def iteration(self):
raise NotImplementedError
self.h = - self.h
self.indice = 0
while (self.liste[0][0] >= a and
not termine(self.liste[0][1])):
self.liste.insert(0, self.iteration())
return self.liste
class Euler(ODE):
def iteration(self):
f, h = self.f, self.h
[t, x] = self.liste[self.indice]
return [t + h, x + h * f(t, x)]
class RK4(ODE):
def iteration(self):
f, h = self.f, self.h
[t, x] = self.liste[self.indice]
k1 = h * f(t, x)
k2 = h * f(t + h/2, x + k1/2)
k3 = h * f(t + h/2, x + k2/2)
k4 = h * f(t + h, x + k3)
return [t + h, x + (k1 + 2*k2 + 2*k3 + k4) / 6]
if __name__ == '__main__':
######################################
### L'exponentielle : Euler vs RK4 ###
######################################
a, b, h = 0, 1, 0.1
liste_exacte = ((t, exp(t)) for t in ps.srange(a, b, h))
######################################################################
### Un exemple d'équation différentielle non linéaire du 1er ordre ###
######################################################################
a, b, h = -4, 4, 0.01
bleu = (0, 0, 1)
boite = [-4.5, -4.5, 4.5, 4.5] # xmin, ymin, xmax, ymax
def horscadre(x):
return abs(x) > 4.5
courbes = []
######################################
### Un exemple de système autonome ###
######################################
def horscadre(x):
return abs(max(x)) > 4
a, b, h = 0, 30, 0.01
sol = RK4(f, h) # RK4 ... et non plus RK4_systeme
sol.CI(0, [0.01, 0.01])
solution = (x[1] for x in sol.resolution(a, b, horscadre))
courbes = [[solution, (1, 0, 0)]]
b = 15
for k in ps.srange(0, 20, 0.4):
###################################################################
### Un exemple d'équation différentielle linéaire du 2eme ordre ###
###################################################################
Si l’on souhaite représenter graphiquement les solutions avec le module matplotlib et non
plus avec PostScript.py, on peut procéder comme suit :
import numpy
import matplotlib.pyplot as plt
class ODE(object):
def iteration(self):
raise NotImplementedError
class RK4(ODE):
def iteration(self):
f, h = self.f, self.h
[t, x] = self.liste[self.indice]
k1 = h * f(t, x)
k2 = h * f(t + h/2, x + k1/2)
k3 = h * f(t + h/2, x + k2/2)
k4 = h * f(t + h, x + k3)
return [t + h, x + (k1 + 2*k2 + 2*k3 + k4) / 6]
if __name__ == '__main__':
######################################################################
### Un exemple d'équation différentielle non linéaire du 1er ordre ###
######################################################################
20 Programmation en Python pour les mathématiques
a, b, h = -4, 4, 0.01
def horscadre(x):
return abs(x) > 4.5
plt.figure()
plt.ylim(-4, 4)
plt.xlabel('t')
plt.ylabel('x')
sol = RK4(f, h)
sol.CI(0, k)
x = numpy.array(sol.resolution(a, b, horscadre))
plt.plot(x[:,0], x[:,1], color=(0, 0, 1))
plt.show()
######################################
### Un exemple de système autonome ###
######################################
def horscadre(x):
return abs(max(x)) > 5
a, b, h = 0, 30, 0.03
plt.figure()
plt.ylim(-4, 4)
plt.xlabel('x')
plt.ylabel('y')
sol = RK4(f, h)
sol.CI(0, [0.01, 0.01])
x = numpy.array([x[1] for x in sol.resolution(a, b, horscadre)])
b = 15
sol = RK4(f, h)
sol.CI(0, [0.3*k-3, 3])
x = numpy.array([x[1] for x in sol.resolution(a, b, horscadre)])
plt.plot(x[:,0], x[:,1], color=(k/20, 0.32, 0.48-k/44))
sol = RK4(f, h)
sol.CI(0, [3-0.3*k, -3])
x = numpy.array([x[1] for x in sol.resolution(a, b, horscadre)])
plt.plot(x[:,0], x[:,1], color=(k/20, 0.32, 0.48-k/44))
plt.show()
###################################################################
### Un exemple d'équation différentielle linéaire du 2eme ordre ###
###################################################################
plt.figure()
plt.xlim(0, 19)
plt.xlabel('x')
plt.ylabel('y')
sol = RK4(f, h)
sol.CI(a, [0.2*k-2, 0])
x = numpy.array([[x[0], x[1][0]] for x in sol.resolution(a, b)])
plt.plot(x[:,0], x[:,1], color=(k/20, 0.32, 0.48-k/44))
plt.show()
22 Programmation en Python pour les mathématiques
4
4
3
3
2
2
1
1
y
0
x
1
1
2
2
3
3
4
4 4 3 2 1 0 1 2 3 4
3 2 1 0 1 2 3 x
t
10
0
y
10
0 5 10 15
x
4*I = 3.1415926535897922
12*(J-sqrt(3)/8) = 3.141592653589793
numpy.pi = 3.141592653589793
Corrigés des exercices 23
0
for k in np.arange(-4, 4, 0.2):
t = np.linspace(0, 4, 1000)
x = odeint(f, k, t)
1
plt.plot(t, x[:, 0], color='b')
def f(x,t):
return [x[1], 0.5 * x[1] - x[0] - x[1]**3]
plt.figure()
plt.xlabel('x')
plt.ylabel('y')
CI = [0.3*k-3, 3]
y = odeint(f, CI, t)
plt.plot(y[:, 0], y[:, 1], color=(k/20, 0.32, 0.48-k/44))
CI = [0.3*k-3, -3]
y = odeint(f, CI, t)
plt.plot(y[:, 0], y[:, 1], color=(k/20, 0.32, 0.48-k/44))
plt.show()
0
y
3
4 3 2 1 0 1 2 3 4
x
plt.figure()
plt.subplots_adjust(hspace=0.25)
CI = [0.01, 0.01]
y = odeint(f, CI, t)
Corrigés des exercices 25
plt.subplot(2, 1, 1)
plt.xlabel('t')
plt.ylabel('x(t)')
plt.plot(t, y[:, 0], color=(1, 0, 0)) # tracé des points (t, x(t))
plt.subplot(2, 1, 2)
plt.xlabel('t')
plt.ylabel('y(t)')
plt.plot(t, y[:, 1], color=(1, 0, 0)) # tracé des points (t, y(t))
CI = [0.3*k-3, 3]
y = odeint(f, CI, t)
plt.subplot(2, 1, 1)
plt.plot(t, y[:, 0], color=(k/20, 0.32, 0.48-k/44))
plt.subplot(2, 1, 2)
plt.plot(t, y[:, 1], color=(k/20, 0.32, 0.48-k/44))
CI = [3-0.3*k, -3]
y = odeint(f, CI, t)
plt.subplot(2, 1, 1)
plt.plot(t, y[:, 0], color=(k/20, 0.32, 0.48-k/44))
plt.subplot(2, 1, 2)
plt.plot(t, y[:, 1], color=(k/20, 0.32, 0.48-k/44))
plt.show()
3
2
1
0
x(t)
1
2
3
0 5 10 15 20 25 30 35 40
t
3
2
1
0
y(t)
1
2
3
0 5 10 15 20 25 30 35 40
t
26 Programmation en Python pour les mathématiques
Les trois graphiques précédents peuvent être construits simultanément et placés dans un
unique objet plt.figure().
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
def f(x,t):
return [x[1], 0.5 * x[1] - x[0] - x[1]**3]
plt.figure()
plt.subplots_adjust(hspace=0.25,wspace=0.3)
CI = [0.01, 0.01]
y = odeint(f, CI, t)
plt.subplot(2, 2, 1)
plt.xlabel('t')
plt.ylabel('x(t)')
plt.plot(t, y[:, 0], color=(1, 0, 0))
plt.subplot(2, 2, 3)
plt.xlabel('t')
plt.ylabel('y(t)')
plt.plot(t, y[:, 1], color=(1, 0, 0))
plt.subplot(1, 2, 2)
plt.xlabel('x(t)')
plt.ylabel('y(t)')
plt.plot(y[:, 0], y[:, 1], color=(1, 0, 0))
CI = [0.3*k-3, 3]
y = odeint(f, CI, t)
plt.subplot(2, 2, 1)
plt.plot(t, y[:, 0], color=(k/20, 0.32, 0.48-k/44))
plt.subplot(2, 2, 3)
plt.plot(t, y[:, 1], color=(k/20, 0.32, 0.48-k/44))
plt.subplot(1, 2, 2)
plt.plot(y[:, 0], y[:, 1], color=(k/20, 0.32, 0.48-k/44))
Corrigés des exercices 27
CI = [3-0.3*k, -3]
y = odeint(f, CI, t)
plt.subplot(2, 2, 1)
plt.plot(t, y[:, 0], color=(k/20, 0.32, 0.48-k/44))
plt.subplot(2, 2, 3)
plt.plot(t, y[:, 1], color=(k/20, 0.32, 0.48-k/44))
plt.subplot(1, 2, 2)
plt.plot(y[:, 0], y[:, 1], color=(k/20, 0.32, 0.48-k/44))
plt.show()
3 3
1
2
0
x(t)
1
1
2
3
0 5 10 15 20 25 30 35 40
t 0
y(t)
2
1
1
0
y(t)
2
1
3 3
0 5 10 15 20 25 30 35 40 3 2 1 0 1 2 3
t x(t)
plt.figure()
plt.xlabel('t')
plt.ylabel('x')
28 Programmation en Python pour les mathématiques
CI = [0.2*k-2, 0]
x = odeint(f, CI, t)
plt.plot(t, x[:, 0], color=(k/20, 0.32, 0.48-k/44))
plt.show()
30
20
10
0
x
10
20
30
0 5 10 15 20
t
Corrigés des exercices
5
Corrigé de l’exercice 60.
table.py
def table(multiplicande, multiplicateur):
if multiplicateur > 0:
table(multiplicande, multiplicateur - 1)
table(7, 10)
if multiplicateur > 0:
table_decroissante(multiplicande, multiplicateur - 1)
table_decroissante(7, 10)
On observera dans le chapitre suivant l’intérêt d’une telle souplesse pour les parcours d’arbre
binaire.
arrange1.py
def arrangement(k, n):
if n >= k:
return n * arrangement(k, n - 1)
else:
return 1
print(arrangement(7, 10))
if n >= k:
return __arrangement(acc * n, k, n - 1)
else:
return acc
print(arrangement(7, 10))
Il est à noter que la paire de caractères « underscore » fait l’objet d’une convention en Python :
leur présence a pour effet de supprimer la visibilité de la définition (portée) hors du module :
ici la fonction __arrangement() est à l’usage unique de arrangement() (ou de toute autre
définition au sein du même fichier source).
def impair(n):
if n > 0:
return pair(n - 1)
else:
return False
print(pair(17))
print(pair(18))
def carre(c):
carre_rec(4, c)
if num > 0:
carre(cote)
forward(cote)
left(90)
cote += 10
dessin(num - 1, cote)
if __name__ == "__main__":
dessin(15, 50)
exitonclick() # un clic de souris termine le programme.
#
# d\'eveloppement limit\'e de cos
#
def developpement_lim_cos(x):
return (x - (x**2)/2 + (x**4)/24 - (x**6)/720 + (x**8)/40320)
#
# approximation (r\'ecursive) de cos(x):
# le param\`etre "epsilon" d\'efinit la valeur absolue de x
# en dessous de laquelle on utilise le d\'eveloppement limit\'e
#
def cosinus(x, epsilon):
if abs(x) < epsilon:
return developpement_lim_cos(x)
else:
return (2 * cosinus(x/2, epsilon)**2 - 1)
#
# test de la fonction cosinus()
#
def test_cosinus(x, epsilon =0.000001):
print("pour x = {0} (epsilon = {1}):".format(x, epsilon))
appcos.py
import cosinus
import math
def test_unitaire_0():
print("*** cosinus: test_unitaire_0 ***")
32 Programmation en Python pour les mathématiques
cosinus.test_cosinus(0.1)
ok = True
return ok
def test_unitaire_1():
print("*** cosinus: test_unitaire_1 ***")
cosinus.test_cosinus(10)
cosinus.test_cosinus(200)
cosinus.test_cosinus(-4)
ok = True
return ok
def test_unitaire_2():
print("*** cosinus: test_unitaire_2 ***")
# cosinus.test_cosinus(math.pi / 1000)
# cosinus.test_cosinus(math.pi / 1000, 0.1)
# cosinus.test_cosinus(math.pi / 1000, 0.01)
# cosinus.test_cosinus(math.pi / 1000, 0.001)
# cosinus.test_cosinus(math.pi / 1000, 0.0001)
# cosinus.test_cosinus(math.pi / 1000, 0.0000001)
# cosinus.test_cosinus(math.pi / 1000, 0.00000001)
# cosinus.test_cosinus(math.pi / 1000, 0.000000001)
ok = True
return ok
def test_unitaire_():
print("*** cosinus: test_unitaire_ ***")
ok = True
return ok
def tests_unitaires():
return (
test_unitaire_0() and \
test_unitaire_1() and \
test_unitaire_2()
)
if __name__ == "__main__":
ok = tests_unitaires()
if ok:
Corrigés des exercices 33
Le programme suivant permet de se faire une idée de la précision standard du type natif float
de Python :
nombre_decimales.py
def nombre_decimales(a, b):
if float(a) + float(b) == float(a):
return 0
else:
return 1 + nombre_decimales(a, b/10)
print(nombre_decimales(1, 1))
def partie_entiere_racine(x):
return __partie_entiere_racine_rec(1, x)
print(partie_entiere_racine(17))
print(partie_entiere_racine(36703))
#
# (a, b) dans Z x N*
#
def __fraction_cont_b_pos(a, b):
q = []
if a < 0:
q.append(-((-a + b) // b))
else:
q.append(a // b)
return q + __fraction_cont_pos([], a - b * q[0], b)[1:]
#
# (a, b) dans Z x Z*
#
def fraction_cont(a, b):
if b < 0:
return __fraction_cont_b_pos(-a, -b)
else:
return __fraction_cont_b_pos(a, b)
x = fraction_cont(111, 40)
print(x)
x = fraction_cont(-111, 40)
print(x)
def tete(l):
if est_vide(l):
return None
else:
return l[0]
def suite(l):
if est_vide(l):
return []
else:
return l[1:]
def longueur(l):
if est_vide(l):
return 0
Corrigés des exercices 35
else:
return 1 + longueur(suite(l))
if tete(liste) == x:
return True
if __name__ == "__main__":
hasard = [random.randrange(50) for t in range(20)]
print(longueur(hasard)) # donne 20
print(hasard)
print(tete(hasard))
print(suite(hasard))
36 Programmation en Python pour les mathématiques
print(debut(2, hasard))
print(coupe(2, hasard))
n = longueur(hasard)
for i in range(n):
print(debut(1, hasard))
hasard = coupe(1, hasard)
6
Corrigés des exercices
def __str__(self):
return str(self.__elements)
def extraire(self):
if len(self.__elements) == 0:
return None
x = self.__elements[self.__indice_ext]
del self.__elements[self.__indice_ext]
return x
def lire(self):
return self.__elements[self.__indice_ext]
def est_vide(self):
return (len(self.__elements) == 0)
mafile.py
import maliste
class mafile(maliste.maliste):
def extraire_premier(self):
return self.extraire()
def lire_premier(self):
return self.lire()
mapile.py
import maliste
class mapile(maliste.maliste):
def depiler(self):
return self.extraire()
def lire_sommet(self):
return self.lire()
if __name__ == "__main__":
p = mapile()
print(p)
x = p.extraire()
while x is not None:
print(x)
x = p.extraire()
acc.inscrire(int(x))
else:
if x == "+":
b = acc.extraire()
a = acc.extraire()
acc.inscrire(a + b)
if x == "-":
b = acc.extraire()
a = acc.extraire()
acc.inscrire(a - b)
if x == "*":
b = acc.extraire()
a = acc.extraire()
acc.inscrire(a * b)
if x == "/":
b = acc.extraire()
a = acc.extraire()
acc.inscrire(a / b)
boucle(acc, p)
def evaluer(p):
acc = mapile.mapile()
boucle(acc, p)
print(acc.extraire())
if __name__ == "__main__":
f = mafile.mafile()
for c in "423+*5-":
f.inscrire(c)
evaluer(f)
#
# (a, b) dans N x N*
#
def reste(a, b):
if a < b:
return a
else:
40 Programmation en Python pour les mathématiques
return reste(a - b, b)
#
# (a, b) dans N x N*
#
def quotient_entier(a, b):
if a < b:
return 0
else:
return 1 + quotient_entier(a - b, b)
#
# (a, b) dans N x N
#
def pgcd(a, b):
if b == 0:
return a
else:
return pgcd(b, reste(a, b))
#
# (a, b) dans N x N*
#
def fraction_cont_pos(q, a, b):
q.append(quotient_entier(a, b))
if reste(a, b) > 0:
return fraction_cont_pos(q, b, reste(a, b))
else:
return q
#
# (a, b) dans Z x N*
#
def fraction_cont_b_pos(a, b):
q = []
if a < 0:
q.append(-quotient_entier(-a + b, b))
else:
q.append(quotient_entier(a, b))
return q + fraction_cont_pos([], a - b * q[0], b)[1:]
#
# (a, b) dans Z x Z*
#
def fraction_cont(a, b):
if b < 0:
return fraction_cont_b_pos(-a, -b)
else:
return fraction_cont_b_pos(a, b)
Corrigés des exercices 41
La classe rationnel définit un objet représentant une fraction. Les méthodes pour l’addition
et la division sont les seules nécessaires à la construction de la fraction réduite.
rationnel.py
import outils
class rationnel(object):
if denom < 0:
p = -num
q = -denom
else:
p = num
q = denom
d = outils.pgcd(abs(p), q)
self.__num = p // d
self.__denom = q // d
def __str__(self):
""" representation en chaine de caracteres """
if self.__denom == 1:
return str(self.__num)
else:
return str(self.__num) + "/" + str(self.__denom)
def fraction_continue(self):
""" """
return outils.fraction_cont(self.__num, self.__denom)
42 Programmation en Python pour les mathématiques
def calcul_reduite(quotients):
return reduite(quotients, rationnel())
if __name__ == "__main__":
r = rationnel(4291, 1329)
print(r)
a = r.fraction_continue()
print(a)
print(calcul_reduite(a))
def partie_entiere_racine(x):
return __partie_entiere_racine_rec(1, x)
if __name__ == "__main__":
print(partie_entiere_racine(17))
print(partie_entiere_racine(36703))
def f(u):
m, d, a, k, p_e_k = u[0], u[1], u[2], u[3], u[4]
mp = d*a - m
dp = (k - mp**2) // d
ap = (p_e_k + mp) // dp
def boucle(u_0):
n = 0
acc = []
boucle_rec(acc, n, u_0)
return [u[2] for u in acc]
def calcul(k):
p_e_k = partent.partie_entiere_racine(k)
if p_e_k**2 == k:
return [p_e_k]
else:
u_0 = (0, 1, p_e_k, k, p_e_k)
return boucle(u_0)
if __name__ == "__main__":
print(calcul(8))
print(calcul(9))
print(calcul(11))
print(calcul(12))
print(calcul(13))
print(calcul(61))
print(calcul(227))
print(calcul(263))
import fraccont3
def test_unitaire_0():
print("*** fraccont3: test_unitaire_0 ***")
c = fraccont3.calcul(61)
print(c)
ok = True
return ok
def test_unitaire_1():
print("*** fraccont3: test_unitaire_1 ***")
c = fraccont3.calcul(n)
print("{0} = {1}\n".format(c ,fc2.calcul_reduite(c)))
ok = True
return ok
def test_unitaire_2():
print("*** fraccont3: test_unitaire_2 ***")
ok = True
return ok
def test_unitaire_3():
print("*** fraccont3: test_unitaire_3 ***")
ok = True
return ok
def test_unitaire_4():
print("*** fraccont3: test_unitaire_4 ***")
ok = True
return ok
def test_unitaire_5():
print("*** fraccont3: test_unitaire_5 ***")
Corrigés des exercices 45
ok = True
return ok
def test_unitaire_6():
print("*** fraccont3: test_unitaire_6 ***")
ok = True
return ok
def test_unitaire_7():
print("*** fraccont3: test_unitaire_7 ***")
ok = True
return ok
def test_unitaire_8():
print("*** fraccont3: test_unitaire_8 ***")
ok = True
return ok
def test_unitaire_9():
print("*** fraccont3: test_unitaire_9 ***")
ok = True
return ok
def test_unitaire_():
print("*** fraccont3: test_unitaire_ ***")
ok = True
return ok
def tests_unitaires():
return (
test_unitaire_0() and \
test_unitaire_1() and \
test_unitaire_2() and \
test_unitaire_3() and \
test_unitaire_4() and \
test_unitaire_5() and \
test_unitaire_6() and \
test_unitaire_7() and \
test_unitaire_8() and \
test_unitaire_9()
)
if __name__ == "__main__":
ok = tests_unitaires()
46 Programmation en Python pour les mathématiques
if ok:
print("*** fraccont3: tests unitaires OK ***")
class arbre(object):
def __hauteur(self):
hauteur_a_gauche = 0
if self.__gauche is not None:
hauteur_a_gauche = self.__gauche.__hauteur()
hauteur_a_droite = 0
if self.__droit is not None:
hauteur_a_droite = self.__droit.__hauteur()
def __delta_hauteur(self):
hauteur_a_gauche = 0
if self.__gauche is not None:
hauteur_a_gauche = self.__gauche.__hauteur()
hauteur_a_droite = 0
if self.__droit is not None:
hauteur_a_droite = self.__droit.__hauteur()
def __rotation_a_gauche(self):
self.__clef, self.__droit.__clef = self.__droit.__clef, self.__clef
t = self.__gauche
self.__gauche = self.__droit
self.__droit = self.__droit.__droit
self.__gauche.__droit = self.__gauche.__gauche
self.__gauche.__gauche = t
def __rotation_a_droite(self):
self.__clef, self.__gauche.__clef = self.__gauche.__clef, self.__clef
t = self.__droit
self.__droit = self.__gauche
self.__gauche = self.__gauche.__gauche
self.__droit.__gauche = self.__droit.__droit
self.__droit.__droit = t
def __equilibrer(self):
d = self.__delta_hauteur()
if d > 1:
if self.__gauche.__delta_hauteur() < 1:
self.__gauche.__rotation_a_gauche()
self.__rotation_a_droite()
if d < -1:
if self.__droit.__delta_hauteur() > -1:
self.__droit.__rotation_a_droite()
self.__rotation_a_gauche()
else:
self.__droit.inserer(clef)
self.__equilibrer()
import random
for i in range(nombre_noeuds):
noeuds.append(noeuds[-1] + random.randrange(1, 10))
i = random.randrange(nombre_noeuds)
t = noeuds[i]
del noeuds[i]
a = avl.arbre(t)
for n in range(len(noeuds)):
a.inserer(noeuds[n])
if visible: a.afficher()
ok = True
return ok
Corrigés des exercices 49
for i in range(nombre_noeuds):
noeuds.append(noeuds[-1] + random.randrange(1, 10))
if visible: print(noeuds)
#
# on prend une copie (profonde) de a
#
copie = list(noeuds)
i = random.randrange(nombre_noeuds)
t = noeuds[i]
del noeuds[i]
a = avl.arbre(t)
for n in range(len(noeuds)):
a.inserer(noeuds[n])
if visible: a.afficher()
if visible: print("-----")
#
# on prend la copie de a et on y met un peu d'entropie.
#
if visible: print(copie)
k = random.randrange(1, 10)
for i in range(1, k):
t = copie[0]
copie.append(t)
del copie[0]
if visible: print(copie)
i = random.randrange(nombre_noeuds)
t = copie[i]
del copie[i]
b = avl.arbre(t)
for n in range(len(copie)):
b.inserer(copie[n])
50 Programmation en Python pour les mathématiques
if visible: b.afficher()
ok = True
return ok
ok = True
return ok
ok = True
return ok
def tests_unitaires():
return (
test_unitaire_0(True) and \
test_unitaire_1(True) and \
test_unitaire_2()
)
if __name__ == "__main__":
ok = tests_unitaires()
if ok:
print("*** arbre: tests unitaires OK ***")