Les nouvelles technologies pour l’enseignement des mathématiques
Intégration des TICE dans l’enseignement des mathématiques

MathémaTICE, première revue en ligne destinée à promouvoir les TICE à travers l’enseignement des mathématiques.

Les algorithmes du programme 2019 de mathématiques de Seconde
Article mis en ligne le 7 avril 2019
dernière modification le 12 juin 2023

par Benjamin Clerc

Cet article peut être librement diffusé et son contenu réutilisé pour une utilisation non commerciale (contacter l’auteur pour une utilisation commerciale) suivant la licence CC-by-nc-sa

Dans le programme de mathématiques de seconde on trouve parmi la liste des compétences mathématiques travaillées :

  • Calculer, appliquer des techniques et mettre en œuvre des algorithmes ;
    Il y a dans ce programme des indications au sujet de ces algorithmes que l’on peut mettre en œuvre, nous allons ici les illustrer.

Nous faisons le choix de vous proposer une approche 100% fonctionnelle, comme préconisé dans les programmes.
Il peut être utile de connaître et d’utiliser Sofuspy qui propose une programmation par blocs et un traducteur vers Python, ce qui permet de faciliter l’apprentissage de Python pour des élèves formés à la programmation par blocs au collège.

Nombres et calculs

Déterminer par balayage un encadrement de √2 d’amplitude inférieure ou égale à 10−n.

Cette méthode, classique, consiste, à partir d’un intervalle [a ; b] dans lequel on sait trouver $\sqrt{2}$, à calculer x², pour x allant de a à b avec un pas de h, « Tant Que » x² < 2 est vérifiée (On utilisera pour cela un While.). La fonction carré étant croissante, dès que x² > 2 on arrête l’algorithme et on obtient un encadrement de longueur h de $\sqrt{2}$ : $x – h ≤ \sqrt{2} < x$.
Il faut déterminer a et b, les bornes de l’intervalle dans lequel on va appliquer le balayage. On prendra a = 1 et b = 2 en effet 1<2<4 donc $1 < \sqrt{2} < 2$.

Fonction qui calcule cet encadrement, renvoyé dans un tuple, en fonction du nombre n de décimales souhaitées :
Cet algorithme détermine par balayage un encadrement de racine de 2 d’amplitude 10^(-n).

  1. def balayage(n):
  2.     h=10**(-n)
  3.     x=1 #1 est la valeur de a. b ne sert à rien ici, inutile de l'introduire.
  4.     while x**2<2:
  5.         x=x+h
  6.     return (round(x-h,n),round(x,n))

Télécharger

Utilisation : Compiler le fichier puis dans la console taper balayage(9) puis « Entrer » :

  1. >>> balayage(9)
  2. (1.414213562, 1.414213563)

Télécharger

Le round permet ici de corriger quelques erreurs d’affichage des flottants [1].
Il est à noter que cet algorithme est très long à donner une réponse si n>=9.
On peut donc chercher à l’optimiser, par exemple en utilisant une boucle for qui va faire la même chose que le programme précédent mais pour h allant de 10-1 à 10-n en réduisant l’intervalle [a ; b] à chaque boucle.
C’est beaucoup plus rapide, jusqu’à n=16 où ça bogue, parce que les flottants (décimaux) ne sont affichés qu’avec 16 chiffres après la virgule.

  1. def balayage(n):
  2.     a=1 #1 est la valeur de a lors de la première boucle. b ne sert à rien ici, inutile de l'introduire.
  3.     for i in range(1,n+1):
  4.         h=10**(-i)
  5.         x=a
  6.         while x**2<2:
  7.             x=x+h
  8.         a=x-h
  9.     return (round(x-h,n),round(x,n))

Télécharger

Les deux programmes précédents dans Sofuspy :
A l’ouverture de la page, vous pouvez exécuter le programme en blocs en cliquant sur « Exécuter » au-dessus des blocs, entrez une valeur de n<=6 parce qu’ils ne fonctionnent pas au-delà de n=6 car le nombre d’itérations est limité à 1000000. Cette limitation peut être levée en demandant à SofusPy la traduction automatique en Python (en cliquant sur "Traduire"), puis en exécutant le programme ainsi obtenu avec l’interpréteur Python de SofusPy (En cliquant sur "Exécuter" au-dessus du code Python).
balayage1
balayage2

Déterminer si un entier naturel a est multiple d’un entier naturel b.

On ne va bien sûr pas utiliser les opérations de base Python :
  % reste de division entière (17 % 3 donne 2)
 // quotient de division entière (17 // 3 donne 5)
il n’y aurait alors aucun intérêt à parler de cet algorithme.
On va bien sûr utiliser le théorème de la division euclidienne :
Il existe un unique couple $(q, r)\in \mathbb{N}\times\mathbb{N}$ tel que : $a = bq + r, 0 \leq r < b $.
On peut donc programmer le calcul de tous les multiples de $b$ inférieurs à $a$ et voir si l’on atteint $a$.
Nous faisons le choix de renvoyer en résultat un booléen pour indiquer si la réponse à la question que l’on pose à la fonction est vraie ou fausse.
Cet algorithme détermine si un entier naturel $a$ est multiple d’un entier naturel $b$.
$n$ sert à compter le nombre de $b$ dans $m$.

  1. def a_multiple_de_b(a,b):
  2.     n=0
  3.     m=0
  4.     while m<=a:
  5.         m+=b
  6.         n+=1
  7.     if a==(n-1)*b:
  8.         return True
  9.     else:
  10.         return False

Télécharger

Utilisation : Compiler le programme et taper dans la console

  1. >>> a_multiple_de_b(569,19)
  2. False
  3. >>> a_multiple_de_b(570,19)
  4. True

Télécharger

Pour des entiers a et b donnés, déterminer le plus grand multiple de b inférieur ou égal à a.

On n’utilisera pas non plus ici les opérations de base Python % et //.
On peut donc programmer le calcul de tous les multiples de $b$ inférieurs à $a$ comme dans l’algorithme précédent, avec des modifications mineures.

Avec Python :
La fonction combien_b_dans_a détermine le plus grand multiple de $b$ inférieur ou égal à $a$.
$n$ sert à compter le nombre de $b$ dans $m$.

  1. def combien_b_dans_a(a,b):
  2.     n=0
  3.     m=0
  4.     while m<=a:
  5.         m+=b
  6.         n+=1
  7.     return n-1

Télécharger

Utilisation : Compiler le programme et taper dans la console

  1. >>> combien_b_dans_a(58,7)
  2. 8
  3. >>> combien_b_dans_a(57,7)
  4. 8
  5. >>> combien_b_dans_a(56,7)
  6. 8
  7. >>> combien_b_dans_a(55,7)
  8. 7

Télécharger

La fonction communique_combien_b_dans_a annonce le résultat, elle peut être occultée. Si elle est utilisée, elle nécessite la fonction combien_b_dans_a qu’elle appelle dans son code.

  1. def communique_combien_b_dans_a(a,b):
  2.     n=combien_b_dans_a(a,b)
  3.     if n*b==a:
  4.         message=str(a)+" est un multiple de "+str(b)+", c'est "+str(n)+"*"+str(b)+"."
  5.     else:
  6.         message=str(n)+"*"+str(b)+" = "+str(n*b)+" est le plus grand multiple de "+str(b)+" inférieur à "+str(a)
  7.     return message

Télécharger

Utilisation : Compiler le programme et taper dans la console

  1. >>> communique_combien_b_dans_a(58,7)
  2. '8*7 = 56 est le plus grand multiple de 7 inférieur à 58'
  3. >>> communique_combien_b_dans_a(57,7)
  4. '8*7 = 56 est le plus grand multiple de 7 inférieur à 57'
  5. >>> communique_combien_b_dans_a(56,7)
  6. "56 est un multiple de 7, c'est 8*7."
  7. >>> communique_combien_b_dans_a(55,7)
  8. '7*7 = 49 est le plus grand multiple de 7 inférieur à 55'

Télécharger

Déterminer si un entier naturel est premier.

On va ici s’autoriser à utiliser l’opération n%i qui donne le reste de la division euclidienne de $n$ par $i$. On utilisera aussi une liste « diviseurs » qui contiendra tous les diviseurs de $n$ (la méthode append permet d’ajouter un élément à une liste, len(liste) renvoie la longueur de liste).

  1. >>> diviseurs
  2. []
  3. >>> len(diviseurs)
  4. 0
  5. >>> diviseurs.append(1)
  6. >>> diviseurs
  7. [1]
  8. >>> len(diviseurs)
  9. 1
  10. >>> diviseurs.append(5)
  11. >>> diviseurs
  12. [1, 5]
  13. >>> len(diviseurs)
  14. 2

Télécharger

Si la liste des diviseurs est de longueur 2 c’est qu’elle contient 1 et $n$, donc que $n$ est premier.

  1. def estPremier(n):
  2.     diviseurs=[]
  3.     for i in range(1,n+1):
  4.         if n%i==0:
  5.             diviseurs.append(i)
  6.     if len(diviseurs)==2:
  7.         return True
  8.     else:
  9.         return False

Télécharger

Utilisation : Compiler le programme et taper dans la console

  1. >>> estPremier(47123)
  2. True
  3. >>> estPremier(471234567)
  4. False

Télécharger

On pourra diviser le temps de calcul par 2 avec le code suivant :

  1. def estPremier(n):
  2.     diviseurs=[]
  3.     borne_sup=round(n/2)
  4.     for i in range(1,borne_sup+1):
  5.         if n%i==0:
  6.             diviseurs.append(i)
  7.     diviseurs.append(n)
  8.     if len(diviseurs)==2:
  9.         return True
  10.     else:
  11.         return False

Télécharger

En effet, le plus grand diviseur de $n$, autre que $n$, ne peut pas être plus grand que $\frac n 2$.

Déterminer la première puissance d’un nombre positif donné supérieure ou inférieure à une valeur donnée.

L’énoncé ressemble beaucoup à « Pour des entiers a et b donnés, déterminer le plus grand multiple de $b$ inférieur ou égal à $a$. », on reprend donc ce script en l’adaptant au nouveau problème :

Le code Python pour $b^n \leq a$ :

  1. def puissance(a,b):
  2.     m=b
  3.     n=1
  4.     while m<=a:
  5.         if m==a:
  6.             m*=b #Sert à arrêter le programme.
  7.             return n
  8.         else:
  9.             m*=b
  10.             n+=1 #Sert à compter l'exposant de b contenu dans a.
  11.     if m!=a and m!=a*b:
  12.         return n-1
  13.     #Le résultat est n-1 puisque avec b^n on dépassait a
  14.     return message

Télécharger

Utilisation :

  1. >>> puissance(1000,3)
  2. 6
  3. >>> puissance(243,3)
  4. 5

Télécharger

La fonction communique_puissance annonce le résultat, elle peut être occultée. Si elle est utilisée, elle nécessite la fonction puissance qu’elle appelle dans son code.

  1. def communique_puissance(a,b):
  2.     n=puissance(a,b)
  3.     if b**n==a:
  4.         message=str(a)+" est une puissance de "+str(b)+", c'est "+str(b)+"^"+str(n)+"."
  5.     else:
  6.         message=str(b)+"^"+str(n)+" = "+str(b**n)+" est la plus grande puissance de "+str(b)+" inférieure à "+str(a)
  7.     return message

Télécharger

Utilisation : Compiler le programme et taper dans la console

  1. >>> communique_puissance(1000,3)
  2. '3^6 = 729 est la plus grande puissance de 3 inférieure à 1000'
  3. >>> communique_puissance(243,3)
  4. "243 est une puissance de 3, c'est 3^5."

Télécharger

Et avec une toute petite modification, le code Python pour $b^n \geq a$ :

  1. def puissance(a,b):
  2.     m=b
  3.     n=1
  4.     while m<=a:
  5.         if m==a:
  6.             m*=b #Sert à arrêter le programme.
  7.             return n
  8.         else:
  9.             m*=b
  10.             n+=1 #Sert à compter l'exposant de b contenu dans a.
  11.     if m!=a and m!=a*b:
  12.         return n
  13.     #Le résultat est n puisque avec b^n on dépassait a
  14.     return message
  15. def communique_puissance(a,b):
  16.     n=puissance(a,b)
  17.     if b**n==a:
  18.         message=str(a)+" est une puissance de "+str(b)+", c'est "+str(b)+"^"+str(n)+"."
  19.     else:
  20.         message=str(b)+"^"+str(n)+" = "+str(b**n)+" est la plus petite puissance de "+str(b)+" supérieure à "+str(a)
  21.     return message

Télécharger

Utilisation :

  1. >>> puissance(1000,3)
  2. 7
  3. >>> puissance(243,3)
  4. 5
  5. >>> communique_puissance(1000,3)
  6. '3^7 = 2187 est la plus petite puissance de 3 supérieure à 1000'
  7. >>> communique_puissance(243,3)
  8. "243 est une puissance de 3, c'est 3^5."

Télécharger

Géométrie

Étudier l’alignement de trois points dans le plan.

On va utiliser le fait que trois points sont alignés si ils ont la même abscisse, ou si ils ont la même ordonnée, ou si les coefficients directeurs de deux des droites qu’ils forment sont égaux. Comme le calcul des coefficients directeurs fait appel à un quotient, il faudra prendre la précaution d’éviter la division par 0.

Pour cet algorithme, nous avons fait le choix d’une fonction qui a en paramètres les noms des points suivis de leurs coordonnées, et qui retourne une phrase qui donne l’équation de la droite lorsque les points sont alignés, d’autres choix peuvent être faits. Cette phrase est une concaténation de chaînes de caractères, ceci se fait tout simplement avec le signe « + », les nombres sont transformés en chaînes de caractères à l’aide de la fonction str().
Ce programme détermine si trois points dont vous allez donner le nom et les coordonnées, sont alignés :
 Ne pas tester en même temps x_A==x_B et x_A==x_C permet d’éviter la division par 0 dans le calcul de m1, le coefficient directeur de (AB)
 m2 est le coefficient directeur de (AC)
 p est l’ordonnée à l’origine de (AB)

  1. def pts_alignes(A,B,C):
  2.     pt_1,x_A,y_A=A
  3.     pt_2,x_B,y_B=B
  4.     pt_3,x_C,y_C=C
  5.     if x_A==x_B:
  6.         if x_A==x_C:
  7.             message=pt_1+", "+pt_2+" et "+pt_3+" sont alignés et appartiennent à la droite verticale d'équation x = "+str(x_A)+"."
  8.         else:
  9.             message=pt_1+", "+pt_2+" et "+pt_3+" ne sont pas alignés."
  10.     elif y_A==y_B and y_A==y_C:
  11.         message=pt_1+", "+pt_2+" et "+pt_3+" sont alignés et appartiennent à la droite horizontale d'équation y = "+str(y_A)+"."
  12.     else:
  13.         if x_A==x_C:
  14.             #permet d'éviter la division par 0 dans le calcul de m2
  15.             message=pt_1+", "+pt_2+" et "+pt_3+" ne sont pas alignés."
  16.         else:
  17.             m1=(y_B-y_A)/(x_B-x_A)  
  18.             m2=(y_C-y_A)/(x_C-x_A)
  19.             if m1==m2:
  20.                 p=y_A-m1*x_A
  21.                 message=pt_1+", "+pt_2+" et "+pt_3+" sont alignés et appartiennent à la droite oblique d'équation y = "+str(m1)+"x +"+str(p)+"."
  22.             else:
  23.                 message=pt_1+", "+pt_2+" et "+pt_3+" ne sont pas alignés."
  24.     return message

Télécharger

Utilisation :

  1. >>> pts_alignes(("D",2,-5),("E",3,-5),("F",4,-5))
  2. "D, E et F sont alignés et appartiennent à la droite horizontale d'équation y = -5."
  3. >>> pts_alignes(("D",2,-5),("E",2,-6),("F",4,-7))
  4. 'D, E et F ne sont pas alignés.'
  5. >>> pts_alignes(("D",2,-5),("E",2,-6),("F",2,-7))
  6. "D, E et F sont alignés et appartiennent à la droite verticale d'équation x = 2."
  7. >>> pts_alignes(("D",2,-5),("E",3,-6),("F",4,-7))
  8. "D, E et F sont alignés et appartiennent à la droite oblique d'équation y = -1.0x +-3.0."
  9. >>> pts_alignes(("D",2,-5),("E",3,-6),("F",3,-7))
  10. 'D, E et F ne sont pas alignés.'

Télécharger

Si l’on veut juste savoir si les points sont alignés ou pas :

  1. def pts_alignes(A,B,C):
  2.     pt_1,x_A,y_A=A
  3.     pt_2,x_B,y_B=B
  4.     pt_3,x_C,y_C=C
  5.     if x_A==x_B:
  6.         #Ne pas tester en même temps x_A==x_B et x_A==x_C permet d'éviter la division par 0 dans le calcul de m1
  7.         if x_A==x_C:
  8.             return True
  9.         else:
  10.             return False
  11.     elif y_A==y_B and y_A==y_C:
  12.         return True
  13.     else:
  14.         if x_A==x_C:
  15.             #permet d'éviter la division par 0 dans le calcul de m2
  16.             return False
  17.         else:
  18.             m1=round((y_B-y_A)/(x_B-x_A),10)
  19.             m2=round((y_C-y_A)/(x_C-x_A),10)
  20.             if m1==m2:
  21.                 return True
  22.             else:
  23.                 return False
  24.     return message

Télécharger

Utilisation :

  1. >>> pts_alignes(("D",2,-5),("E",2,6),("F",1,-5))
  2. False
  3. >>> pts_alignes(("D",2,-5),("E",3,-6),("F",4,-7))
  4. True

Télécharger

A noter que l’on utilise round pour éviter que le test ne fonctionne pas à cause des flottants alors que m1==m2, voir ci-dessous :

  1. >>> pts_alignes(("D",0.2,-3.2),("E",0.3,-3.3),("F",0.4,-3.4))
  2. m1 = -0.9999999999999967
  3. m2 = -0.9999999999999987
  4. False

Télécharger

Déterminer une équation de droite passant par deux points donnés.

Pour cet algorithme, nous avons fait le choix, dans un premier temps, d’une fonction qui a en paramètres les coordonnées des deux points, et qui retourne une phrase qui donne l’équation réduite de la droite, d’autres choix peuvent être faits. Cette phrase est une concaténation de chaînes de caractères, ceci se fait tout simplement avec le signe « + », les nombres sont transformés en chaînes de caractères à l’aide de la fonction str().
Calcul de l’équation réduite d’une droite à partir des coordonnées de deux de ses points donnés sous la forme de couples (tuples).

  1. def EQ_DROITE(A,B):
  2.     x_A,y_A=A
  3.     x_B,y_B=B
  4.     if x_A==x_B:
  5.         if y_A==y_B:
  6.             droite="Il n'est pas possible de donner UNE équation de droite avec deux points identiques !"
  7.         else:
  8.             droite="Droite verticale d'équation x = "+str(x_A)+"."
  9.     elif y_A==y_B:
  10.         droite="Droite horizontale d'équation y = "+str(y_A)+"."
  11.     else:
  12.         m=(y_B-y_A)/(x_B-x_A)
  13.         p=y_A-m*x_A
  14.         droite="Droite oblique d'équation y = "+str(m)+"x + "+str(p)+"."
  15.     return droite

Télécharger

Utilisation :

  1. >>> EQ_DROITE((2,3),(2,33))
  2. "Droite verticale d'équation x = 2."
  3. >>> EQ_DROITE((2,3),(2,3))
  4. 'Il n'est pas possible de donner UNE équation de droite avec deux points identiques !'
  5. >>> EQ_DROITE((2,3),(-1,3))
  6. "Droite horizontale d'équation y = 3."
  7. >>> EQ_DROITE((2,3),(-1,-9))
  8. "Droite oblique d'équation y = 4.0x + -5.0."

Télécharger

Puisqu’il y a dans les nouveaux programmes de seconde :
 Équation de droite : équation cartésienne, équation réduite.
On peut proposer que la fonction renvoie une équation cartésienne de la droite (ou plus exactement ses coefficients) dans un tuple.
On pourra demander à l’élève de démontrer que si $M(x ; y) \in (AB)$, la colinéarité des vecteurs $\overrightarrow{AB}$ et $\overrightarrow{AM}$ mène à l’équation $(y_A-y_B)x + (x_B-x_A)y+x_A(y_B-y_A)+y_A(x_A-x_B)=0$ :
Calcul d’une équation cartésienne d’une droite à partir des coordonnées de deux de ses points donnés sous forme de couples (tuples).
Pour une équation cartésienne ax + by + c = 0, le programme renvoie (a,b,c).

  1. def EQ_CARTESIENNE(A,B):
  2.     x_A,y_A=A
  3.     x_B,y_B=B
  4.     if A==B:
  5.         return None
  6.     else:
  7.         return y_A-y_B,x_B-x_A,x_A*(y_B-y_A)+y_A*(x_A-x_B)

Télécharger

Utilisation :

  1. >>> EQ_CARTESIENNE((1,3),(1,3))
  2. #pas d'équation cartésienne.
  3. >>> EQ_CARTESIENNE((-5,3),(1,3))
  4. (0, 6, -18) #Équation 6y - 18 = 0
  5. >>> EQ_CARTESIENNE((-5,3),(-5,-3))
  6. (6, 0, 30)    #Équation 6x + 30 = 0
  7. >>> EQ_CARTESIENNE((-5,3),(-2,-3))
  8. (6, 3, 21)    #Équation 6 x + 3y + 21 = 0

Télécharger

Fonctions

Pour une fonction dont le tableau de variations est donné, algorithmes d’approximation numérique d’un extremum (balayage, dichotomie).

Nous commencerons par une fonction dont on sait qu’elle est croissante puis décroissante sur un intervalle [a ; b], donc qu’elle admet un maximum sur cet intervalle.
Nous procéderons d’abord par balayage :

  1. def f(x):
  2.     return -3*x**3+4*x+1 #Entrez ici l'expression de la fonction
  3. def balayage(f,a,b,n):
  4.     #n est le nombre de chiffres après la virgule souhaités
  5.     e=10**(-n)
  6.     #e est la précision souhaitée
  7.     #a est la Borne inférieure de l'intervalle dans lequel le maximum a été repéré
  8.     #b est la Borne supérieure de l'intervalle dans lequel le maximum a été repéré
  9.     maxi=f(a)
  10.     while b-a>e:
  11.         amplitude=b-a
  12.         for i in range(11): #On découpe arbitrairement [a ; b] en 10
  13.             x=a+amplitude/10*i #calcul des abscisses obtenues en divisant [a ; b] en 10
  14.             if f(x)>maxi:
  15.                 maxi=f(x)
  16.                 x_max=x
  17.         a=x_max-amplitude/10 #On réduit l'intervalle dans lequel on va appliquer
  18.         b=x_max+amplitude/10 #à nouveau le balayage jusqu'à la précision demandée
  19.     return [round(a,n),round(b,n)]

Télécharger

Utilisation :

  1. >>> balayage(f,0,2,3)
  2. [0.666, 0.667]
  3. >>> balayage(f,0,2,7)
  4. [0.6666666, 0.6666667]
  5. >>> balayage(f,0,2,10)
  6. [0.6666666598, 0.6666666599]

Télécharger

A noter que Python montre ses limites à partir de n=8, la réponse [0.6666666598, 0.6666666599] est fausse puisque 2/3 n’appartient pas à cet intervalle ...

Par dichotomie, il y a un problème du fait que l’on ne sait pas dans quel intervalle se trouve le maximum : les données de f(a), f(m) et f(b) ne permettent pas de déterminer si le minimum est dans [a ; m] ou dans [m ; b]. Les deux cas sont possibles.

Plutôt que de couper l’intervalle en deux, nous allons le couper en trois, en posant $m = \frac{b -a}{3}$, $c = a + m$ et $d = b - m$.
On a alors a < c < d < b et l’on peut procéder par disjonction des cas, en notant $x_0$ l’abscisse du sommet :
 Si $a < x_0 <= c$, alors $f(c) > f(d)$.
 Si $c <= x_0 <= d$, alors $f(c) >= f(d)$ ou $f(c) <= f(d)$.
 Si $d <= x_0 <= b$, alors $f(c) < f(d)$.
L’on peut résumer cela en :
 Si $f(c) <= f(d)$ alors $x_0 \in [c ; b]$
 Si $f(c) >= f(d)$ alors $x_0 \in [a ; d]$
D’où l’algorithme suivant :

  1. def f(x):
  2.     return -3*x**3+4*x+1 #Entrez ici l'expression de la fonction
  3. def trichotomie(f,a,b,n):
  4.     #n est le nombre de chiffres après la virgule souhaités
  5.     e=10**(-n)
  6.     #e est la précision souhaitée
  7.     #a est la Borne inférieure de l'intervalle dans lequel le maximum a été repéré
  8.     #b est la Borne supérieure de l'intervalle dans lequel le maximum a été repéré
  9.     while b-a>e:
  10.         m=(b-a)/3
  11.         c=a+m
  12.         d=b-m
  13.         if f(c)<=f(d):
  14.             a=c
  15.         else:
  16.             b=d
  17.     return (round(a,n),round(b,n))

Télécharger

Utilisation :

  1. >>> trichotomie(f,0,2,7)
  2. (0.6666666, 0.6666667)
  3. >>> trichotomie(f,0,2,8)
  4. (0.66666667, 0.66666667)
  5. >>> trichotomie(f,0,2,9)
  6. (0.666666674, 0.666666675)
  7. >>> trichotomie(f,0,2,10)
  8. (0.6666666743, 0.6666666744)

Télécharger

Où l’on constate les mêmes problèmes que dans le script précédent.

Avec une fonction dont on sait qu’elle est décroissante puis croissante sur un intervalle [a ; b], donc qu’elle admet un minimum sur cet intervalle.

Le code Python pour approcher le minimum par balayage :

  1. def f(x):
  2.     return -3*x**3+4*x+1 #Entrez ici l'expression de la fonction
  3. def balayage_min(f,a,b,n):
  4.     #n est le nombre de chiffres après la virgule souhaités
  5.     e=10**(-n)
  6.     #e est la précision souhaitée
  7.     #a est la Borne inférieure de l'intervalle dans lequel le maximum a été repéré
  8.     #b est la Borne supérieure de l'intervalle dans lequel le maximum a été repéré
  9.     mini=f(a)
  10.     while b-a>e:
  11.         amplitude=b-a
  12.         for i in range(11): #On découpe arbitrairement [a ; b] en 10
  13.             x=a+amplitude/10*i #calcul des abscisses obtenues en divisant [a ; b] en 10
  14.             if f(x)<mini:
  15.                 mini=f(x)
  16.                 x_min=x
  17.         a=x_min-amplitude/10 #On réduit l'intervalle dans lequel on va appliquer
  18.         b=x_min+amplitude/10 #à nouveau le balayage jusqu'à la précision demandée
  19.     return (round(a,n),round(b,n))

Télécharger

Utilisation :

  1. >>> balayage_min(f,-2,1,5)
  2. (-0.66667, -0.66666)
  3. >>> balayage_min(f,-2,1,7)
  4. (-0.6666667, -0.6666666)
  5. >>> balayage_min(f,-2,1,8)
  6. (-0.66666667, -0.66666667)

Télécharger

Et par trichotomie :
- On entre l’expression de la fonction dans f(x)
 n est le nombre de chiffres après la virgule souhaités
 e est la précision souhaitée
 a est la Borne inférieure de l’intervalle dans lequel le maximum a été repéré
 b est la Borne supérieure de l’intervalle dans lequel le maximum a été repéré

  1. def f(x):
  2.     return -3*x**3+4*x+1
  3. def trichotomie_min(f,a,b,n):
  4.     e=10**(-n)
  5.     while b-a>e:
  6.         m=(b-a)/3
  7.         c=a+m
  8.         d=b-m
  9.         if f(d)<=f(c):
  10.             a=c
  11.         else:
  12.             b=d
  13.     return (round(a,n),round(b,n))

Télécharger

Utilisation :

  1. >>> trichotomie_min(f,-2,1,7)
  2. (-0.6666667, -0.6666666)
  3. >>> trichotomie_min(f,-2,1,8)
  4. (-0.66666667, -0.66666666)
  5. >>> trichotomie_min(f,-2,1,9)
  6. (-0.666666664, -0.666666663)

Télécharger

Algorithme de calcul approché de longueur d’une portion de courbe représentative de fonction.

Ici, on veut approcher une fonction continue sur un intervalle [a ; b] par n segments dont les abscisses des extrémités sont distantes de (b-a)/n :

  1. from math import sqrt
  2. def f(x):
  3.     return x**2 #Modifier la fonction ici
  4. def distance(x1,y1,x2,y2):
  5.     return sqrt((x1-x2)**2 + (y1-y2)**2)
  6. def longueurCourbe(f,a,b,n):
  7.     longueur = 0
  8.     x1,y1 = a,f(a)
  9.     h = (b-a)/n
  10.     for i in range(n):
  11.         x2 = x1 + h
  12.         y2 = f(x2)
  13.         longueur = longueur + distance(x1,y1,x2,y2)
  14.         x1,y1 = x2,y2
  15.     return longueur

Télécharger

Utilisation :

  1. >>> longueurCourbe(f,1,10,50)
  2. 99.5680744899207
  3. >>> longueurCourbe(f,1,10,100)
  4. 99.56828473103201

Télécharger

Python, le tableur ou la calculatrice, pour mettre en évidence l’aspect de programme de calcul.

Au lieu de proposer un programme de calcul basique que l’on trouve dans les manuels scolaires, intéressons-nous à un programme de calcul donné par un « magicien » dans une émission de télévision :

  1. def programme(n):
  2.     N=n-n//10 #on enlève le chiffre des dizaines
  3.     N=N-n%10 #on enlève le chiffre des unités
  4.     return N

Télécharger

Utilisation :

  1. >>> programme(34)
  2. 27
  3. >>>from random import randint
  4. >>> programme(randint(10,99))
  5. 9
  6. >>> programme(randint(10,99))
  7. 81
  8. >>> programme(randint(10,99))
  9. 81
  10. >>> programme(randint(10,99))
  11. 63

Télécharger

On peut alors conjecturer que le nombre obtenu est toujours égal à 9 fois le chiffre des dizaines, ou plus généralement à un multiple de 9, le démontrer, puis démasquer le « truc » du « magicien ».

Exploiter un logiciel de géométrie dynamique ou de calcul formel, la calculatrice ou Python pour décrire les variations d’une fonction donnée par une formule.

On sait qu’une fonction f est croissante sur un intervalle [a ; b] si :
pour tous x et y de [a ; b], si x < y alors f(x) < f(y).
On sait qu’une fonction f est décroissante sur un intervalle [a ; b] si :
pour tous x et y de [a ; b], si x < y alors f(x) > f(y).

On peut donc imaginer de tester « pour tous » x et y de [a ; b], si f(x) < f(y), évidemment ici le "pour tous" va être remplacé par "un certain nombre de" ...
On peut alors avoir l’idée de mettre un "m" quand f(x) < f(y) (ça "monte") et un "d" quand f(x) > f(y) (ça « descend »), comme dans le script suivant :

  1. def f(x):
  2.     return x**3-x**2-12*x-1 #Saisir ici l'expression de la fonction
  3. def sens_variation(a,b,f):
  4.     pas=(b-a)/10
  5.     tableau=[] #On crée une liste qui va stocker les résultats
  6.     for i in range(10):
  7.         x1=a+i*pas
  8.         x2=x1+pas
  9.         y1=f(x1)
  10.         y2=f(x2)
  11.         if y1<y2:
  12.             tableau.append("m")
  13.         else:
  14.             tableau.append("d")
  15.     return tableau

Télécharger

Utilisation :

  1. >>> sens_variation(-5,5,f)
  2. ['m', 'm', 'm', 'd', 'd', 'd', 'd', 'm', 'm', 'm']

Télécharger

Ce qui peut permettre de conjecturer que f est croissante puis décroissante puis croissante sur [-5 ; 5] ...
On peut affiner la conjecture en modifiant l’algorithme de manière à afficher les abscisses, on peut ainsi insérer avant le test if y1<y2 : :

  1. tableau.append(x2)

On obtient alors :
[-4.0, ’m’, -3.0, ’m’, -2.0, ’m’, -1.0, ’d’, 0.0, ’d’, 1.0, ’d’, 2.0, ’d’, 3.0, ’m’, 4.0, ’m’, 5.0, ’m’] ce qui peut permettre de conjecturer que f est croissante puis décroissante puis croissante, le changement de sens de variation se faisant entre -3 et -1 puis entre 1 et 3 (Attention ici à ne pas croire que ces changements se passent dans [-2 ; -1] et dans [2 ; 3], cela n’est pas vrai en général, nous vous laissons y réfléchir avec ces deux images ...).

On peut ensuite affiner :
tableau = [-2.8, ’m’, -2.6, ’m’, -2.4, ’m’, -2.27, ’m’, -2.0, ’m’, -1.8, ’m’, -1.6, ’m’, -1.4, ’d’, -1.2, ’d’, -1.0, ’d’]
tableau = [-1.76, ’m’, -1.72, ’m’, -1.68, ’m’, -1.64, ’d’, -1.6, ’d’, -1.56, ’d’, -1.52, ’d’, -1.48, ’d’, -1.44, ’d’, -1.4, ’d’]
tableau = [-1.712, ’m’, -1.704, ’m’, -1.696, ’m’, -1.688, ’d’, -1.68, ’d’, -1.672, ’d’, -1.664, ’d’, -1.656, ’d’, -1.648, ’d’, -1.64, ’d’]
pour en déduire que le premier changement de sens de variation se passe dans [-1.704 ; -1.688], en réalité en $\frac{2-\sqrt{148}}{6}\approx-1.694$.

Statistique et probabilités

Pour des données réelles ou issues d’une simulation, lire et comprendre une fonction écrite en Python renvoyant la moyenne m, l’écart type s, et la proportion d’éléments appartenant à [m-2s,m+2s].

On a besoin de calculer une racine carrée pour obtenir l’écart-type, ceci n’est pas possible dans Python sauf à importer cette fonction depuis un fichier math.py qui contient de nombreuses fonctions mathématiques, cela se fait à l’aide de la ligne suivante : from math import sqrt

  1. from math import sqrt
  2. def stats(tableau):
  3.         n=len(tableau) #On mesure la taille du tableau
  4.         m=sum(tableau)/n #calcul de la moyenne
  5.         tableau2=[(x-m)**2 for x in tableau] #On crée le tableau des carrés des écarts à la moyenne
  6.         variance=sum(tableau2)/n #Calcul de la variance
  7.         s=sqrt(variance) #Calcul de l'ecartype
  8.         a=m-2*s
  9.         b=m+2*s
  10.         compteur=0
  11.         for i in range(n):
  12.                 if tableau[i]<=b and tableau[i]>=a:
  13.                         compteur+=1
  14.         proportion=compteur/n
  15.         return [m,s,proportion] #On renvoie un tableau qui contient la moyenne, l'écart-type et la proportion d’éléments appartenant à [m-2s,m+2s].

Télécharger

Après avoir compilé le code, on peut taper dans la console :

  1. >>> tableau=[i**2 for i in range(100)]
  2. >>> stats(tableau)
  3. >>> [3283.5, 2953.2966410436998, 0.96]

Télécharger

On peut compléter ce qui précède avec l’ensemble des fonctions qui donnent toutes les caractéristiques d’une série de données ’a 1 variable :

  1. from math import sqrt
  2. def mini(tab):
  3.     minimum=tab[0]
  4.     for element in tab:
  5.         if element<minimum:
  6.             minimum=element
  7.     return minimum
  8. def maxi(tab):
  9.     maximum=tab[0]
  10.     for element in tab:
  11.         if element>maximum:
  12.             maximum=element
  13.     return maximum
  14. def somme(tab):
  15.     somme=0
  16.     for element in tab:
  17.         somme+=element
  18.     return somme
  19. def somme_des_carres(tab):
  20.     somme=0
  21.     for element in tab:
  22.         somme+=element**2
  23.     return somme
  24. def moyenne(tab):
  25.     return somme(tab)/len(tab)
  26. def etendue(tab):
  27.     return maxi(tab)-mini(tab)
  28. def effectif_total(tab):
  29.     return len(tab)
  30. def variance(tab):
  31.     somme=0
  32.     moy=moyenne(tab)
  33.     for element in tab:
  34.         somme+=(element-moy)**2
  35.     return somme/len(tab)
  36. def ecart_type(tab):
  37.     return sqrt(variance(tab))
  38. def ecart_type_echantillon(tab):
  39.     L=len(tab)
  40.     return sqrt(variance(tab)*L/(L-1))
  41. def tri_croissant(tab):
  42.     sortie=tab
  43.     sortie.sort()
  44.     return sortie
  45. def Q1(tab):
  46.     L=len(tab)
  47.     if L%2==0:
  48.         return tri_croissant(tab)[len(tab)//4-1]
  49.     else:
  50.         return tri_croissant(tab)[len(tab)//4]
  51. def Q3(tab):
  52.     L=len(tab)
  53.     if L%2==0:
  54.         return tri_croissant(tab)[3*len(tab)//4-1]
  55.     else:
  56.         return tri_croissant(tab)[3*len(tab)//4]
  57. def mediane(tab):
  58.     L=len(tab)
  59.     sortie=tri_croissant(tab)
  60.     if L%2==0:
  61.         return moyenne([sortie[L//2-1],sortie[L//2]])
  62.     else:
  63.         return sortie[L//2]
  64. def ecart_interquartile(tab):
  65.     return Q3(tab)-Q1(tab)
  66. def Stats_1Var(tab):
  67.     print("Effectif total :"+str(effectif_total(tab)))
  68.     print("Minimum :"+str(mini(tab)))
  69.     print("Maximum :"+str(maxi(tab)))
  70.     print("Étendue :"+str(etendue(tab)))
  71.     print("Moyenne :"+str(moyenne(tab)))
  72.     print("Écart type :"+str(ecart_type(tab)))
  73.     print("Variance :"+str(variance(tab)))
  74.     print("Premier quartile :"+str(Q1(tab)))
  75.     print("Troisième quartile :"+str(Q3(tab)))
  76.     print("Médiane :"+str(mediane(tab)))
  77.     print("Écart interquartile :"+str(ecart_interquartile(tab)))
  78.     print("Somme :"+str(somme(tab)))
  79.     print("Somme des carrés :"+str(somme_des_carres(tab)))
  80.     print("Écart type échantillon :"+str(ecart_type_echantillon(tab)))
  81. def boite_a_moustaches(tab):
  82.     import matplotlib.pyplot as plt
  83.     plt.clf()
  84.     plt.boxplot([mini(tab),Q1(tab),mediane(tab),Q3(tab),maxi(tab)])
  85.     plt.ylim(mini(tab)-2,maxi(tab)+2)
  86.     plt.savefig('SimpleBoxPlot.png')
  87.     plt.show()

Télécharger

Après avoir compilé le code, on peut taper dans la console :

  1. >>> Stats_1Var([6, 47, 49, 15, 43, 41, 7, 39, 43, 41, 36])
  2. Effectif total :11
  3. Minimum :6
  4. Maximum :49
  5. Étendue :43
  6. Moyenne :33.36363636363637
  7. Écart type :15.233173890455644
  8. Variance :232.04958677685954
  9. Premier quartile :15
  10. Troisième quartile :43
  11. Médiane :41
  12. Écart interquartile :28
  13. Somme :367
  14. Somme des carrés :14797
  15. Écart type échantillon :15.97668756202441
  16. >>> boite_a_moustaches([6, 47, 49, 15, 43, 41, 7, 39, 43, 41, 36])

Télécharger


On retrouve bien :

  • Le minimum : 6
  • Le premier quartile : 15
  • La médiane : 41
  • Le troisième quartile : 43
  • Le maximum : 49

Lire et comprendre une fonction Python renvoyant le nombre ou la fréquence de succès dans un échantillon de taille n pour une expérience aléatoire à deux issues.

  1. from random import*
  2. def nb_succes(n,p):
  3.     #n est le nombre de simulations
  4.     #p est la probabilité testée
  5.     c=0
  6.     for k in range(1,n+1):
  7.         t=random()
  8.         if t<p:
  9.             c=c+1
  10.     return c

Télécharger

Utilisation :

  1. >>> nb_succes(1000,0.3)
  2. 303
  3. >>> 303/1000
  4. 0.303

Télécharger

On peut calculer la fréquence dans la console comme ci-dessus ou changer la dernière ligne du programme :

  1.     return c/n

ou pour récupérer nombre et fréquence :

  1.     return [c,c/n]

Observer la loi des grands nombres à l’aide d’une simulation sur Python ou tableur.

En statistiques, la loi des grands nombres exprime le fait que les caractéristiques d’un échantillon aléatoire se rapprochent des caractéristiques statistiques de la population lorsque la taille de l’échantillon augmente. Autrement dit la fréquence de succès d’un événement sur l’échantillon s’approche de la probabilité de cet événement sur la population.
Nous choisissons d’illustrer cela avec un jeu de dé :
On lance un dé à 6 faces non truqué.
 Si c’est 1 qui sort, on gagne 1€.
 Si c’est 2, 3 ou 4 qui sort, on gagne 2€.
 Sinon, on gagne 4€.
L’espérance de gain à ce jeu est donc de $\frac{1 \times 1 + 3\times 2 + 2\times 4}{6} = 2,5€$.
On utilisera deux fonctions :
 Une fonction expérience() qui simule un jeu.
 Une fonction evolutionMoyenne(experience,nExperiences) qui va jouer nExperiences fois le jeu, en calculant la moyenne à chaque nouveau jeu et en représentant graphiquement l’évolution de cette moyenne à l’aide de la librairie matplotlib :

  1. import matplotlib.pyplot as plt
  2. from random import randint
  3. def experience():
  4.     de = randint(1,6)
  5.     # on tire au hasard un nombre entier parmi 1,2,3,4,5,6
  6.     if de < 2:
  7.         X = 1
  8.     elif de < 5:
  9.         X = 2
  10.     else:
  11.         X = 4
  12.     return X
  13. def evolutionMoyenne(experience,nExperiences):
  14.     s = experience()
  15.     n = 1
  16.     L = [s] # moyenne sur 1 expérience
  17.     while n < nExperiences:
  18.         n = n+1
  19.         s = s + experience()
  20.         L.append(s/n) # on ajoute la moyenne sur n expériences
  21.     plt.plot(list(range(1,nExperiences+1)),L,'b.')
  22.     plt.plot([1,nExperiences],[2.5, 2.5],'r-')
  23.     #2.5 est l'espérance de gain
  24.     plt.grid()
  25.     plt.show()

Télécharger

Utilisation :

  1. evolutionMoyenne(experience,500)
Simulation de 100 jeux : nExperiences=100 Simulation de 1000 jeux : nExperiences=1000
Simulation de 2000 jeux : nExperiences=2000 Simulation de 5000 jeux : nExperiences=5000

Bibliographie :