#!/usr/bin/env python
# coding: utf-8
#
#
TP n°8 : Arithmétique - éléments de correction
# $\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}}$
# In[1]:
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = [15, 8] # pour des plots plus grands
import numpy as np
import sympy as sp
# # 1 - Nombres premiers
#
# Exercice 1 : Test naïf de primalité
#
# In[2]:
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
# In[3]:
est_premier(12)
# In[4]:
est_premier(19)
# In[5]:
[i for i in range(21) if est_premier(i)]
# > Pour compter (naïvement) le nombre de nombres premiers inférieurs (ou égaux) à 1000, on peut procéder de la manière suivante :
# In[6]:
cpt = 0
for i in range(2, 1001):
if est_premier(i):
cpt += 1
print(cpt)
#
# Exercice 2 : Crible d'Ératosthène
#
# In[7]:
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
# In[8]:
crible(10)
# > On peut obtenir la liste des premiers nombres premiers de la manière suivante :
# In[9]:
N = 21
C = crible(N)
print([i for i in range(N) if C[i]])
#
# Exercice 3 : Théorème des nombres premiers
#
# In[10]:
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$}
# $$
#
# Exercice 4 : Spirale d'Ulam
#
# In[11]:
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()
# In[12]:
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
# In[13]:
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()
# # 2 - Algorithmes d'Euclide
#
# Exercice 5 : Algorithme d'Euclide étendu
#
# > On code d'abord l'algorithme d'Euclide classique :
# In[14]:
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
# In[15]:
euclide(35, 25)
# In[16]:
euclide(42, 13)
# In[17]:
euclide(48, 0)
# > 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 :
# In[18]:
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
# In[19]:
euclidex(35, 25)
# In[20]:
a, b = 42, 13
pgcd, u, v = euclidex(a, b)
print(a * u + b * v == pgcd)
# # 3 - Chiffrement RSA
#
# Exercice 6 : RSA
#
# À vous de voir si vous êtes motivés... ou pas !