2014-04-28 24 views

risposta

63

Sono disponibili due opzioni:

  1. Utilizzare float.as_integer_ratio(): (., Come di Python 3.6, è possibile do the same with a decimal.Decimal() object)

    >>> (0.25).as_integer_ratio() 
    (1, 4) 
    

  2. Utilizzare la fractions.Fraction() type:

    >>> from fractions import Fraction 
    >>> Fraction(0.25) 
    Fraction(1, 4) 
    

Quest'ultimo ha una molto utile str() conversione:

>>> str(Fraction(0.25)) 
'1/4' 
>>> print Fraction(0.25) 
1/4 

Poiché i valori in virgola mobile può essere impreciso, si può finire con 'strano 'frazioni; limitare il denominatore a 'semplificare' la frazione in qualche modo, con Fraction.limit_denominator():

>>> Fraction(0.185) 
Fraction(3332663724254167, 18014398509481984) 
>>> Fraction(0.185).limit_denominator() 
Fraction(37, 200) 

Se si sta utilizzando Python 2.6 ancora, quindi Fraction() non ancora supporta il passaggio in un float direttamente, ma si può combinare le due cose tecniche di cui sopra in:

Fraction(*0.25.as_integer_ratio()) 

Oppure si può semplicemente utilizzare il Fraction.from_float() class method:

Fraction.from_float(0.25) 

che essenzialmente fa la stessa cosa, ad es. prendere la tupla del rapporto intero e passarla come due argomenti separati.

E una piccola demo con i propri valori di esempio:

>>> for f in (0.25, 0.5, 1.25, 3.0): 
...  print f.as_integer_ratio() 
...  print repr(Fraction(f)), Fraction(f) 
... 
(1, 4) 
Fraction(1, 4) 1/4 
(1, 2) 
Fraction(1, 2) 1/2 
(5, 4) 
Fraction(5, 4) 5/4 
(3, 1) 
Fraction(3, 1) 3 

Sia il modulo fractions e il metodo float.as_integer_ratio() sono nuovi in ​​Python 2.6.

+0

Grazie! Le opzioni 1 funzionano, ma l'opzione 2 (Fraction (0.25)) mi dà l'errore: "TypeError: l'oggetto 'float' non può essere interpretato come un indice". Puoi dirmi perché? – user2370460

+0

Ottima risposta. Link ed esempi molto utili. – fr1tz

+0

@ user2370460: Quale versione di Python stai usando? –

7
from fractions import Fraction 

print(Fraction(0.25)) 
print(Fraction(0.5)) 
print(Fraction(1.25)) 
print(Fraction(3)) 

#1/4 
#1/2 
#5/4 
#3 
+0

Grazie, ma questo mi dà: "TypeError: l'oggetto 'float' non può essere interpretato come un indice". Puoi dirmi perché? – user2370460

+1

Un buon suggerimento, ma vorrei aggiungere: il costruttore di un argomento funziona bene per alcuni numeri, ma non per altri. Ad esempio, 'Fraction (.2)' diventa 'Fraction (3602879701896397, 18014398509481984)'. Potrebbe essere meglio usare il costruttore a due argomenti, es. 'Frazione (2,10)' – Kevin

+2

@Kevin: questo perché .2 non può essere rappresentato con precisione da un float. Vedi la mia risposta per una soluzione alternativa; limita il denominatore e puoi riportarlo a 2/10 in un batter d'occhio. –

1

Espandere la risposta eccellente di Martijn Pieters con un'opzione aggiuntiva a causa dell'imprecisione intrinseca con i galleggianti più complessi. Ad esempio:

>>> f = 0.8857097 
>>> f.as_integer_ratio() 
(1994440937439217, 2251799813685248)   # mathematically wrong 
>>> Fraction(f) 
Fraction(1994440937439217, 2251799813685248) # same result but in a class 
>>> Fraction(f).limit_denominator() 
Fraction(871913, 984423)      # still imprecise 

Il risultato desiderato è stato matematico 8857097/10000000 che può essere realizzato per fusione in una stringa e poi manipolarlo.

A cura di risposta

ho trovato un modo molto più semplice per risolvere il problema precisione.

>>> Fraction(str(f)) 
Fraction(8857097, 10000000) 

Casting da una stringa consente inoltre di precisare le istanze decimali

>>> Decimal(f).as_integer_ratio() 
(1994440937439217, 2251799813685248) 
>>> Decimal(str(f)).as_integer_ratio() 
(8857097, 10000000) 

risposta originale

def float_to_ratio(flt): 
    if int(flt) == flt:  # to prevent 3.0 -> 30/10 
     return int(flt), 1 
    flt_str = str(flt) 
    flt_split = flt_str.split('.') 
    numerator = int(''.join(flt_split)) 
    denominator = 10 ** len(flt_split[1]) 
    return numerator, denominator 

Ora cerchiamo di testarlo:

>>> float_to_ratio(f) 
(8857097, 10000000)  # mathematically correct 

Noterò che questo tipo di precisione della frazione non è ottimizzato e di solito non sarà necessario, ma per completezza è qui. Questa funzione non semplifica la frazione, ma è possibile eseguire un'ulteriore elaborazione per ridurla:

>>> n = 0.5 
>>> float_to_ratio(n) 
(5, 10) 
>>> Fraction(*float_to_ratio(n)) 
Fraction(1, 2)