Applications des valeurs numériques en Python

Application 1 : le programme 10_vers_2.py

Écrire un programme en Python 10_vers_2.py qui demande à l'utilisateur un nombre en base 10 et qui affiche sa représentation en base 2. Le nombre saisie peut être entier (seulement des chiffres 0 à 9) ou à virgule (contenant un seul caractère point).

Remarque :

  • vous veillerez à filtrer la chaîne de caractères saisie par l'utilisateur afin de détecter toute saisie ne correspondant pas au format demandé, et à ré-inviter l'utilisateur à entrer un nouveau nombre en cas d'anomalie constatée
  • pour effectuer la convertion de la base 10 vers la base 2 vous implémenterez l'algorithme vu en classe (succession de division par 2 avec conservation des restes pour la partie entière, et succession de multiplication par 2 avec conservation de la partie entière pour convertir la partie fractionnaire).

 

Cliquez ici pour télécharger la solution de l'application 1 : 10_vers_2.pyw

 

Application 2 : le programme 2_vers_10.py

Écrire un programme en Python 2_vers_10.py qui demande à l'utilisateur un nombre en base 2 et qui affiche sa représentation en base 10. Le nombre saisie peut être entier (seulement des chiffres 0 et 1) ou à virgule (contenant un seul caractère point).

Remarque :

  • vous veillerez à filtrer la chaîne de caractères saisie par l'utilisateur afin de détecter toute saisie ne correspondant pas au format demandé, et à ré-inviter l'utilisateur à entrer un nouveau nombre en cas d'anomalie constatée
  • pour effectuer la convertion de la base 2 vers la base 10 vous implémenterez l'algorithme vu en classe (addition des poids des bits qui sont à 1, aussi bien pour la partie entière (puissances de 2 positives) que pour la partie fractionniare (puissances de 2 négatives)).

 

Cliquez ici pour télécharger la solution de l'application 2 : 2_vers_10.pyw

 

Application 3 : le programme 10_vers_2_python.py

Proposez une autre version du programme 10_vers_2.py, que nous appellerons 10_vers_2_python.py, en utilisant cette fois au maximum les fonctions de conversion directes dispobibles dans Python et sans faire à la main la succession de divisions ou de multiplications par 2.

Voici quelques idées de base à tester, à s'inspirer et à améliorer ou à compléter pour écrire le programme 10_vers_2_python.py demandé.

Si le nombre saisi est un entier, la fonction bin() suffira. Il faut juste filtrer la chaîne de caractères renvoyée pour supprimer le préfixe '0b' :

>>> n=9
>>> bin(n)
'0b1001'
>>> bin(n)[2:]
'1001'

Si le nombre en base 10 est un nombre à virgule, il faut également trouver la partie fractionnaire. Or la fonction bin() ne traite que des nombres entiers.

Exemple : si on saisie 9.25 on attend 1001.01 en binaire (8+1+1/4)

Pour connaître instantanément le codage en binaire d'un nombre à virgule flottante on va interpréter la chaîne de caractères renvoyée par float.hex() :

>>> ch_hexa=float.hex(9.25)
>>> ch_hexa
'0x1.2800000000000p+3'

L'exposant suit le caractère 'p' et va jusqu'à la fin de la chaîne :

>>> ch_hexa[ch_hexa.index('p')+1:]
'+3'

Enregistrons-le en valeur numérique :

>>> exposant=int(ch_hexa[ch_hexa.index('p')+1:])
>>> exposant
3

Passons à la partie fractionnaire de la mantisse. Comme le format renvoyé par float.hex() est toujours le même, la partie fractionnaire de la mantisse (située entre les caractères '.' et 'p' dans la chaîne ch_hexa) se retrouve facilement par tranchage entre les positions 4 et 17 :

>>> ch_hexa[4:17]
'2800000000000'

Il faut convertir ce nombre hexadécimal en binaire :

>>> bin(int(ch_hexa[4:17],16))
'0b10100000000000000000000000000000000000000000000000'

Supprimons le préfixe '0b' :

>>> bin(int(ch_hexa[4:17],16))[2:]
'10100000000000000000000000000000000000000000000000'

Problème : lors de la conversion de l'hexadécimal vers le binaire naturel, le chiffre de poids fort n'a pas été forcément converti en un quartet : les bits de poids forts non significatifs (donc à 0) ne sont pas présents, il faut les rajouter.

Commençons par enregistrer la chaîne représentant la mantice en binaire :

>>> ch_bin=bin(int(ch_hexa[4:17],16))[2:]
>>> ch_bin
'10100000000000000000000000000000000000000000000000'

Posons-nous la question si elle contient un nombre entier de quartet, ce qui revient à vérifier si sa taille est multiple de 4 :

>>> len(ch_bin) % 4
2

Ici le reste de la division entière par 4 donne 2, ce qui signifit qu'il manque 2 zéros sur les bits de poids forts. Ajoutons-les :

>>> ch_bin='00'+ch_bin
>>> ch_bin
'0010100000000000000000000000000000000000000000000000'
>>> len(ch_bin) % 4
0

Maintenat la chaîne ch_bin contient bien des quartets complets.

Ajoutons la partie entière de la mantisse que nous avons laissé de côté :

>>> ch_bin='1.'+ch_bin
>>> ch_bin
'1.0010100000000000000000000000000000000000000000000000'

Enfin il reste à décaler la virgule selon l'exposant (traitement non détaillé ici ...). Comme l'exposant vaut ici +3, il faut décaler la virgule de 3 rangs vers la droite.

>>> exposant
3

Après traitement de la chaîne ch_bin on obtient bien la valeur en base 2 de 9.25 :

>>> ch_bin
'1001.0100000000000000000000000000000000000000000000000'

Un dernier traitement (non détaillé ici ...) pourait être la supression des zéros non significatifs dans la partie fractionnaire. On obtiendrait alors :

>>> ch_bin
'1001.01'

Nous venons de faire "à la main" dans la console de Python ce que le programme 10_vers_2_python.py doit réaliser automatiquement. A vous de jouer maintenant !

 

Application 4 : le programme 2_vers_10_python.py

Proposez une autre version du programme 2_vers_10.py, que nous appellerons 2_vers_10_python.py, en utilisant cette fois au maximum les fonctions de conversion directes dispobibles dans Python et sans faire à la main la somme des poids des bits qui sont à 1.

Exemple : si on saisie '1001.01' le programme doit renvoyer 9.25

Voici quelques idées de base à tester, à s'inspirer et à améliorer ou à compléter pour écrire le programme 10_vers_2_python.py demandé.

Si le nombre saisi en base 2 est un nombre entier, la fonction int() donnera instantanément son équivalent en base 10 à condition de lui préciser que la chaîne à analyser est en base 2 :

>>> ch='1001'
>>> int(ch,2)
9

Si la chaîne possède un séparateur décimal, l'idée est alors la suivante :

1 - déterminer la position de la virgule et en déduite le nombre de bits constituant la partie entière et la partie fractionnaire :

>>> ch='1001.01'
>>> ch.index('.')
4
>>> len(ch)-ch.index('.')-1
2

Ici la partie entière contient 4 bits et la partie fractionnaire contient 2 bits.

2 - supprimer la virgule (caractère point) dans la chaîne, ce qui revient à effectuer un décalage à gauche de 2 bits, c'est-à-dire une multiplication par 4 :

>>> ch=ch.replace('.','')
>>> ch
'100101'

3 - convertir en décimal le nombre entier obtenu :

>>> int(ch,2)
37

4 - enfin il reste à effectuer un décalage à droite de 2 bits pour revenir au nombre de départ, ce qui revient à faire une division par 4 :

>>> 37/4
9.25

En partant de la chaîne de caractères '1001.01' nous sommes bien retombé sur le nombre 9.25 qui est son équivalent en base 10.

Nous venons de voir dans la console de Python les grandes lignes de ce que le programme 10_vers_2_python.py doit réaliser automatiquement. A vous de jouer maintenant en vous en inspirant !

 

Application 5 : erreur de calcul en virgule flottante

Dans la console de Python tapez l'addition 0.1+0.2

Que constatez-vous ?

Comment se code en binaire sur 64 bits les nombres 0.1 et 0.2 ?

Effectuez la somme binaire en utilisant vos résultats, puis reconvertissez en décimal le résultat de l'addition en binaire.

Retombez-vous sur le résultat approximatif de Python ou sur 0.3 exactement ?

Testez de la même manière d'autres additions dont le résultat donné par Python est faux.

 

Application 6 : les différentes méthodes d'arrondi

Nous avons vu que la fonction int() de Python permet de convertir un nombre à virgule en nombre entier.

Exemple :

>>> int(7.89)
7
>>> int(1.0056)
1

Python dispose également d'une fonction round() qui arrondi un nombre décimal à un nombre entier.

Exemple :

>>> round(63.87)
64
>>> round(45.21)
45

Faites des expériences dans la console de Python en passant en paramètres différents nombres à virgule à int() et à round(), aussi bien des nombres positifs que négatifs, puis répondez aux questions suivantes :

Les fonctions int() et round() donnent-elles toujours le même résultat si on leur passe en paramètre le même nombre à virgule ?

Dans quels cas les fonctions int() et round() donnent-elles le même résultats ?

Dans quels cas les fonctions int() et round() ne donnent-elles pas le même résultats ?

En mathématiques il existe principalement 4 méthodes d'arrondi pour convertir un nombre décimal en nombre entier :

  • garder la partie entière
  • arrondir à l'entier le plus proche
  • renvoyer le plus petit entier supérieur
  • renvoyer le plus grand entier inférieur

Exemples :

Nombre
partie entière
entier le plus proche
entier supérieur
entier inférieur
2.3
2
2
3
2
17.9
17
18
18
17
45.08
45
45
46
45
37.0
37
37
38
36
86.5
86
87
87
86
52.99999
52
53
53
52
-7.8
-7
-8
-7
-8
-6.001
-6
-6
-6
-7
-3.5
-3
-4
-3
-4
etc.

Proposez une fonction en Python qui renvoie systématiquement la partie entière d'un nombre décimal, quel que soit sa partie fractionnaire.

Proposez une fonction en Python qui renvoie systématiquement l'entier le plus proche d'un nombre décimal.

Proposez une fonction en Python qui renvoie systématiquement le premier entier scritement supérieur d'un nombre décimal.

Proposez une fonction en Python qui renvoie systématiquement le premier entier scritement inférieur d'un nombre décimal.

La fonction int() réalise-t-elle une de ces 4 méthodes d'arrondi ? Si oui laquelle ?

La fonction round() réalise-t-elle une de ces 4 méthodes d'arrondi ? Si oui laquelle ?

Existe-t-il en Python d'autre fonctions toutes faites (en plus de int() et round()) réalisant une méthode d'arrondi ? Si oui lesquelles ? Et à quelle méthode d'arrondi correspondent-elles ?

 


 

 

Site Internet : python.gecif.net

Auteur : Jean-Christophe MICHEL

Professeur de Sciences Industrielles de l'Ingénieur
option Informatique et Numérique

Courriel : jc.michel@gecif.net