Le frazioni con precisione decimale
-
19-09-2019 - |
Domanda
C'è un'implementazione pitone puro fractions.Fraction
che supporta long
s come numeratore e denominatore? Purtroppo, l'elevamento a potenza sembra essere codificato in per restituire un float (ACK !!!), che dovrebbe almeno il supporto utilizzando decimal.Decimal
.
Se non c'è, suppongo che posso probabilmente fare una copia della biblioteca e provare a sostituire le occorrenze di float()
con qualcosa di appropriato da Decimal
ma preferirei qualcosa che è stato testato da altri prima.
Ecco un esempio di codice:
base = Fraction.from_decimal(Decimal(1).exp())
a = Fraction(69885L, 53L)
x = Fraction(9L, 10L)
print base**(-a*x), type(base**(-a*x))
risultati in 0.0 <type 'float'>
in cui la risposta dovrebbe essere davvero un piccolo decimale.
Aggiorna : ho ottenuto il seguente work-around per ora (assumendo, per un ** B, che entrambi sono frazioni, naturalmente, avrò bisogno di un'altra funzione quando exp_ è un galleggiante o è essa stessa un decimale):
def fracpow(base, exp_):
base = Decimal(base.numerator)/Decimal(base.denominator)
exp_ = Decimal(exp_.numerator)/Decimal(exp_.denominator)
return base**exp_
che dà la risposta 4.08569925773896097019795484811E-516.
Sarei ancora interessato se c'è un modo migliore di fare questo senza le funzioni supplementari (sto cercando di indovinare se lavoro con la classe Fraction
abbastanza, troverò altri carri che lavorano la loro strada nei miei risultati).
Soluzione
"Alza ad una potenza" non è un'operazione chiusa sopra razionali (diversamente dai soliti quattro operazioni aritmetiche): non c'è un numero razionale r
tale che r == 2 ** 0.5
. La leggenda narra che Pitagora (da cui il teorema questo fatto segue in modo così semplice) ha avuto il suo discepolo Ippaso ucciso per l'orrendo crimine di provare questo; Sembra che simpatizzare wit presunta reazione di Pitagora ;-), dato l'utilizzo di strano 'dovrebbe'.
frazioni di Python sono destinate ad essere esatti, quindi inevitabilmente ci sono casi in cui sollevare una frazione della potenza di un'altra frazione sarà assolutamente non per tornare una frazione come risultato; e "dovrebbe" semplicemente non può essere ragionevolmente applicata ad un'impossibilità matematica.
Quindi la cosa migliore che puoi fare è quello di approssimativa il risultato desiderato, per esempio ottenendo un risultato che non è una frazione esatta (galleggianti sono generalmente considerati sufficienti per lo scopo) e poi ravvicinare ulteriormente indietro con una frazione. La maggior parte delle attuali implementazioni puro-Python (ci sono molti file rationals.py
trovato intorno alla rete ;-) preferiscono non implementare un operatore **
a tutti, ma ovviamente non c'è nulla ti impedisce di prendere una decisione in design diverso la propria implementazione -!)
Altri suggerimenti
È possibile scrivere la propria funzione "pow" per frazioni che non utilizzano in virgola mobile elevamento a potenza. E 'questo che stai cercando di fare?
Questo solleverà una frazione di una potenza intera con ricadere a galleggiare.
def pow( fract, exp ):
if exp == 0:
return fract
elif exp % 2 == 0:
t = pow( fract, exp//2 )
return t*t
else:
return fract*pos( fract, exp-1 )