La nature des nombres à virgule flottante signifie qu'il n'a pas de sens de vérifier si un nombre à virgule flottante est rationnel, puisque tous les nombres à virgule flottante sont vraiment des fractions de la forme n/2 e. Cependant, vous pourriez vouloir savoir s'il y a une fraction simple (une avec un petit dénominateur plutôt qu'une grande puissance de 2) qui se rapproche étroitement d'un nombre à virgule flottante donné.
Donald Knuth traite de ce dernier problème dans L'art de la programmation par ordinateur volume II. Voir la réponse à l'exercice 4.53-39. L'idée est de rechercher la fraction ayant le plus petit dénominateur dans une fourchette, en élargissant les extrémités de la fourchette en tant que fractions continues tant que leurs coefficients sont égaux, puis, lorsqu'elles diffèrent, de prendre la valeur la plus simple entre elles. Voici une implémentation assez simple en Python:
from fractions import Fraction
from math import modf
def simplest_fraction_in_interval(x, y):
"""Return the fraction with the lowest denominator in [x,y]."""
if x == y:
# The algorithm will not terminate if x and y are equal.
raise ValueError("Equal arguments.")
elif x < 0 and y < 0:
# Handle negative arguments by solving positive case and negating.
return -simplest_fraction_in_interval(-y, -x)
elif x <= 0 or y <= 0:
# One argument is 0, or arguments are on opposite sides of 0, so
# the simplest fraction in interval is 0 exactly.
return Fraction(0)
else:
# Remainder and Coefficient of continued fractions for x and y.
xr, xc = modf(1/x);
yr, yc = modf(1/y);
if xc < yc:
return Fraction(1, int(xc) + 1)
elif yc < xc:
return Fraction(1, int(yc) + 1)
else:
return 1/(int(xc) + simplest_fraction_in_interval(xr, yr))
def approximate_fraction(x, e):
"""Return the fraction with the lowest denominator that differs
from x by no more than e."""
return simplest_fraction_in_interval(x - e, x + e)
Et voici quelques résultats:
>>> approximate_fraction(6.75, 0.01)
Fraction(27, 4)
>>> approximate_fraction(math.pi, 0.00001)
Fraction(355, 113)
>>> approximate_fraction((1 + math.sqrt(5))/2, 0.00001)
Fraction(377, 233)
Les irrationnels ne peuvent pas non plus être représentés par le ratio (nal) s - que la définition même et la source du nom! – delnan
@delnan, FWIW, ils peuvent être représentés comme rationnels. Les deux méthodes couramment utilisées pour le faire formellement (coupes de Dedekind et séries de Cauchy) utilisent des rationnels pour le faire. Ils utilisent juste une quantité infinie de rationnels :) – aaronasterling
Pour un vrai plaisir, cherchez des fractions continues. Pour mettre en œuvre une solution vous-même, vous faites la fraction continue jusqu'à ce qu'il en résulte une fraction exacte ou le dénominateur devient trop grand à votre goût. – phkahler