Exercices

Compréhension de liste

  1. Construisez une liste dont les éléments sont les 13 premiers entiers qui ne sont multiples ni de 3 ni de 5. Commencez par faire cet exercice avec des boucles, des tests… vous allez arriver a quelque chose qui va marcher (normalement) mais qui va être lourd à lire et éventuellement à comprendre.
[1]:
k = 1
res = []
while len(res) < 13:
    if k % 3 != 0 and k % 5 != 0:
        res.append(k)
    k += 1
print(res)
[1, 2, 4, 7, 8, 11, 13, 14, 16, 17, 19, 22, 23]
  1. Même exercice avec « simplement » une compréhension de liste.
[2]:
[k for k in range(40) if k % 3 != 0 and k % 5 != 0][:13]
[2]:
[1, 2, 4, 7, 8, 11, 13, 14, 16, 17, 19, 22, 23]
  1. Soit la liste suivante :
[3]:
foo = [2, 5, 12, 31, 2, 17, 31, 42, 2]

Pour chaque compréhension ci-dessous, écrire le résultat sur une feuille, puis vérifiez votre résultat à la console :

[4]:
[n % 5 for n in foo]
[4]:
[2, 0, 2, 1, 2, 2, 1, 2, 2]
[5]:
[n + 2 for n in foo[:-2]]
[5]:
[4, 7, 14, 33, 4, 19, 33]
[6]:
[n <= 12 for n in foo if n >= 12]
[6]:
[True, False, False, False, False]
[7]:
[bin(n) for n in foo if n > 15]
[7]:
['0b11111', '0b10001', '0b11111', '0b101010']
  1. Écrire la liste des lettres qui sont dans la chaîne ampfusntqnsuet
[8]:
[c for c in 'ampfusntqnsuet']

# Ou bien :
list(map(lambda x: x, 'ampfusntqnsuet'))
[8]:
['a', 'm', 'p', 'f', 'u', 's', 'n', 't', 'q', 'n', 's', 'u', 'e', 't']
  1. Soit la liste :
[9]:
foo = [2, 4, 3, 9, 6, 9, 2, 6, 1, 0, 1, 0, 0, 6, 4, 5, 5, 0]

Écrire une liste qui contient les éléments pair ou impair pour chaque élément de foo, suivant que l’élément est pair ou impair.

[10]:
['pair' if i % 2 == 0 else 'impair' for i in foo]
[10]:
['pair',
 'pair',
 'impair',
 'impair',
 'pair',
 'impair',
 'pair',
 'pair',
 'impair',
 'pair',
 'impair',
 'pair',
 'pair',
 'pair',
 'pair',
 'impair',
 'impair',
 'pair']
  1. Écrire par ordre croissant la liste des chiffres impairs dans foo. Note : on pourra utiliser la fonction sorted().
[11]:
[k for k in sorted(foo) if k%2 == 1]

# Ou
sorted([k for k in foo if k%2 == 1])
[11]:
[1, 1, 3, 5, 5, 9, 9]
  1. Écrire la liste associée à foo indiquant si les éléments sont pairs ou non (avec le booléen True ou False).
[12]:
[i % 2 == 0 for i in foo]

# Ou avec une fonction lambda
[(lambda x: x % 2 == 0)(i) for i in foo]
[12]:
[True,
 True,
 False,
 False,
 True,
 False,
 True,
 True,
 False,
 True,
 False,
 True,
 True,
 True,
 True,
 False,
 False,
 True]
  1. Soit la liste :
[13]:
bar = [2.3, 3.2, 5.9, -0.4, 6.2, -4.9, 0.1, -2.7, 4.8, -2.0]

Écrire la liste associée à bar de la partie entière des nombres positifs. Note : on pourra utiliser la fonction int().

[14]:
[int(x) for x in bar if x > 0]
[14]:
[2, 3, 5, 6, 0, 4]
  1. Soit la liste :
[15]:
baz = ['z', 'a', 'f', 'u', 'a', 'i', 'k', 'o', 'b', 'f', 'y']

Écrire la liste des lettres dans baz en majuscule. Note : On pourra utiliser la méthode .upper().

[16]:
[c.upper() for c in baz]
[16]:
['Z', 'A', 'F', 'U', 'A', 'I', 'K', 'O', 'B', 'F', 'Y']

Suite de Fibonacci

Leonardo Fibonacci (circa 1175 – 1250), mathématicien italien, proposa comme un exercice mathématique amusant le modèle suivant pour décrire la croissance naturelle d’une population de lapins. On suppose qu’on dispose d’un couple de lapins tout juste nés, maintenus isolés de leurs congénères. On suppose de plus que chaque mois, chaque couple âgé d’au moins deux mois engendre un nouveau couple de lapins. On ne tient pas compte de la mortalité naturelle des lapins. Le nombre \(C_n\) de couples de lapins suit par conséquent une relation de récurrence,

\[C_0 = C_1 = 1 \ \ \ , \ \ \ C_n = C_{n-1}+C_{n-2}\]

La suite d’entiers \(C_n\) est connue comme la suite de Fibonacci. On commence par inclure les paquets numpy et matplotlib

[17]:
import numpy as np
import matplotlib.pyplot as plt
  1. Créez un tableau ns de 50 entiers de 0 à 49 inclus.
[18]:
N = 50
ns = np.arange(50)
  1. En utilisant une boucle for, la valeur des deux premiers termes \(C_0\) et \(C_1\), et la relation de récurrence, calculez les 50 premières valeurs de cette suite, et stockez-les dans un tableau numpy C.
[19]:
C = np.empty(N, dtype = 'int64')
C[0] = 1
C[1] = 1
for i in range(2, N):
    C[i] = C[i - 1] + C[i - 2]
  1. Représentez l’évolution du nombre de couples de lapins en fonction du temps (exprimé en mois), pendant 50 mois. Pensez à ajouter un titre, à indiquez les axes et les unités.
[20]:
plt.plot(ns, C, 'b+-')
plt.title("Évolution du nombre de couples de lapins")
plt.xlabel("Temps [mois]")
plt.ylabel("Couples de lapins")
plt.show()
../../_images/notebooks_04-suites-relations-recurrence_02-exercices_38_0.png
  1. Ajoutez dans votre programme le calcul de la suite des rapports \(r_n\) entre deux termes successifs de la suite de Fibonacci (pour \(n\) allant de 1 à 49 inclus) :

    \[r_n = \frac{C_n}{C_{n-1}}\]
[21]:
# Avec boucle :
r = np.empty((N - 1,))
for i in range(N - 1):
    r[i] = C[i + 1] / C[i]

# Ou sans boucle :
r = np.array(C[1:], dtype = 'float') / C[:-1] # Si on veut être sûr des conversions de type
# Ou plus simplement :
r = C[1:] / C[:-1]
  1. Tracez le graphe de ce rapport \(r_n\) en fonction du mois \(n\), pour \(n\) allant de 1 à 49 inclus.
[22]:
plt.plot(ns[1:], r, 'b+-')
plt.title("Suite de Fibonacci : rapport entre termes successifs")
plt.xlabel("Temps $n$ [mois]")
plt.ylabel("$r_n = C_n/C_{n-1}$")
plt.show()
../../_images/notebooks_04-suites-relations-recurrence_02-exercices_42_0.png

On peut montrer que le rapport \(r_n\) a pour limite le nombre d’or \(\phi = \frac{1}{2} \left(1+\sqrt{5}\right)\). Pour des \(n\) suffisamment grands, la suite \(C_n\) tend donc vers une suite géométrique de la forme \(A \phi^n\).

  1. Tracez les 50 premiers termes de la suite de Fibonacci sur un graphe semi-logarithmique (échelle log selon les ordonnées). La suite de Fibonacci tend-elle bien vers une suite géométrique ?
[23]:
plt.semilogy(ns, C, 'b+-')
plt.title("Suite de Fibonacci")
plt.xlabel("Temps [mois]")
plt.ylabel("Couples de lapins")
plt.show()
../../_images/notebooks_04-suites-relations-recurrence_02-exercices_44_0.png

Comme la suite \(C_n\) tend vers une suite géométrique, on a de manière immédiate :

\[\lim\limits_{n \rightarrow \infty} D_n = \lim\limits_{n \rightarrow \infty} \log(C_n) = \log A + n \log \phi\]
  1. Calculez la suite \(D_n\) et stockez-la dans un tableau numpy.
[24]:
D = np.log(C)

Récursion

  1. Écrire une fonction factorielle en utilisant la récursion, et proposer un test avec assert
[25]:
# Définition de la fonction factorielle
def factorielle(x):
    ''' Retourne la factorielle du nombre x '''
    if x == 1:
        return 1
    else:
        return x * factorielle(x - 1)

# Test de la fonction
assert factorielle(6) == 720
  1. Écrire une fonction récursive de signature pascal(n) qui prend comme argument un entier \(n\), et qui retourne la liste contenant les coefficients de la ligne \(n\) du triangle de Pascal. Utiliserer pour cela une boucle for. Proposer un test de la fontion avec assert.
[26]:
# Définition de la fonction pascal
def pascal(n):
    ''' Retourne la ligne n du triangle de Pascal '''
    if n == 1:
        return [1]
    else:
        previous_line = pascal(n - 1)
        line = [1]
        for i in range(len(previous_line) - 1):
            line += [previous_line[i] + previous_line[i + 1]]
        line += [1]
        return line

# Test de la fonction
assert pascal(6) == [1, 5, 10, 10, 5, 1]
  1. Même question avec une compréhension de liste au lieu de la boucle for.
[27]:
# Définition de la fonction pascal
def pascal(n):
    ''' Retourne la ligne n du triangle de Pascal '''
    if n == 1:
        return [1]
    else:
        p_line = pascal(n - 1)
        return [1] + [p_line[i] + p_line[i + 1] for i in range(len(p_line) - 1)] + [1]

# Test de la fonction
assert pascal(6) == [1, 5, 10, 10, 5, 1]
[28]:
for i in range(10):
    print(pascal(i))
---------------------------------------------------------------------------
RecursionError                            Traceback (most recent call last)
/tmp/ipykernel_1260/275530431.py in <module>
      1 for i in range(10):
----> 2     print(pascal(i))

/tmp/ipykernel_1260/2405232983.py in pascal(n)
      5         return [1]
      6     else:
----> 7         p_line = pascal(n - 1)
      8         return [1] + [p_line[i] + p_line[i + 1] for i in range(len(p_line) - 1)] + [1]
      9

... last 1 frames repeated, from the frame below ...

/tmp/ipykernel_1260/2405232983.py in pascal(n)
      5         return [1]
      6     else:
----> 7         p_line = pascal(n - 1)
      8         return [1] + [p_line[i] + p_line[i + 1] for i in range(len(p_line) - 1)] + [1]
      9

RecursionError: maximum recursion depth exceeded in comparison
[29]:
# Complément : usage des tableaux NumPy

# Définition de la fonction pascal
def pascal(n):
    ''' Retourne la ligne n du triangle de Pascal '''
    if n == 1:
        return np.array([1])
    else:
        precedent = pascal(n - 1)
        return np.concatenate(([1], precedent[:-1] + precedent[1:], [1]))

# Test de la fonction
assert (pascal(6) == np.array([1, 5, 10, 10, 5, 1])).all()