#!/usr/bin/env python
# coding: utf-8
#
#
TP 4 (fonctions) : éléments de correction
# ## 1. Définir une fonction
#
# Exercice 1 : occurences
#
# In[1]:
def Occurrences(a, L):
"""
Renvoie le nombre d'occurences (i.e. d'apparitions)
de l'élément a dans la liste L
"""
n = 0 # initialisation du compteur
for k in range(len(L)):
if a == L[k]: # test d'égalité + confusion entre k et L[k] + oubli des ":"
n = n + 1
return n # mauvaise indentation
# In[2]:
# test avec la liste vide
Occurrences(1, [])
# In[3]:
# test avec plusieurs occurences
Occurrences(1, [1, 2, 3, 4, 1, 2, 3, 4, 1])
# In[4]:
# test sans occurrence
Occurrences(1, [2, 3, 4, 5])
# On pourrait également utiliser un autre type de parcours de liste, qui se fait élément par élément :
# In[5]:
def Occurrences(a, L):
"""
Renvoie le nombre d'occurences (i.e. d'apparitions)
de l'élément a dans la liste L
"""
n = 0
for elt in L:
if a == elt:
n = n + 1
return n
#
# Exercice 2 : premières fonctions
#
# ### Question 1
# On va utiliser une liste par compréhension :
# In[6]:
import random as rd
# In[7]:
def listealeatoire(n, a, b):
"""
Renvoie une liste de n entiers aleatoires compris entre a et b.
"""
return [rd.randint(a, b) for i in range(n)]
# In[8]:
listealeatoire(4, 1, 5)
# In[9]:
listealeatoire(0, 1, 10)
# In[10]:
listealeatoire(3, 2, 2)
# ### Question 2
# On adapte un script du TP précédent pour le transformer en fonction :
# In[11]:
def maxi(L):
"""
Renvoie le maximum des elements d’une liste de nombres L.
"""
M = L[0]
for k in range(len(L)):
if L[k] > M:
M = L[k]
return M
# In[12]:
maxi([])
# Notre fonction ne fonctionne pas avec une liste vide...
# In[13]:
def maxi(L):
"""
Renvoie le maximum des elements d’une liste de nombres L.
"""
if len(L) == 0:
return None
else:
M = L[0]
for k in range(len(L)):
if L[k] > M:
M = L[k]
return M
# In[14]:
maxi([])
# In[15]:
maxi([1, 2, 3, 4, 5, 4, 3, 2, 1])
# In[16]:
maxi([5, 4, 3, 2, 1])
# **Remarque :**
# > on peut également utiliser un parcours des éléments de la liste ```L``` de la façon suivante :
# In[17]:
def maxi(L):
"""
Renvoie le maximum des elements d’une liste de nombres L.
"""
if len(L) == 0:
return None
else:
M = L[0]
for elt in L:
if elt > M:
M = elt
return M
# ### Question 3
# In[70]:
def mini(L):
"""
Renvoie le minimum des elements d’une liste de nombres L.
"""
if len(L) == 0:
return None
else:
M = L[0]
for elt in L:
if elt < M:
M = elt
return M
# In[77]:
def minmax(N, n, a, b):
"""
genere N listes de n entiers aleatoires compris entre a et b,
determine le maximum des elements de chacune de ces listes
et renvoie le minimum de ces maximums.
"""
if n==0:
return None
else:
Lmax=[]
for k in range(N):
L=listealeatoire(n,a,b)
M=maxi(L)
Lmax.append(M)
return mini(Lmax)
# In[78]:
minmax(0, 10, 2, 3)
# In[79]:
minmax(10, 0, 2, 3)
# In[80]:
minmax(10,12,1,5)
# In[ ]:
# In[18]:
def minmax(N, n, a, b):
"""
genere N listes de n entiers aleatoires compris entre a et b,
determine le maximum des elements de chacune de ces listes
et renvoie le minimum de ces maximums.
"""
if N == 0 or n == 0:
return None
else:
L = listealeatoire(n, a, b)
M = maxi(L)
m = M
for k in range(N - 1):
L = listealeatoire(n, a, b)
M = maxi(L)
if M < m:
m = M
return m
# In[19]:
minmax(0, 10, 2, 3)
# In[20]:
minmax(10, 0, 2, 3)
# In[21]:
minmax(10,12,1,5)
#
# Exercice 3 : coefficients binomiaux
#
# In[22]:
def factorielle(n):
"""
Renvoie la factorielle de n.
"""
f = 1
for k in range(1, n + 1):
f = f * k
return f
# ### Question 1
# In[23]:
def coeff(n, k):
"""
Renvoie le coefficient binomial "k parmi n"
"""
return factorielle(n) // factorielle(k) // factorielle(n - k)
# In[24]:
coeff(0, 0)
# In[25]:
coeff(3, 1)
# In[26]:
coeff(9, 6)
# In[27]:
[coeff(4, k) for k in range(5)]
# In[28]:
coeff(50, 13)
# In[29]:
coeff(10000, 9997)
# On peut même afficher le début du triangle de Pascal :
# In[30]:
for n in range(6):
print([coeff(n, k) for k in range(n + 1)])
# ### Question 2
# In[31]:
def LigneSuivante(L):
"""
Reçoit une liste de nombres L
et renvoie la liste M définie comme dans l'énoncé
"""
M = [L[0]]
for k in range(1, len(L)):
M.append(L[k - 1] + L[k])
M.append(L[len(L) - 1])
return M
# In[32]:
LigneSuivante([1, 5, 10, 10, 5, 1])
# Une variante, avec une liste par compréhension :
# In[33]:
def LigneSuivante(L):
"""
Reçoit une liste de nombres L
et renvoie la liste M définie comme dans l'énoncé
"""
M = [L[0]] + [L[k - 1] + L[k] for k in range(1, len(L))] + [L[len(L) - 1]]
return M
# In[34]:
LigneSuivante([1, 5, 10, 10, 5, 1])
# In[35]:
LigneSuivante([1])
# ### Question 3
# In[36]:
def Pascal(N):
"""
Affiche les N premieres lignes du triangle de Pascal.
"""
L = [1]
print(L)
for k in range(N):
L = LigneSuivante(L)
print(L)
return None
# In[37]:
Pascal(5)
# On pourrait chronométrer les 2 façons de faire pour voir que la 2ème est plus efficace : vous pouvez vous inspirer de l'exercice 6 pour faire des tests chez vous !
# ## 2. Nombres premiers
#
# Exercice 4 : algorithme naïf
#
# ### Questions 1 et 2
# In[38]:
from math import sqrt
# In[39]:
def estpremier(n):
"""
Teste si un nombre entier naturel est premier.
"""
if n == 0 or n == 1:
return False
for k in range(2, int(sqrt(n)) + 1):
if n % k == 0:
return False
return True
# In[40]:
for n in range(21):
if estpremier(n):
print(n, end=' ')
print() # pour le retour a la ligne
# ### Question 3
# On peut utiliser un compteur pour chaque nombre premier :
# In[41]:
cpt = 0
for n in range(1001):
if estpremier(n):
cpt += 1
print("Il y a {} nombres premiers inférieurs (ou égaux) à 1000.".format(cpt))
# Python est assez souple en ce qui concerne les sommes : il peut sommer des booléens (```True``` vaut alors 1 et ```False``` vaut 0). On peut donc également proposer la version suivante :
# In[42]:
S = sum([estpremier(n) for n in range(1001)])
# In[43]:
print("Il y a {} nombres premiers inférieurs (ou égaux) à 1000.".format(S))
# ### Question 4
# On va utiliser une boucle ```while```, jusqu'à obtenir un nombre premier :
# In[44]:
n = 10**10
while not (estpremier(n)):
n = n + 1
print("Le plus petit nombre premier supérieur à 10**10 est {}.".format(n))
#
# Exercice 5 : crible d'Ératosthène
#
# In[45]:
def Crible(N):
"""
Implémente le crible d'Eratosthene
"""
C = [True for k in range(N)]
C[0] = False
C[1] = False
for k in range(2, N):
if C[k]:
for i in range(2*k,N,k):
C[i] = False
return (C)
# In[46]:
C1 = Crible(20)
for n in range(20):
if C1[n]: # Test : n est-il premier ?
print(n, end=' ')
print()
# On peut également utiliser une liste définie par compréhension (avec une condition) :
# In[47]:
[n for n in range(20) if C1[n]]
# On retrouve également le résultat de la question 3 de l'exercice précédent :
# In[48]:
C2 = Crible(1000)
c = 0
for n in range(1000):
if C2[n]:
c += 1
print(c)
# ou bien également :
# In[49]:
sum(C2)
#
# Exercice 6 : comparaison des algorithmes
#
# In[50]:
from time import time
# In[51]:
N = 100
t1 = time()
C = [estpremier(n) for n in range(N + 1)]
t2 = time()
print("Temps avec la version naïve :", t2 - t1)
t1 = time()
C = Crible(N + 1)
t2 = time()
print("Temps avec le crible d'Eratosthene :", t2 - t1)
# In[52]:
N = 10**4
t1 = time()
C = [estpremier(n) for n in range(N + 1)]
t2 = time()
print("Temps avec la version naïve :", t2 - t1)
t1 = time()
C = Crible(N + 1)
t2 = time()
print("Temps avec le crible d'Eratosthene :", t2 - t1)
# In[53]:
N = 10**5
t1 = time()
C = [estpremier(n) for n in range(N + 1)]
t2 = time()
print("Temps avec la version naïve :", t2 - t1)
t1 = time()
C = Crible(N + 1)
t2 = time()
print("Temps avec le crible d'Eratosthene :", t2 - t1)
# ## 3. Compléments
#
# Exercice 7 : nombres parfaits et amis
#
# ### Question 1
# Dès qu'on le peut, on utilise une liste par compréhension :
# In[54]:
def diviseurs(n):
"""
reçoit un entier n positif,
et renvoie la liste de ses diviseurs autres que lui-meme.
"""
D = [k for k in range(1, n) if n % k == 0]
return D
# In[55]:
diviseurs(12)
# On peut bien sûr quand même construire la liste élément par élément :
# In[56]:
def diviseurs(n):
"""
Reçoit un entier n positif,
et renvoie la liste de ses diviseurs autres que lui-meme.
"""
D = []
for k in range(1, n):
if n % k == 0:
D.append(k)
return D
# In[57]:
diviseurs(30)
# ### Question 2 : nombres parfaits
# On dresse la liste de tous les nombres
# parfaits strictement inférieurs à $10^4$ :
# In[58]:
P = []
N = 10**4
for n in range(N):
D = diviseurs(n)
if n == sum(D):
P.append(n)
print(P)
# ### Question 3 : Nombres amis
# Une première version, naïve et peu efficace :
# In[59]:
A = []
N = 10**3
for a in range(N):
for b in range(a + 1, N): # pour éviter les doublons
if a == sum(diviseurs(b)) and b == sum(diviseurs(a)):
A.append((a, b))
print(A)
# Pour éviter de refaire trop de fois les mêmes calculs, on peut proposer la variante suivante :
# In[60]:
A = []
N = 10**4
for a in range(N):
Da = sum(diviseurs(a))
for b in range(a + 1, N): # pour éviter les doublons
if b == Da:
Db = sum(diviseurs(b))
if a == Db:
A.append((a, b))
print(A)
# **Remarque :**
# >On pourrait même faire encore moins de calculs en enregistrant chaque calcul de somme des diviseurs dans une variable : ce sera possible avec ce que l'on appelle un "dictionnaire", que nous étudierons dans le prochain TP.
#
# Exercice 8 : nombres premiers jumeaux
#
# In[61]:
def jumeaux(n):
"""
Teste si n et n+2 sont premiers
"""
C = Crible(n + 3)
if C[n] and C[n + 2]:
return True
else:
return False
# On peut simplifier la syntaxe pour le ```return``` :
# In[62]:
def jumeaux(n):
"""
Teste si n et n+2 sont premiers
"""
C = Crible(n + 3)
return C[n] and C[n + 2]
# In[63]:
jumeaux(3)
# In[64]:
jumeaux(7)
# In[65]:
N = 2**20
cpt = 0 # compteur
C = Crible(N + 1)
for n in range(N - 2):
if C[n] and C[n + 2]:
# print((n,n+2)) # ça prend trop de place à l'affichage
cpt = cpt + 1
print("Il y a {} couples de nombres premiers jumeaux inférieurs à 2**20.".format(cpt))
# **Remarque :**
# > on n'a pas utilisé la fonction ```jumeaux``` pour ne pas recalculer le crible à chaque fois...
#
# Exercice 9 : conjecture de Goldbach
#
# In[66]:
C = Crible(101) # c'est une variable globale
def sommepremier(n):
"""
Teste si n peut s'écrire comme somme de 2 nombres premiers
Affiche le premier couple possible le cas échéant
"""
assert (n % 2 == 0)
for k in range(2, n // 2 + 2):
if C[k] and C[n - k]:
print("{0} = {1} + {2}".format(n, k, n - k))
return True
return False
# In[67]:
for n in range(2, 101, 2):
sommepremier(n)
# In[68]:
def goldbach(n):
"""
Teste si n peut s'écrire comme somme de 2 nombres premiers
"""
assert (n % 2 == 0)
for k in range(2, n // 2 + 2):
if C[k] and C[n - k]:
return True
return False
# Ici encore, ```C``` est une variable globale. Si on ne souhaite pas utiliser de variable globale, on pourrait la passer en paramètre de la fonction ```goldbach```.
# In[69]:
N = 2**20
C = Crible(N + 2) # c'est une variable globale
k = 4
conjecture = goldbach(k)
while conjecture and k <= N:
k += 2
conjecture = goldbach(k)
print("La conjecture de Goldbach est-elle vérifiée jusqu'au rang N ?",conjecture)