2010-05-08 25 views
6

¿Hay alguna forma de obtener el límite máximo de un decimal de alta precisión en python?obteniendo Ceil() de Decimal en python?

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

matemáticas redondea el valor y devuelve valor no precisa

+0

Soy nuevo en python, recién empecé ayer. Tropecé con este problema en mi segundo programa de práctica (el primero era, por supuesto, el obligatorio "imprimir" Hello, World! '; "). entonces, me resulta difícil juzgar la mejor respuesta a esto. La solución decimal.Context de Matthew Flaschen funcionó en mi caso particular. Pero me gustaría que los demás voten mejor que la mejor solución (también sería útil para los novatos como yo si puedes explicar por qué un cierto enfoque funciona mejor) y volveré y acepto. – Gunjan

Respuesta

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

Esto es bueno, pero no es necesario cambiar la precisión del contexto aquí. 'to_integral_exact' también toma un argumento de 'redondeo', por lo que puede evitar jugar con el contexto por completo. –

3

Usted puede hacer esto utilizando la precisión y la opción del modo del constructor Contexto redondeo.

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

EDIT: Usted debe considerar el cambio de la respuesta aceptada .. Aunque el prec se puede aumentar según sea necesario, to_integral_exact es una solución más simple.

+0

perfecto :) --- completar el límite de caracteres --- – Gunjan

+2

@Gunjan, si es perfecto, ¿por qué no aceptarlo? –

+0

@Alex lo siento, tuve que irme antes de 6 minutos de tiempo de espera. Gracias por el recordatorio – Gunjan

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

Tenga en cuenta que esta solución tiene problemas para las instancias 'Decimal' con gran valor: por ejemplo, si intenta' c.quantize (decimal.Decimal ('1e100'), 1) 'con su contexto' c', obtendrá un Excepción 'InvalidOperation'. –

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

La forma más directa para tomar el techo de una instancia decimal x es utilizar x.to_integral_exact(rounding=ROUND_CEILING). No hay necesidad de meterse con el contexto aquí. Tenga en cuenta que esto establece los indicadores Inexact y Rounded donde corresponda; si no quiere que se toquen las banderas, use x.to_integral_value(rounding=ROUND_CEILING) en su lugar. Ejemplo:

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

A diferencia de la mayoría de los métodos de decimales, los métodos y to_integral_exactto_integral_value no se ven afectados por la precisión del contexto actual, por lo que no tiene que preocuparse de cambiar la precisión:

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

Por cierto, en Python 3.x, math.ceil funciona exactamente como lo desea, excepto que devuelve una instancia de int en lugar de Decimal. Eso funciona porque math.ceil es sobrecargable para tipos personalizados en Python 3. En Python 2, math.ceil simplemente convierte la instancia Decimal en un float primero, lo que podría perder información en el proceso, por lo que puede terminar con resultados incorrectos.

+0

Solo para completar: en Python 2.x 'math.ceil' no funciona como se esperaba: primero convierte decimal a float. Debido a que 'int (ceil (D ('1.0000000000000001')))' evalúa a 1 en python 2.xy a 2 en python 3.x –

+0

@AntonyHatchkins: Gracias, buen punto. He editado esa información en la respuesta. –

0

Simplemente use la potencia para hacer esto. importa matemática

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