$\require{color}$ $\require{xcolor}$ $\require{cancel}$ $\newcommand{\myfbox}[1]{\fcolorbox{red}{white}{$\textrm{#1}$}}$ $\require{stmaryrd}$ $\newcommand{\ient}{[\![}$ $\newcommand{\rrbracket}{]\!]}$ $\newcommand{\llbracket}{[\![}$ $\newcommand{\fient}{]\!]}$ $\newcommand{\R}{\mathbb R}$ $\newcommand{\K}{\mathbb K}$ $\newcommand{\N}{\mathbb N}$ $\newcommand{\C}{\mathbb C}$ $\newcommand{\P}{\mathbb P}$ $\newcommand{\E}{\mathbb E}$ $\newcommand{\V}{\mathbb V}$ $\newcommand{\Z}{\mathbb Z}$ $\newcommand{\dt}{\mathrm d}$ $\newcommand{\sh}{\operatorname{sh}}$ $\newcommand{\ch}{\operatorname{ch}}$ $\newcommand{\th}{\operatorname{th}}$ $\newcommand{\e}{\operatorname{e}}$ $\newcommand{\id}{\operatorname{Id}}$ $\newcommand{\mat}{\operatorname{mat}}$ $\newcommand{\sp}{\operatorname{Sp}}$ $\newcommand{\In}{\operatorname{I}}$ $\newcommand{\vect}{\operatorname{Vect}\ }$ $\newcommand{\rg}{\operatorname{rg}}$ $\newcommand{\tr}{\operatorname{Tr}}$ $\newcommand{\dis}{\displaystyle}$ $\renewcommand{\Im}{\operatorname{Im}}$ $\newcommand{\im}{\operatorname{Im}}$ $\newcommand{\bordermatrix}[3]{ \begin{matrix} \begin{matrix}#1\end{matrix} & \\ #3 & \hspace{-1em} \begin{matrix}#2\end{matrix} \end{matrix}}$ $\newcommand{\fonction}[5]{#1\ \colon \left\{\begin{array}{ccl}#2 & \longrightarrow & #3\\#4 & \longmapsto & #5\end{array}\right.}$ $\newcommand{\fonctionsansnom}[4]{\left\{\begin{array}{ccl}#1 & \longrightarrow & #2\\#3 & \longmapsto & #4\end{array}\right.}$ $\newcommand{\revdots}{\mathinner{\mkern1mu\raise1pt{\kern7pt\hbox{.}}\mkern2mu\raise4pt\hbox{.}\mkern2mu\raise7pt\hbox{.}\mkern1mu}}$ $\newcommand{\tendvers}[2]{\xrightarrow[#1\to#2]{}}$ $\newcommand{\q}[1]{\mathbf{Q#1}\ \triangleright}$ $\newcommand{\nicefrac}[2]{^{#1}/_{#2}}$
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = [15, 8] # pour des plots plus grands
import numpy as np
import sympy as sp
def est_premier(n: int) -> bool:
"""
Teste si n est premier (algorithme naif)
"""
if n <= 1:
return False
for k in range(2, int(n**0.5) + 1):
if n % k == 0:
return False
return True
est_premier(12)
False
est_premier(19)
True
[i for i in range(21) if est_premier(i)]
[2, 3, 5, 7, 11, 13, 17, 19]
Pour compter (naïvement) le nombre de nombres premiers inférieurs (ou égaux) à 1000, on peut procéder de la manière suivante :
cpt = 0
for i in range(2, 1001):
if est_premier(i):
cpt += 1
print(cpt)
168
def crible(N: int) -> [bool]:
"""
Implémente le crible D'Eratosthène
"""
# Initialisation
C = [False] * 2 + (N - 1) * [True]
# Parcours du crible
for n in range(2, int(N**0.5) + 1):
if C[n]:
for k in range(2 * n, N + 1, n):
C[k] = False
return C
crible(10)
[False, False, True, True, False, True, False, True, False, False, False]
On peut obtenir la liste des premiers nombres premiers de la manière suivante :
N = 21
C = crible(N)
print([i for i in range(N) if C[i]])
[2, 3, 5, 7, 11, 13, 17, 19]
X, Y = [], []
p = 0
N = 100
# tracé de la courbe représentative de pi
for n in range(N):
if est_premier(n):
p += 1
X.append(n)
Y.append(p)
plt.plot(X, Y, "b.", label=r"$x\mapsto \pi(x)$")
# tracé de la courbe représentative de x->x/ln(x)
X = np.linspace(2, N)
Y2 = X / np.log(X)
plt.plot(X, Y2, label=r"$x\mapsto \dfrac{x}{\ln(x)}$")
# tracé de la courbe représentative de x->int_{2}^{x} 1/ln(t)dt
t = sp.Symbol('t')
Li = lambda x: sp.integrate(1 / sp.log(t), (t, 2, x))
Y3 = [Li(x) for x in X]
plt.plot(X, Y3, label=r"$x\mapsto \int_{2}^{x}\dfrac{1}{\ln(t)}\mathrm{d}t$")
# option de tracé
plt.legend()
plt.grid()
plt.axis("equal")
plt.show()
Il semble donc que l'on ait l'encadrement suivant : $$ \fbox{$\forall x\geqslant 12,\ \frac{x}{\ln(x)} \leqslant \pi(x) \leqslant \int_{2}^{x}\dfrac{1}{\ln(t)}\mathrm{d}t$} $$
n = 100
N = n**2
X = []
Y = []
abscisse = 0
ordonnee = 0
nb = 1
cpt = 1
signex = 1
signey = 1
while nb < N:
for i in range(cpt):
abscisse = abscisse + signex
nb += 1
if est_premier(nb):
X.append(abscisse)
Y.append(ordonnee)
signex *= -1
for i in range(cpt):
ordonnee = ordonnee + signey
nb += 1
if est_premier(nb):
X.append(abscisse)
Y.append(ordonnee)
signey *= -1
cpt+=1
plt.scatter(X,Y,s=10)
#plt.axis("off")
plt.axis("equal")
plt.show()
def nb_diviseurs(n: int) -> int:
"""
Renvoie le nombre de diviseurs de l'entier n
"""
d = 2
for k in range(2, n):
if n % k == 0:
d += 1
return d
n = 100
N = n**2
X = []
Y = []
S = []
abscisse = 0
ordonnee = 0
nb = 1
cpt = 1
signex = 1
signey = 1
while nb < N:
for i in range(cpt):
abscisse = abscisse + signex
nb += 1
X.append(abscisse)
Y.append(ordonnee)
S.append(nb_diviseurs(nb) / 10)
signex *= -1
for i in range(cpt):
ordonnee = ordonnee + signey
nb += 1
X.append(abscisse)
Y.append(ordonnee)
S.append(nb_diviseurs(nb) / 10)
signey *= -1
cpt += 1
plt.scatter(X, Y, S)
plt.axis("off")
plt.axis("equal")
plt.show()
On code d'abord l'algorithme d'Euclide classique :
def euclide(a: int, b: int) -> int:
"""
Entrée : deux entiers naturels a et b tels que a >= b
Sortie : pgcd(a,b)
"""
assert(a >= b)
while b != 0:
a, b = b, a%b
return a
euclide(35, 25)
5
euclide(42, 13)
1
euclide(48, 0)
48
On adapte la fonction précédente pour implémenter l'algorithme d'Euclide étendu ; il faut rajouter la gestion des suites $(u_n)$ et $(v_n)$, qui sont des suites récurrentes doubles, et donc nécessitent d'utiliser 2 variables chacune pour stocker leurs termes consécutifs :
def euclidex(a: int, b: int) -> (int):
"""
Entrée : deux entiers naturels a et b tels que a >= b
Sortie : pgcd(a,b) et coefficients de Bezout associes
"""
assert (a >= b)
u, uu, v, vv = 1, 0, 0, 1
while b != 0:
q = a // b # on le stocke pour ne pas le calculer 2 fois
u, uu, v, vv = uu, u - q * uu, vv, v - q * vv
a, b = b, a % b
return a, u, v
euclidex(35, 25)
(5, -2, 3)
a, b = 42, 13
pgcd, u, v = euclidex(a, b)
print(a * u + b * v == pgcd)
True
À vous de voir si vous êtes motivés... ou pas !