2010-05-08 15 views
6

C'è un modo per ottenere il ceil di un decimale di alta precisione in python?ottenendo Ceil() di Decimal in python?

>>> import decimal; 
>>> decimal.Decimal(800000000000000000001)/100000000000000000000 
Decimal('8.00000000000000000001') 
>>> math.ceil(decimal.Decimal(800000000000000000001)/100000000000000000000) 
8.0 

matematica arrotonda il valore e restituisce valore non preciso

+0

Sono nuovo di Python, appena iniziato ieri infatti. Mi sono imbattuto in questo problema nel mio secondo programma di pratica (il primo era ovviamente la "stampa" obbligatoria Hello, World! ";"). quindi, sto trovando difficile giudicare la migliore risposta a questo. La soluzione decimale.Context di Matthew Flaschen ha funzionato nel mio caso particolare. Ma mi piacerebbe che gli altri volessero cambiare la soluzione migliore (sarebbe utile anche per i neofiti come me se riesci a spiegare perché un certo approccio funziona meglio) e tornerò ad accettare. – Gunjan

risposta

5
x = decimal.Decimal('8.00000000000000000000001') 
with decimal.localcontext() as ctx: 
    ctx.prec=100000000000000000 
    ctx.rounding=decimal.ROUND_CEILING 
    y = x.to_integral_exact() 
+4

Questo è buono, ma non è necessario modificare la precisione del contesto qui. 'to_integral_exact' accetta anche un argomento' rounding', quindi è possibile evitare del tutto il contesto. –

3

È possibile eseguire questa operazione utilizzando la precisione e l'opzione modalità del costruttore contesto di arrotondamento.

ctx = decimal.Context(prec=1, rounding=decimal.ROUND_CEILING) 
ctx.divide(decimal.Decimal(800000000000000000001), decimal.Decimal(100000000000000000000)) 

EDIT: Si dovrebbe pensare di cambiare la risposta accettata .. Anche se il prec può essere aumentato, se necessario, to_integral_exact è una soluzione più semplice.

+0

perfetto :) --- limite di caratteri di completamento --- – Gunjan

+2

@Gunjan, se è perfetto, perché non accettarlo ?! –

+0

@Alex mi dispiace dover partire prima del timeout di 6 minuti. Grazie per il promemoria – Gunjan

0
>>> decimal.Context(rounding=decimal.ROUND_CEILING).quantize(
... decimal.Decimal(800000000000000000001)/100000000000000000000, 0) 
Decimal('9') 
+0

Si noti che questa soluzione presenta problemi per le istanze 'Decimal' con un valore elevato: ad esempio, se si prova' c.quantize (decimal.Decimal ('1e100'), 1) 'con il proprio contesto' c', si otterrà un Eccezione 'InvalidOperation'. –

0
def decimal_ceil(x): 
    int_x = int(x) 
    if x - int_x == 0: 
     return int_x 
    return int_x + 1 
18

Il modo più diretto per prendere il soffitto di un'istanza decimale x è quello di utilizzare x.to_integral_exact(rounding=ROUND_CEILING). Non c'è bisogno di pasticciare con il contesto qui. Si noti che questo imposta i flag Inexact e Rounded laddove appropriato; se non vuoi che le bandiere vengano toccate, usa invece x.to_integral_value(rounding=ROUND_CEILING). Esempio:

>>> from decimal import Decimal, ROUND_CEILING 
>>> x = Decimal('-123.456') 
>>> x.to_integral_exact(rounding=ROUND_CEILING) 
Decimal('-123') 

differenza della maggior parte dei metodi decimali, i to_integral_exact e to_integral_value metodi non sono influenzati dalla precisione del contesto attuale, in modo da non dover preoccuparsi di cambiare la precisione:

>>> from decimal import getcontext 
>>> getcontext().prec = 2 
>>> x.to_integral_exact(rounding=ROUND_CEILING) 
Decimal('-123') 

A proposito, in Python 3.x, math.ceil funziona esattamente come si desidera, tranne che restituisce un'istanza int anziché un'istanza Decimal. Funziona perché math.ceil è sovraccarico per i tipi personalizzati in Python 3. In Python 2,converte semplicemente l'istanza Decimal in un float per prima, potenzialmente perdendo le informazioni nel processo, così puoi finire con risultati errati.

+0

Solo per completezza: in python 2.x 'matematica.ceil' non funziona come previsto: converte prima i decimali in virgola mobile. A causa di ciò 'int (ceil (D ('1.0000000000000001')))' restituisce 1 in python 2.xe in 2 in python 3.x –

+0

@AntonyHatchkins: Grazie, buon punto. Ho modificato questa informazione nella risposta. –

0

Basta usare la potenza per farlo. importazione matematica

def lo_ceil(num, potency=0): # Use 0 for multiples of 1, 1 for multiples of 10, 2 for 100 ... 
     n = num/(10.0 ** potency) 
     c = math.ceil(n) 
     return c * (10.0 ** potency) 

lo_ceil(8.0000001, 1) # return 10