Mathématiques avec Python et Ruby/Fractions en Python

L'écriture de nombres non entiers sous forme de fractions a de loin précédé celle des nombres décimaux, puisque les égyptiens et les babyloniens les utilisaient déjà. Chaque fois que le dénominateur n'est pas une puissance de 10, on continue encore de nos jours à utiliser des écritures fractionnaires plus ou moins cachées, comme dans les exemples suivants :

  1. Lorsqu'on dit qu'un homme mesure 5 pieds 7 pouces, ça signifie que sa taille, en pieds, est (il y a douze pouces dans un pied);
  2. Lorsqu'on dit qu'il est 8 heures 13, c'est que depuis minuit, il est passé exactement heures (soit 493 minutes).
  3. Lorsque Roméo se plaint d'avoir attendu Juliette pendant plus de trois quarts-d'heure, il exprime la durée de son attente insoutenable sous la forme d'une fraction...
  4. Les probabilités se donnent aussi souvent sous forme de fractions (le plus souvent des fractions égyptiennes). Comme dans "j'ai une chance sur 10 millions de recevoir une météorite sur la tête" ou "Casaque Jaune est donné favori à 5 contre 1".
  5. Idem parfois pour les statistiques : "5 Français sur 7 estiment qu'il y a trop de sondages sur les sondages"...


L'égalité 0,2+0,5=0,7 peut s'écrire mais l'égalité ne peut pas s'écrire sous forme décimale exacte parce que le résultat n'est pas décimal. Python affiche 1/2+1/3=0.8333333333333333 et malgré l'abondance de chiffres, cette égalité n'est pas exacte.

Pour faire des calculs exacts avec des fractions, Python a un module fractions.py. Pour transformer Python en un langage de programmation spécialisé dans les fractions, il suffit de précéder les scripts de ce chapitre de la ligne

from fractions import *

qui importe le module fractions en entier (pourquoi faire dans le détail?). Une alternative est de chercher le fichier __init__.py, initialement vide, et d'y mettre la ligne précédente.

Obtention d'une fraction

modifier

Pour entrer la fraction   dans Python, on entre Fraction(n,d) après avoir importé le module fractions :

from fractions import *
a=Fraction(24,10)
print(a)

On constate que la fraction   a été automatiquement simplifiée par Python au moment de son instanciation.

Si on entre 0 comme dénominateur, la fraction ne se crée pas et on a un message d'erreur : Comme une fraction est un quotient, on ne peut pas diviser par 0.

Une fois qu'une fraction est calculée, on peut obtenir son numérateur et son dénominateur par

from fractions import *
a=Fraction(24,10)
print(a.numerator)
print(a.denominator)

Bien entendu, le numérateur de   n'est pas 24...

Pour obtenir la valeur de la fraction (le quotient de son numérateur par son dénominateur), on peut lui additionner 0.0 : La somme d'une fraction et d'un réel, même nul, est un réel.

from fractions import *
a=Fraction(24,10)
print(a+0.0)

Réciproquement, on peut convertir un nombre réel en fraction, mais le résultat est parfois surprenant, si on prend un nombre dont le développement décimal s'arrête alors que le développement binaire ne le fait pas :

from fractions import *
a=Fraction.from_float(1.2)
print(a)

On s'attendait à  , on a l'approximation un peu surprenante  ...

Opérations

modifier

Les opérations sur les fractions se notent comme celles sur les autres nombres, mais en général le résultat est une fraction.

Opérations unaires

modifier

Opposé

modifier

L'opposée d'une fraction s'obtient en la faisant précéder du signe -. Par exemple, la fraction suivante est positive :

from fractions import *
a=Fraction(2,-3)
print(-a)

Inverse

modifier

Pour obtenir l'inverse d'une fraction, on divise 1 par celle-ci :

from fractions import *
a=Fraction(5,4)
print(1/a)

Addition

modifier

La somme de deux fractions est une fraction :

from fractions import *
a=Fraction(34,21)
b=Fraction(21,13)
print(a+b)

Soustraction

modifier

La différence de deux fractions est une fraction :

from fractions import *
a=Fraction(34,21)
b=Fraction(21,13)
print(a-b)


Multiplication

modifier

Le produit de deux fractions est une fraction :

from fractions import *
a=Fraction(34,21)
b=Fraction(21,13)
print(a*b)


Division

modifier

Le quotient de deux fractions est une fraction (à condition que la deuxième ne soit pas nulle) :

from fractions import *
a=Fraction(34,21)
b=Fraction(21,13)
print(a/b)

Le reste euclidien continue à être défini pour des fractions, et le résultat est une fraction :

from fractions import *
a=Fraction(32,7)
b=Fraction(7,2)
print(a%b)

Puissance

modifier

Si l'exposant est entier, la puissance d'une fraction est une fraction :

from fractions import *
a=Fraction(3,2)
print(a**12)
print(a**(-1))

Mais si l'exposant est un réel, la puissance n'est pas une fraction mais un réel :

from fractions import *
a=Fraction(9,4)
print(a**0.5)


Algorithmes

modifier

Réduite de Farey

modifier

La création de réduite de Farey est aisée avec le module fractions de Python:

from fractions import *
def Farey(a,b):
    n=a.numerator+b.numerator
    d=a.denominator+b.denominator
    return Fraction(n,d)


a=Fraction(5,4)
b=Fraction(1,13)
print(Farey(a,b))

C'est si facile qu'on en vient tout de suite à la question suivante : à quoi ça peut bien servir ?

Si on répond que ça sert à fabriquer un arbre de Stern-Brocot, ça n'éclaire peut-être pas beaucoup, mais disons que ça sert à quelque chose de mathématique...

Fractions égyptiennes

modifier

Une fraction égyptienne est définie comme une somme d'inverses d'entiers. En effet les égyptiens avaient la réputation de ne pas utiliser de numérateurs. Toute fraction peut s'écrire comme une somme de fractions égyptiennes, et l'algorithme de Fibonacci permet d'en trouver un exemple à partir de la fraction. Dans la version Python ci-dessous, l'algorithme fournit une liste de fractions, toutes de numérateur 1, dont la somme est une fraction donnée f. Mais au cas où f serait supérieure à 1, on commence la liste par un entier :

 
from fractions import *
from math import *

def egypt(f):
	e=int(f)
	f-=e
	liste=[e]
	while(f.numerator>1):
		e=Fraction(1,int(ceil(1/f)))
		liste.append(e)
		f-=e
	liste.append(f)
	return liste

a=Fraction(21,13)
print(egypt(a))

Quelques explications sur le bricolage ci-dessus : Le dénominateur d'une fraction égyptienne est choisi entier (bien sûr) et plus grand que l'inverse de la fraction f (pour que l'algorithme converge). Une solution serait de prendre la troncature int de l'inverse de f et ajouter 1. Mais si l'inverse de f est entier, on ne doit pas ajouter 1 (sinon la suite est infinie). Alors on utilise la fonction ceil. Donc

  1. Il a fallu importer le module math qui contient cette fonction ceil;
  2. Du coup l'objet ceil(1/f) n'est plus un entier mais un réel, et ne peut plus être le dénominateur d'une fraction (message d'erreur de Python). Alors il faut convertir ce réel (qui est déjà entier, mais Python ne le sait pas) en entier, ce qui se fait par int.

Enfin, Python ne possédant pas de boucle do..while, il faut ajouter la dernière fraction égyptienne à la liste, pour que celle-ci soit complète.

En lançant le script ci-dessus, on apprend que  .