Aller au contenu

Les nombres réels⚓︎

I. Prérequis sur les puissances⚓︎

Question
  • \(10^0=0\)
  • \(10^0=1\)
  • \(10^0=10\)
  • \(10^0\) n'existe pas
  • ❌ \(10^0=0\)
  • ✅ \(10^0=1\)
  • ❌ \(10^0=10\)
  • ❌ \(10^0\) n'existe pas
Question
  • \(10^{-1}\) est négatif
  • \(10^{-1}\) est positif
  • \(10^{-1}\) est égal à 0
  • \(10^{-1}\) n'existe pas
  • ❌ \(10^{-1}\) est négatif
  • ✅ \(10^{-1}\) est positif
  • ❌ \(10^{-1}\) est égal à 0
  • ❌ \(10^{-1}\) n'existe pas
Question

\(10^{-1}=\)?

  • -1
  • 0
  • 1
  • 10
  • -0,1
  • 0,1
  • ❌ -1
  • ❌ 0
  • ❌ 1
  • ❌ 10
  • ❌ -0,1
  • ✅ 0,1
Question
  • \(2^0=0\)
  • \(2^0=1\)
  • \(2^0=2\)
  • \(2^0\) n'existe pas
  • ❌ \(2^0=0\)
  • ✅ \(2^0=1\)
  • ❌ \(2^0=2\)
  • ❌ \(2^0\) n'existe pas
Question
  • \(2^{-1}\) est négatif
  • \(2^{-1}\) est positif
  • \(2^{-1}\) est égal à 0
  • \(2^{-1}\) n'existe pas
  • ❌ \(2^{-1}\) est négatif
  • ✅ \(2^{-1}\) est positif
  • ❌ \(2^{-1}\) est égal à 0
  • ❌ \(2^{-1}\) n'existe pas
Question

\(2^{-1}=\)?

  • -2
  • 0
  • 2
  • 20
  • 0,2
  • 0,5
  • - 0,5
  • ❌ -2
  • ❌ 0
  • ❌ 2
  • ❌ 20
  • ❌ -0,2
  • ✅ 0,5
  • ❌ -0,5

A retenir

Pour tout réel \(a\) et pour tout entier positif \(n\)

\(a^0=1\)

\(a^{-n}=\dfrac{1}{a^n}\)

Par exemple

  • \(2^{-1}=\dfrac{1}{2^1}=0,5\)
  • \(2^{-2}=\dfrac{1}{2^2}=0,25\)

II. Découverte des "float" ou "nombres flottants"⚓︎

Tester

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Shift+Esc ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Vive les entiers en Python !

Python nous donne la valeur exacte du résultat. 777 est un entier.

Tester

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Shift+Esc ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution

777.0 n'est pas codé dans la machine comme un entier, mais comme un nombre flottant. Nous venons de constater que cela ne revient pas du tout au même !

Tester

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Shift+Esc ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Echec

Nous devrons comprendre pourquoi \(0,1+0,2\) n'est pas égal à \(0,3\) pour Python. Ce n'est pas dû au langage Python, nous aurions le même problème avec d'autres langages.
Ce problème est dû à la façon dont les nombres à virgule appelés en français les flottants sont représentés dans la machine.

Une boucle while

Observez le code suivant. Que remarquez-vous ?

🐍 Script Python
x = 1.0
y = x + 1.0
while y != x:
    x = x * 2
    y = x + 1.0
Solution

On est sur une boucle infinie

Tester

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Shift+Esc ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution

La boucle n'est pas infinie.

Modifier le code

Modifier le code pour afficher le nombre de tours de boucles effectuées.

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Shift+Esc ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution
🐍 Script Python
x = 1.0
y = x + 1.0
cpt = 0  # Le compteur
while y != x:
    x = x * 2
    y = x + 1.0
    cpt = cpt + 1

# En sortie de boucle
print("x = ",x)
print("y = ",y)
print("y - x = ", y - x)
print("nombre de boucles effectuées : ", cpt)

Bilan

Nous allons étudier la représentation des réels dans la machine. Cela va nous permettre de comprendre ces comportements, et surtout d'apprendre qu'il y a des choses qu'il ne faut pas faire.

III. Codage en binaire des nombres à virgule⚓︎

1. Rappel sur la base 10⚓︎

5 3 2 , 3 6 1
centaines dizaines unités virgule dixième centième millième

\(532,361_{10} = 5 \times 10^2 + 3 \times 10^1 + 2 \times 10^0 + 3 \times 10^{-1} + 6 \times 10^{-2} + 1 \times 10^{-3}\)

2. En binaire⚓︎

\(101,11_{2} = (1 \times 2^2 + 0 \times 2^1 + 1 \times 2^0 + 1 \times 2^{-1} + 1 \times 2^{-2})_{10}=4 + 1 + \dfrac{1}{2}+ \dfrac{1}{4}=4+1+0.5+0,25=5.75_{10}\)

\(110,101_2=(1 \times 2^2 + 1 \times2^1 +0 \times 2^0 + 1 \times 2^{-1} +0 \times 2^{-2}+1 \times 2^{-3})_{10} =4+2+0,5+0,125=6,625_{10}\)

Ecriture dyadique

On dit que \(110,101_2\) est l'écriture dyadique de \(6,625_{10}\)

IV. conversion⚓︎

1. Méthode de conversion⚓︎

Exemple

Considérons le nombre \(3,6875\). Il se décompose en une partie entière (3) et une partie décimale (\(0,6875\)).

  • partie entière : \(3=11_2\)
  • partie décimale : la conversion de \(0,6875\) se fait en plusieurs étapes.
    👉 A chaque étape, on multiplie la partie décimale par 2 :

  • \(0,6875 \times 2 = \textbf{1},375\) Partie décimale : \(0,375\)

  • \(0,375 \times 2 = \textbf{0},75\) Partie décimale : \(0,75\)
  • \(0,75 \times 2 = \textbf{1},5\) Partie décimale : \(0,5\)
  • \(0,5 \times 2 = \textbf{1},0\) Partie décimale : \(0,0\)
  • On pourrait continuer ... mais \(0,0 \times 2 = \textbf{0},0\) ...

👉 On s'arrête quand la partie décimale est nulle.

On prend ensuite le chiffre des unités de tous les nombres obtenus : 1011

Donc \(3,6875_{10}=11,1011_2\)

Exercice 1

Donner l'écriture binaire de 20,875.

  • partie entière : \(20 = 10100_2\)
  • partie décimale :
    • \(0,875 \times 2 = \textbf{1},75\)
    • \(0,75 \times 2 = \textbf{1},5\)
    • \(0,5 \times 2 = \textbf{1}\)

Donc \(20,875=10100,111_2\)

Exercice 2

Donner l'écriture binaire de 0,2.

  • partie entière : \(0 = 0_2\)
  • partie décimale :
    • \(0,2 \times 2 = \textbf{0},4\)
    • \(0,4 \times 2 = \textbf{0},8\)
    • \(0,8 \times 2 = \textbf{1},6\)
    • \(0,6 \times 2 = \textbf{1},2\)
    • \(0,2 \times 2 = \textbf{0},4\)
    • et cela continue...

Le nombre 0,2 n'admet pas d'écriture binaire finie.

\(0,2_{10}=0,00110011..._{2}\)

Exercice 3

Donner l'écriture binaire de 0,1.

  • partie entière : \(0 = 0_2\)
  • partie décimale :
    • \(0,1 \times 2 = \textbf{0},2\)
    • \(0,2 \times 2 = \textbf{0},4\)
    • \(0,4 \times 2 = \textbf{0},8\)
    • \(0,8 \times 2 = \textbf{1},6\)
    • \(0,6 \times 2 = \textbf{1},2\)
    • \(0,2 \times 2 = \textbf{0},4\)
    • et cela continue...

Le nombre 0,1 n'admet pas d'écriture binaire finie.

\(0,1_{10}=0,0001100110011..._{2}\)

Conclusion⚓︎

Mon info

Certains nombres n'admettent pas une écriture binaire finie. Or la mémoire d'un ordinateur, quelqu'il soit, est toujours finie. Certains nombres ne peuvent donc pas être représentés correctement en machine : c'est une impossibilité théorique. Cela amène à des comportements étranges comme ce que nous avons déjà vu dans la partie découverte :

🐍 Script Python
>>> 0.1 + 0.2
0.30000000000000004
remarque sur quelques flottants usuels

Parmi les nombres décimaux à un chiffre après la virgule (0.1, 0.2, 0.3 ...) seul 0.5 admet une écriture binaire finie ! Tous les autres ont une représentation en machine qui n'en donne qu'une valeur approchée.

V. Conséquences : la difficile manipulation des flottants⚓︎

Le type float

En python, les nombres non entiers sont du type float.

🐍 Script Python
>>> type(0.1)
<class 'float'>

Remarque

Ces flottants (traduction française) sont à manipuler avec une extrême précaution. Il faut garder en tête que les calculs sont potentiellement faux, du moins imprécis, lorsque des flottants interviennent.

🐍 Script Python
>>> 0.5-0.2-0.2-0.1
-2.7755575615628914e-17
Une tragique histoire vraie

En 1991, durant la Guerre du Golfe, un missile anti-missile américain a raté sa cible de 500 mètres car son ordinateur interne émettait un signal toutes les 0.1 secondes. Au bout de 100 heures de fonctionnement, l'approximation du nombre flottant 0.1 a conduit à un décalage de 0,34 secondes, ce qui lui a fait rater sa cible. (source)

VI. Comment faire des tests d'egalité sur les flottants ?⚓︎

Remarque

Première réponse : ON NE FAIT PAS DE TEST DE COMPARAISONS ENTRE FLOTTANTS.

Si a et b sont deux flottants, le test classique

🐍 Script Python
if a == b :
    print("a et b sont égaux")

a de grandes chances d'échouer :

Le script

🐍 Script Python
1
2
3
4
5
6
a = 0.1
b = 0.3 - 0.2
if a == b :
    print("a et b sont égaux")
else :
    print("a et b sont différents")

renverra

📋 Texte
a et b sont différents
On se débrouille autrement

Si vraiment un test d'égalité est nécessaire, on ne va pas tester l'égalité entre a et b mais leur proximité, grâce à la valeur absolue de leur différence.

La fonction abs(a-b) renvoie un nombre positif égal à la distance entre a et b. Il faut alors décider d'un écart minimal e en dessous duquel on considèrera que a et b sont égaux.

Le script

🐍 Script Python
a = 0.1
b = 0.3-0.2
e = 10**(-12)
if abs(a-b) < e :
    print("a et b sont égaux")
else :
    print("a et b sont différents")
renverra

🐍 Console Python
a et b sont égaux

VII. Codage des réels en machine⚓︎

1. La notation scientifique⚓︎

La notation scientifique

Les nombres très grands (ou très petits) ont une écriture décimale difficile à manipuler, à lire ou à utiliser on préfère les écrire en notation scientifique c'est à dire sous la forme :

\(a \times 10^n\)

\(a\) appelé mantisse est un nombre compris entre 1 et 10 et \(n\) appelé exposant est un entier positif ou négatif.

Par exemple :

  • \(760000000 = 7,6 \times 10^8\)
  • \(0,00000000049 = 4,9 \times 10^{-10}\)

A retenir

Il faut un seul chiffre différent de zéro avant la virgule.

La notation scientifique en binaire

En binaire, le seul chiffre possible avant la virgule est donc 1 en notation scientifique.

Exemples

\(1010,0111_2=1,0100111_2 \times (2^3)_{10}\)

\(0,001101_2=1,101_2 \times (2^{-3})_{10}\)

2. La norme IEEE-754⚓︎

IEEE-754

Source de l'image : By Codekaizen - Own work, CC BY-SA 4.0

La norme

\(s\) est le bit de signe (bit 63 représenté en bleu).
\(e\) est codé sur les 11 bits représentés en vert. C'est l'exposant décalé.
\(f\) est codé sur les 52 bits représentés en rouge.
La mantisse \(m\) est égale à \(1,f\). (Le "\(1,\)" étant évident n'est pas codé pour économiser un bit).
Soit \(x\) le réel ainsi codé :
\(x = (-1)^{s} \times m \times 2^{e-1023}\)

Exemple

\(0,01101_2=1,101_2 \times 2^{-2}_{10}\)

m = 1,101 est la mantisse

  • Signe positif donc \(s=0\)

  • m = 1,f

La mantisse en base 2 commence toujours par 1. Comme nous l'avons vu, On économise un bit en ne codant pas le 1 qui est devant la virgule.

On a donc f = 1010000000000...

  • \(-2=e-1023\) donc \(e=1023-2=1021\)

Il faut donc écrire 1021 en binaire sur 11 bits. Par divisions successives, on trouve : \(1021_{10}=01111111101_2\)

👉 \(0,01101_2=2^{-2}+2^{-3}+2^{-5}=0.40625\)

Nous venons de voir comment ce nombre était codé dans notre machine :

\(0\) \(01111111101\) \(10100000000000000000000000000000000000000000000000000\)

VIII. Exercices⚓︎

1. \(1,3_{10}\)
  • est représenté exactement en machine par \(\dfrac{3}{10}\)
  • est représenté exactement en machine par \(0,11_2\)
  • ne peut pas être représenté exactement en machine car c'est un nombre à virgule
  • ne peut pas être représenté exactement car son écriture dyadique est illimitée
  • ❌ est représenté exactement en machine par \(\dfrac{3}{10}\)
  • ❌ est représenté exactement en machine par \(0,11_2\)
  • ❌ ne peut pas être représenté exactement en machine car c'est un nombre à virgule
  • ✅ ne peut pas être représenté exactement car son écriture dyadique est infinie
2. \(0,25_{10}\)
  • est représenté exactement en machine par \(0,1_2\)
  • est représenté exactement en machine par \(0,01_2\)
  • ne peut pas être représenté exactement en machine car c'est un nombre à virgule
  • ne peut pas être représenté exactement car son écriture dyadique est illimitée
  • ❌ est représenté exactement en machine par \(0,1_2\)
  • ✅ est représenté exactement en machine par \(0,01_2\)
  • ❌ ne peut pas être représenté exactement en machine car c'est un nombre à virgule
  • ❌ ne peut pas être représenté exactement car son écriture dyadique est illimitée
3. Quelle est l'écriture décimale de \(0,11_2\) ?
  • 0,5
  • 0,25
  • 0,75
  • 0,3
  • ❌ 0,5
  • ❌ 0,25
  • ✅ 0,75
  • ❌ 0,3
4. Quelle est l'écriture dyadique de \(0,625_{10}\) ?
  • \(0,101_2\)
  • \(0,011_2\)
  • \(0,110_2\)
  • \(0,111_2\)
  • ✅ \(0,101_2\)
  • ❌ \(0,011_2\)
  • ❌ \(0,110_2\)
  • ❌ \(0,111_2\)
5. Un seul des nombres suivants n'a pas une écriture finie en base 2, lequel ?
  • \(1,25_{10}\)
  • \(1,5_{10}\)
  • \(1,6_{10}\)
  • \(1,75_{10}\)
  • ❌ \(1,25_{10}\)
  • ❌ \(1,5_{10}\)
  • ✅ \(1,6_{10}\)
  • ❌ \(1,75_{10}\)
6. coder 1/3 en binaire

Ecrire le codage de \(\dfrac{1}{3}\) en binaire.

Astuce 1
  • \(\dfrac{1}{3} = 0,3333 ...\) avec des \(3\) répétés à l'infini.
  • Vous pouvez utiliser la méthode apprise :
    \(0,33333... \times 2 = \boxed{0},66666... (\dfrac{2}{3})\)
Astuce 2

\(0,66666... \times 2 = \boxed{1},33333...\) car \(\dfrac{2}{3} \times 2 = \dfrac{4}{3}=1+\dfrac{1}{3}\)

Solution

\(0,33333... \times 2 = \boxed{0},66666... =\dfrac{2}{3}\)
\(0,66666... \times 2 = \boxed{1},33333...\) car \(\dfrac{2}{3} \times 2 = \dfrac{4}{3}=1+\dfrac{1}{3}\)
\(0,33333... \times 2 = \boxed{0},66666...\)
\(0,66666... \times 2 = \boxed{1},33333...\)
Le processus se reproduit de façon identique.
Le codage de \(\dfrac{1}{3}\) en binaire est donc \(\boxed{0,010101010101...}\) la période 01 se répétant à l'infini.

7. Comment coder 1/3 dans une machine ?

Déduire du résultat de l'exercice précédent le codage de \(\dfrac{1}{3}\) avec la norme IEEE 754. Vous pourrez utiliser l'instruction bin pour vous aider.

Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Solution

\(0,010101010101...=(1,0101010101...)_{2} \times (2^{-2})_{10}\)
\(-2=e-1023\) donc \(e=1023 - 2=1021\)

En utilisant des divisions successives, ou l'instruction bin(1021), on trouve que \(1021_{10}=1111111101_2\)

\(f = 01010101............\)
Le codage de \(\dfrac{1}{3}\) est donc :
\(0 \quad 01111111101 \quad 0101010101010101010101010101010101010101010101010101\)

IX. Compléments⚓︎

Après avoir téléchargé le fichier, vous pourrez le lire à partir de Basthon

🌐 TD à télécharger : Fichier reels_compl.ipynb : "Clic droit", puis "Enregistrer la cible du lien sous"

Vous pouvez tester la représentation des réels en machine ici : IEEE754

X. Crédits⚓︎

  • Une grande partie du II. de ce cours a été réalisée par Gilles LASSUS.
  • Les QCM du VIII ont été réalisés par Fabrice Nativel.