Il modulo fractions ci permette di creare e usare i rational numbers: frazioni con un numeratore intero diviso per un denominatore intero.
Per esempio, possiamo memorizzare 2/3 come frazione esatta invece del valore approssimato float 0.6666...
A differenza dei numeri int, float e complex, le frazioni non hanno una forma letterale.
Tuttavia, il costruttore di frazioni è piuttosto flessibile.
Nel caso più ovvio, può accettare due numeri interi. I fattori comuni vengono rimossi automaticamente, riducendo la frazione alla sua «forma più semplice» (i numeri interi più piccoli che rappresentano accuratamente la frazione):
>>> from fractions import Fraction
>>> f1 = Fraction(2, 3) # 2/3
>>> f1
Fraction(2, 3)
>>> f2 = Fraction(6, 9)
>>> f2
Fraction(2, 3) # automatically simplified
>>> f1 == f2
True
Il costruttore di frazioni può anche analizzare una rappresentazione sotto forma di stringa:
>>> f3 = Fraction('2/3')
>>> f3
Fraction(2, 3)
Può anche lavorare con parametri float, ma questo può dare problemi per via della natura approssimata della rappresentazione interna in binario del valore decimale.
Per saperne di più su questo problema di rappresentazione, vedi il sito 0.30000000000000004 e la pagina Aritmetica in virgola mobile: problemi e limiti della documentazione di Python.
Per un risultato più affidabile quando si usano i numeri in virgola mobile con le frazioni, c'è il metodo <fraction>.limit_denominator().
.limit_denominator() può accettare un parametro intero se hai esigenze specifiche, ma anche il valore predefinito (max_denominator=1000000) può funzionare bene e dare un'approssimazione accettabile e semplice.
>>> Fraction(1.2)
Fraction(5404319552844595, 4503599627370496)
>>> Fraction(1.2).limit_denominator()
Fraction(6, 5)
I soliti arithmetic operators + - * / ** funzionano con le frazioni, come con gli altri tipi numerici.
Si possono includere numeri interi e altri Fraction, e il risultato sarà un Fraction.
Includere un float nell'espressione produce un risultato float, con una conseguente (possibile) perdita di precisione.
>>> Fraction(2, 3) + Fraction(1, 4) # addition
Fraction(11, 12)
>>> Fraction(2, 3) * Fraction(6, 5) # multiply fractions
Fraction(4, 5)
>>> Fraction(2, 3) * 6 / 5 # fraction with integers
Fraction(4, 5)
>>> Fraction(2, 3) * 1.2 # fraction with float -> float
0.7999999999999999
>>> Fraction(2, 3) ** 2 # exponentiation with integer
Fraction(4, 9)
Le frazioni sono ottime per preservare la precisione durante i calcoli intermedi, ma potrebbero non essere ciò che vuoi per il risultato finale.
È possibile ottenere il numeratore e il denominatore singolarmente o come tupla (tuples saranno trattate in un concetto successivo):
>>> Fraction(2, 3).numerator
2
>>> Fraction(2, 3).denominator
3
>>> Fraction(2, 3).as_integer_ratio()
(2, 3)
Anche varie funzioni numeriche standard di Python danno il risultato che ti aspetteresti lavorando con i tipi int e float:
>>> round(Fraction(11, 3))
4
>>> from math import floor, ceil
>>> floor(Fraction(11, 3))
3
>>> ceil(Fraction(11, 3))
4
>>> float(Fraction(11, 3))
3.6666666666666665