decimal
— Aritmética decimal de coma fija y coma flotante¶
Código fuente: Lib/decimal.py
The decimal
module provides support for fast correctly rounded
decimal floating point arithmetic. It offers several advantages over the
float
datatype:
Decimal «se basa en un modelo de coma flotante que se diseñó pensando en las personas, y necesariamente tiene un principio rector supremo: las computadoras deben proporcionar una aritmética que funcione de la misma manera que la aritmética que las personas aprenden en la escuela.» – extracto (traducido) de la especificación de la aritmética decimal.
Decimal numbers can be represented exactly. In contrast, numbers like
1.1
and2.2
do not have exact representations in binary floating point. End users typically would not expect1.1 + 2.2
to display as3.3000000000000003
as it does with binary floating point.The exactness carries over into arithmetic. In decimal floating point,
0.1 + 0.1 + 0.1 - 0.3
is exactly equal to zero. In binary floating point, the result is5.5511151231257827e-017
. While near to zero, the differences prevent reliable equality testing and differences can accumulate. For this reason, decimal is preferred in accounting applications which have strict equality invariants.The decimal module incorporates a notion of significant places so that
1.30 + 1.20
is2.50
. The trailing zero is kept to indicate significance. This is the customary presentation for monetary applications. For multiplication, the «schoolbook» approach uses all the figures in the multiplicands. For instance,1.3 * 1.2
gives1.56
while1.30 * 1.20
gives1.5600
.A diferencia del punto flotante binario basado en hardware, el módulo decimal tiene una precisión modificable por el usuario (por defecto es de 28 dígitos decimales) que puede ser tan grande como sea necesario para un problema dado:
>>> from decimal import * >>> getcontext().prec = 6 >>> Decimal(1) / Decimal(7) Decimal('0.142857') >>> getcontext().prec = 28 >>> Decimal(1) / Decimal(7) Decimal('0.1428571428571428571428571429')
Tanto la representación en coma flotante binaria como la decimal se implementan de acuerdo a estándares publicados. Mientras que el tipo float expone solo una pequeña parte de sus capacidades, el módulo decimal expone todos los componentes requeridos del estándar. Cuando es necesario, el desarrollador tiene control total sobre el redondeo y la gestión de las señales. Esto incluye la capacidad de forzar la aritmética exacta, utilizando excepciones para bloquear cualquier operación inexacta.
El módulo decimal fue diseñado para admitir «indiscriminadamente, tanto aritmética decimal exacta sin redondeo (a veces llamada aritmética de coma fija) como la aritmética de coma flotante con redondeo.» – extracto (traducido) de la especificación de la aritmética decimal.
El módulo está diseñado en torno a tres conceptos: el número decimal, el contexto aritmético y las señales.
A decimal number is immutable. It has a sign, coefficient digits, and an
exponent. To preserve significance, the coefficient digits do not truncate
trailing zeros. Decimals also include special values such as
Infinity
, -Infinity
, and NaN
. The standard also
differentiates -0
from +0
.
El contexto aritmético es un entorno que permite especificar una precisión, reglas de redondeo, límites en los exponentes, flags que indican el resultado de las operaciones y habilitadores de trampas que especifican si las señales (reportadas durante operaciones ilegales) son tratadas o no como excepciones de Python. Las opciones de redondeo incluyen ROUND_CEILING
, ROUND_DOWN
, ROUND_FLOOR
, ROUND_HALF_DOWN
, ROUND_HALF_EVEN
, ROUND_HALF_UP
, ROUND_UP
y ROUND_05UP
.
Las señales son grupos de condiciones excepcionales que ocurren durante el cálculo. Dependiendo de las necesidades de la aplicación, las señales pueden ignorarse, tratarse como información o tratarse como excepciones. Las señales existentes en el módulo decimal son Clamped
, InvalidOperation
, DivisionByZero
, Inexact
, Rounded
, Subnormal
, Overflow
, Underflow
y FloatOperation
.
Por cada señal hay un flag y un habilitador de trampa. Cuando ocurre una operación ilegal, su flag se establece en uno, luego, si su habilitador de trampa está establecido en uno, se lanza una excepción. La configuración de los flags es persistente, por lo que el usuario debe restablecerlos antes de comenzar un cálculo que desee monitorear.
Ver también
IBM’s General Decimal Arithmetic Specification, The General Decimal Arithmetic Specification.
Tutorial de inicio rápido¶
El punto de partida habitual para usar decimales es importar el módulo, ver el contexto actual con getcontext()
y, si es necesario, establecer nuevos valores para la precisión, el redondeo o trampas de señales habilitadas:
>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
InvalidOperation])
>>> getcontext().prec = 7 # Set a new precision
Decimal instances can be constructed from integers, strings, floats, or tuples.
Construction from an integer or a float performs an exact conversion of the
value of that integer or float. Decimal numbers include special values such as
NaN
which stands for «Not a number», positive and negative
Infinity
, and -0
:
>>> getcontext().prec = 28
>>> Decimal(10)
Decimal('10')
>>> Decimal('3.14')
Decimal('3.14')
>>> Decimal(3.14)
Decimal('3.140000000000000124344978758017532527446746826171875')
>>> Decimal((0, (3, 1, 4), -2))
Decimal('3.14')
>>> Decimal(str(2.0 ** 0.5))
Decimal('1.4142135623730951')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.414213562373095048801688724')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')
Si la señal FloatOperation
es atrapada, la mezcla accidental de decimales y flotantes en constructores o comparaciones de orden lanzará una excepción:
>>> c = getcontext()
>>> c.traps[FloatOperation] = True
>>> Decimal(3.14)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') < 3.7
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') == 3.5
True
Nuevo en la versión 3.3.
La significación de un nuevo objeto Decimal es determinada únicamente por el número de dígitos ingresados. La precisión y el redondeo establecidos en el contexto solo entran en juego durante las operaciones aritméticas.
>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')
Se lanza una excepción InvalidOperation
si durante la construcción de un objeto Decimal se exceden los límites internos de la versión de C:
>>> Decimal("1e9999999999999999999")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
Distinto en la versión 3.3.
Los objetos Decimal interactúan bien con gran parte del resto de Python. Aquí hay un pequeño circo volador de punto flotante decimal:
>>> data = list(map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split()))
>>> max(data)
Decimal('9.25')
>>> min(data)
Decimal('0.03')
>>> sorted(data)
[Decimal('0.03'), Decimal('1.00'), Decimal('1.34'), Decimal('1.87'),
Decimal('2.35'), Decimal('3.45'), Decimal('9.25')]
>>> sum(data)
Decimal('19.29')
>>> a,b,c = data[:3]
>>> str(a)
'1.34'
>>> float(a)
1.34
>>> round(a, 1)
Decimal('1.3')
>>> int(a)
1
>>> a * 5
Decimal('6.70')
>>> a * b
Decimal('2.5058')
>>> c % a
Decimal('0.77')
Y algunas funciones matemáticas también están disponibles para Decimal:
>>> getcontext().prec = 28
>>> Decimal(2).sqrt()
Decimal('1.414213562373095048801688724')
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal('10').ln()
Decimal('2.302585092994045684017991455')
>>> Decimal('10').log10()
Decimal('1')
The quantize()
method rounds a number to a fixed exponent. This method is
useful for monetary applications that often round results to a fixed number of
places:
>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN)
Decimal('7.32')
>>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP)
Decimal('8')
Como se muestra arriba, la función getcontext()
accede al contexto actual y permite cambiar la configuración. Este enfoque satisface las necesidades de la mayoría de las aplicaciones.
Para trabajos más avanzados, puede resultar útil crear contextos alternativos utilizando el constructor Context(). Para activar un contexto alternativo, usa la función setcontext()
.
De acuerdo con el estándar, el módulo decimal
proporciona dos contextos estándar listos para usar, BasicContext
y ExtendedContext
. El primero es particularmente útil para la depuración, ya que muchas de las trampas de señales están habilitadas por defecto:
>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)
>>> setcontext(myothercontext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857142857142857142857142857')
>>> ExtendedContext
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[])
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857143')
>>> Decimal(42) / Decimal(0)
Decimal('Infinity')
>>> setcontext(BasicContext)
>>> Decimal(42) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#143>", line 1, in -toplevel-
Decimal(42) / Decimal(0)
DivisionByZero: x / 0
Contexts also have signal flags for monitoring exceptional conditions
encountered during computations. The flags remain set until explicitly cleared,
so it is best to clear the flags before each set of monitored computations by
using the clear_flags()
method.
>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])
The flags entry shows that the rational approximation to pi was rounded (digits beyond the context precision were thrown away) and that the result is inexact (some of the discarded digits were non-zero).
Individual traps are set using the dictionary in the traps
attribute of a context:
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(0)
Decimal('Infinity')
>>> getcontext().traps[DivisionByZero] = 1
>>> Decimal(1) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#112>", line 1, in -toplevel-
Decimal(1) / Decimal(0)
DivisionByZero: x / 0
La mayoría de los programas ajustan el contexto actual una sola vez, al comienzo del programa. Y, en muchas aplicaciones, los datos se convierten a Decimal
mediante una única conversión dentro de un bucle. Con el contexto establecido y los decimales creados, la mayor parte del programa manipula los datos de la misma forma que con otros tipos numéricos de Python.
Objetos Decimal¶
-
class
decimal.
Decimal
(value='0', context=None)¶ Construye un nuevo objeto
Decimal
basado en value.value puede ser un entero, una cadena de caracteres, una tupla, un
float
u otro objetoDecimal
. Si no se proporciona value, retornaDecimal('0')
. Si value es una cadena, debe ajustarse a la sintaxis de cadena numérica decimal después de que los espacios en blanco iniciales y finales, así como los guiones bajos, sean eliminados:sign ::= '+' | '-' digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' indicator ::= 'e' | 'E' digits ::= digit [digit]... decimal-part ::= digits '.' [digits] | ['.'] digits exponent-part ::= indicator [sign] digits infinity ::= 'Infinity' | 'Inf' nan ::= 'NaN' [digits] | 'sNaN' [digits] numeric-value ::= decimal-part [exponent-part] | infinity numeric-string ::= [sign] numeric-value | [sign] nan
También se permiten otros dígitos decimales Unicode en aquellos lugares en los que arriba aparece
digit
. Estos incluyen dígitos decimales de otros alfabetos (por ejemplo, dígitos del alfabeto árabe-índico y devanāgarī) junto con los dígitos de ancho completo desde'\uff10'
a'\uff19'
.If value is a
tuple
, it should have three components, a sign (0
for positive or1
for negative), atuple
of digits, and an integer exponent. For example,Decimal((0, (1, 4, 1, 4), -3))
returnsDecimal('1.414')
.Si value es un
float
, el valor binario de coma flotante se convierte sin pérdidas a su equivalente decimal exacto. Esta conversión a menudo puede requerir 53 o más dígitos de precisión. Por ejemplo,Decimal(float('1.1'))
se convierte enDecimal('1.100000000000000088817841970012523233890533447265625')
.La precisión de context no afecta a la cantidad de dígitos almacenados. Eso está determinado exclusivamente por el número de dígitos en value. Por ejemplo,
Decimal('3.00000')
registra los cinco ceros incluso si la precisión del contexto es solo tres.The purpose of the context argument is determining what to do if value is a malformed string. If the context traps
InvalidOperation
, an exception is raised; otherwise, the constructor returns a new Decimal with the value ofNaN
.Una vez construidos, los objetos
Decimal
son inmutables.Distinto en la versión 3.2: Ahora se permite que el argumento del constructor sea una instancia
float
.Distinto en la versión 3.3: Los argumentos
float
ahora generan una excepción si se establece la trampaFloatOperation
. Por defecto, la trampa está desactivada.Distinto en la versión 3.6: Se permiten guiones bajos para la agrupación, como ocurre en el código con los literales enteros y de punto flotante.
Los objetos de coma flotante decimal comparten muchas propiedades con los otros tipos numéricos integrados, como
float
eint
. Se aplican todas las operaciones matemáticas habituales y los métodos especiales. Asimismo, los objetos decimales se pueden copiar, serializar con pickle, imprimir, usar como claves de un diccionario o como elementos de un conjunto, comparar, ordenar y convertir a otros tipos (comofloat
oint
).Hay algunas pequeñas diferencias entre la aritmética en objetos decimales y la aritmética en enteros y flotantes. Cuando el operador de resto
%
se aplica a objetos Decimal, el signo del resultado es el signo del dividendo en lugar del signo del divisor:>>> (-7) % 4 1 >>> Decimal(-7) % Decimal(4) Decimal('-3')
El operador de división entera
//
se comporta de manera análoga, retornando la parte entera del cociente verdadero (truncando hacia cero) en lugar del resultado de aplicarle la función suelo. Esto se hace con la finalidad de preservar la identidad habitualx == (x // y) * y + x % y
:>>> -7 // 4 -2 >>> Decimal(-7) // Decimal(4) Decimal('-1')
Los operadores
%
y//
implementan las operacionesremainder
ydivide-integer
(respectivamente) como se describe en la especificación.Los objetos de la clase Decimal generalmente no se pueden combinar con flotantes o instancias de
fractions.Fraction
en operaciones aritméticas: un intento de agregar un objetoDecimal
a unfloat
, por ejemplo, lanzará una excepciónTypeError
. Sin embargo, es posible usar los operadores de comparación de Python para comparar una instancia deDecimal
x
con otro númeroy
. Esto evita resultados confusos al hacer comparaciones de igualdad entre números de diferentes tipos.Distinto en la versión 3.2: Las comparaciones de tipo mixto entre instancias de
Decimal
y otros tipos numéricos ahora son totalmente compatibles.Además de las propiedades numéricas estándar, los objetos de coma flotante decimal también tienen varios métodos especializados:
-
adjusted
()¶ Retorna el exponente ajustado después de desplazar los dígitos del extremo derecho del coeficiente hasta que solo quede el dígito principal:
Decimal('321e+5').adjusted()
retorna siete. Se utiliza para determinar la posición del dígito más significativo con respecto al punto decimal.
-
as_integer_ratio
()¶ Retorna un par de enteros
(n, d)
que representan la instancia deDecimal
proporcionada como una fracción irreducible y con un denominador positivo:>>> Decimal('-3.14').as_integer_ratio() (-157, 50)
La conversión es exacta. Lanza una excepción OverflowError si se proporcionan valores infinitos y ValueError con valores NaN.
Nuevo en la versión 3.6.
-
as_tuple
()¶ Retorna una representación en forma de named tuple del número:
DecimalTuple(sign, digits, exponent)
.
-
canonical
()¶ Retorna la codificación canónica del argumento. Actualmente, la codificación de una instancia de
Decimal
es siempre canónica, por lo que esta operación retorna su argumento sin cambios.
-
compare
(other, context=None)¶ Compara los valores de dos instancias de Decimal. El método
compare()
retorna una instancia de Decimal, y si alguno de los operandos es un NaN, el resultado es un NaN:a or b is a NaN ==> Decimal('NaN') a < b ==> Decimal('-1') a == b ==> Decimal('0') a > b ==> Decimal('1')
-
compare_signal
(other, context=None)¶ Esta operación es idéntica al método
compare()
, excepto que todos los valores NaN generan una señal. Es decir, si ninguno de los operandos es un NaN señalizador, cualquier operando de NaN silencioso se trata como si fuera un NaN señalizador.
-
compare_total
(other, context=None)¶ Compara dos operandos utilizando su representación abstracta en lugar de su valor numérico. Similar al método
compare()
, pero el resultado proporciona un ordenamiento total en las instancias deDecimal
. Dos instancias deDecimal
con el mismo valor numérico, pero diferentes representaciones, se comparan como desiguales usando este orden:>>> Decimal('12.0').compare_total(Decimal('12')) Decimal('-1')
Los NaN silenciosos y señalizadores también se incluyen en el ordenamiento total. El resultado de esta función es
Decimal('0')
si ambos operandos tienen la misma representación,Decimal('-1')
si el primer operando es menor en el orden total que el segundo yDecimal('1')
si el primer operando es mayor en el orden total que el segundo operando. Consulta las especificaciones para obtener detalles sobre el ordenamiento total.Esta operación no se ve afectada por el contexto y es silenciosa: no se cambian los flags y no se realiza ningún redondeo. Como excepción, la versión de C puede lanzar InvalidOperation si el segundo operando no se puede convertir exactamente.
-
compare_total_mag
(other, context=None)¶ Compara dos operandos usando su representación abstracta en lugar de su valor, como en
compare_total()
, pero ignorando el signo de cada operando.x.compare_total_mag(y)
es equivalente ax.copy_abs().compare_total(y.copy_abs())
.Esta operación no se ve afectada por el contexto y es silenciosa: no se cambian los flags y no se realiza ningún redondeo. Como excepción, la versión de C puede lanzar InvalidOperation si el segundo operando no se puede convertir exactamente.
-
conjugate
()¶ Simplemente retorna self (el propio objeto al que pertenece el método invocado). Este método existe solo para cumplir con la Especificación decimal.
-
copy_abs
()¶ Retorna el valor absoluto del argumento. Esta operación no se ve afectada por el contexto y es silenciosa: no se modifican los flags y no se realiza ningún redondeo.
-
copy_negate
()¶ Retorna la negación del argumento. Esta operación no se ve afectada por el contexto y es silenciosa: no se cambian los flags y no se realiza ningún redondeo.
-
copy_sign
(other, context=None)¶ Retorna una copia del primer operando pero con el signo establecido para que sea el mismo que el del segundo operando. Por ejemplo:
>>> Decimal('2.3').copy_sign(Decimal('-1.5')) Decimal('-2.3')
Esta operación no se ve afectada por el contexto y es silenciosa: no se cambian los flags y no se realiza ningún redondeo. Como excepción, la versión de C puede lanzar InvalidOperation si el segundo operando no se puede convertir exactamente.
-
exp
(context=None)¶ Retorna el valor de la función exponencial (natural)
e**x
en el número dado. El resultado es correctamente redondeado utilizando el modo de redondeoROUND_HALF_EVEN
.>>> Decimal(1).exp() Decimal('2.718281828459045235360287471') >>> Decimal(321).exp() Decimal('2.561702493119680037517373933E+139')
-
classmethod
from_float
(f)¶ Alternative constructor that only accepts instances of
float
orint
.Note
Decimal.from_float(0.1)
is not the same asDecimal('0.1')
. Since 0.1 is not exactly representable in binary floating point, the value is stored as the nearest representable value which is0x1.999999999999ap-4
. That equivalent value in decimal is0.1000000000000000055511151231257827021181583404541015625
.Nota
Desde Python 3.2 en adelante, una instancia de
Decimal
también se puede construir directamente desde una instancia defloat
.>>> Decimal.from_float(0.1) Decimal('0.1000000000000000055511151231257827021181583404541015625') >>> Decimal.from_float(float('nan')) Decimal('NaN') >>> Decimal.from_float(float('inf')) Decimal('Infinity') >>> Decimal.from_float(float('-inf')) Decimal('-Infinity')
Nuevo en la versión 3.1.
-
fma
(other, third, context=None)¶ Fusión de la multiplicación y la suma. Retorna self*other+third sin redondeo del producto intermedio self*other.
>>> Decimal(2).fma(3, 5) Decimal('11')
-
is_canonical
()¶ Retorna
True
si el argumento es canónico yFalse
en caso contrario. Actualmente, una instancia deDecimal
es siempre canónica, por lo que esta operación siempre retornaTrue
.
-
is_finite
()¶ Retorna
True
si el argumento es un número finito yFalse
si el argumento es un valor infinito o un NaN.
-
is_infinite
()¶ Retorna
True
si el argumento es un valor infinito positivo o negativo yFalse
en caso contrario.
-
is_nan
()¶ Retorna
True
si el argumento es un NaN (silencioso o señalizador) yFalse
en caso contrario.
-
is_normal
(context=None)¶ Retorna
True
si el argumento es un número finito normal. RetornaFalse
si el argumento es cero, subnormal, infinito o un NaN.
-
is_signed
()¶ Retorna
True
si el argumento tiene signo negativo yFalse
en caso contrario. Ten en cuenta que tanto los ceros como los NaN pueden tener signo.
-
ln
(context=None)¶ Retorna el logaritmo natural (base e) del operando. El resultado es correctamente redondeado utilizando el modo de redondeo
ROUND_HALF_EVEN
.
-
log10
(context=None)¶ Retorna el logaritmo en base diez del operando. El resultado es correctamente redondeado utilizando el modo de redondeo
ROUND_HALF_EVEN
.
-
logb
(context=None)¶ Para un número distinto de cero, retorna el exponente ajustado de su operando como una instancia de
Decimal
. Si el operando es cero, se retornaDecimal('-Infinity')
y se activa el flagDivisionByZero
. Si el operando es infinito, se retornaDecimal('Infinity')
.
-
logical_and
(other, context=None)¶ logic_and()
es una operación lógica que toma dos operandos lógicos (consultar Operandos lógicos). El resultado es eland
dígito por dígito de los dos operandos.
-
logical_invert
(context=None)¶ logic_invert()
es una operación lógica. El resultado es la inversión dígito a dígito del operando.
-
logical_or
(other, context=None)¶ logical_or()
es una operación lógica que toma dos operandos lógicos (consultar Operandos lógicos). El resultado es unor
dígito a dígito de los dos operandos.
-
logical_xor
(other, context=None)¶ logic_xor()
es una operación lógica que toma dos operandos lógicos (consultar Operandos lógicos). El resultado es la disyunción exclusiva («exclusive or») dígito a dígito de ambos operandos.
-
max
(other, context=None)¶ Like
max(self, other)
except that the context rounding rule is applied before returning and thatNaN
values are either signaled or ignored (depending on the context and whether they are signaling or quiet).
-
max_mag
(other, context=None)¶ Similar al método
max()
, pero la comparación se realiza utilizando los valores absolutos de los operandos.
-
min
(other, context=None)¶ Like
min(self, other)
except that the context rounding rule is applied before returning and thatNaN
values are either signaled or ignored (depending on the context and whether they are signaling or quiet).
-
min_mag
(other, context=None)¶ Similar al método
min()
, pero la comparación se realiza utilizando los valores absolutos de los operandos.
-
next_minus
(context=None)¶ Retorna el número más grande representable en el contexto proporcionado (o en el contexto del hilo actual si no se proporciona un contexto) que sea más pequeño que el operando proporcionado.
-
next_plus
(context=None)¶ Retorna el número más pequeño representable en el contexto proporcionado (o en el contexto del hilo actual si no se proporciona ningún contexto) que sea más grande que el operando proporcionado.
-
next_toward
(other, context=None)¶ Si los dos operandos no son iguales, retorna el número más cercano al primer operando en la dirección del segundo operando. Si ambos operandos son numéricamente iguales, retorna una copia del primer operando con el signo establecido para que sea el mismo que el signo del segundo operando.
-
normalize
(context=None)¶ Normalize the number by stripping the rightmost trailing zeros and converting any result equal to
Decimal('0')
toDecimal('0e0')
. Used for producing canonical values for attributes of an equivalence class. For example,Decimal('32.100')
andDecimal('0.321000e+2')
both normalize to the equivalent valueDecimal('32.1')
.
-
number_class
(context=None)¶ Retorna una cadena de caracteres que describe la class del operando. El valor retornado es una de las siguientes diez cadenas de caracteres.
"-Infinity"
, que indica que el operando es un infinito negativo."-Normal"
, que indica que el operando es un número normal negativo."-Subnormal"
, que indica que el operando es negativo y subnormal."-Zero"
, que indica que el operando es un cero negativo."+Zero"
, que indica que el operando es un cero positivo."+Subnormal"
,que indica que el operando es positivo y subnormal."+Normal"
, que indica que el operando es un número normal positivo."+Infinity"
, que indica que el operando es un infinito positivo."NaN"
, que indica que el operando es un NaN (no es un número) silencioso."sNaN"
, que indica que el operando es un NaN (no es un número) señalizador.
-
quantize
(exp, rounding=None, context=None)¶ Retorna un valor igual al primer operando después de ser redondeado y de asignarle el exponente del segundo operando.
>>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414')
A diferencia de otras operaciones, se genera una señal
InvalidOperation
si la longitud del coeficiente después de la operación quantize es mayor que la precisión. Esto garantiza que, a menos que exista una condición de error, el exponente cuantificado sea siempre igual al del operando de la derecha.Además, a diferencia de otras operaciones, quantize nunca genera una señal Underflow, incluso si el resultado es subnormal e inexacto.
Si el exponente del segundo operando es mayor que el del primero, puede ser necesario redondear. En este caso, el modo de redondeo está determinado por el argumento
rounding
, si se proporciona, o por el argumentocontext
en caso contrario. Si no se proporciona ninguno de estos dos argumentos, se utiliza el modo de redondeo establecido en el contexto del hilo actual.An error is returned whenever the resulting exponent is greater than
Emax
or less thanEtiny()
.
-
radix
()¶ Retorna
Decimal(10)
, que es la raíz (base) en la que la claseDecimal
hace toda su aritmética. Este método está incluido solo por compatibilidad con la especificación.
-
remainder_near
(other, context=None)¶ Retorna el resto de dividir self entre other. Esto difiere de la operación
self%other
, en la que el signo del resto se elige para minimizar su valor absoluto. Más precisamente, el valor de retorno esself - n * other
, donden
es el número entero más cercano al valor exacto deself / other
. Si dos enteros están igualmente cerca, entonces el valor par es el elegido.Si el resultado es cero, entonces su signo será el signo de self.
>>> Decimal(18).remainder_near(Decimal(10)) Decimal('-2') >>> Decimal(25).remainder_near(Decimal(10)) Decimal('5') >>> Decimal(35).remainder_near(Decimal(10)) Decimal('-5')
-
rotate
(other, context=None)¶ Retorna el resultado de rotar los dígitos del primer operando en una cantidad especificada por el segundo operando. El segundo operando debe ser un número entero en el rango comprendido desde -precisión hasta precisión. El valor absoluto del segundo operando da el número de lugares a rotar. Si el segundo operando es positivo, la rotación es hacia la izquierda; de lo contrario, la rotación es hacia la derecha. El coeficiente del primer operando se rellena con ceros a la izquierda para satisfacer la precisión de longitud si es necesario. El signo y el exponente del primer operando no se modifican.
-
same_quantum
(other, context=None)¶ Test whether self and other have the same exponent or whether both are
NaN
.Esta operación no se ve afectada por el contexto y es silenciosa: no se cambian los flags y no se realiza ningún redondeo. Como excepción, la versión de C puede lanzar InvalidOperation si el segundo operando no se puede convertir exactamente.
-
scaleb
(other, context=None)¶ Retorna el primer operando con su exponente ajustado por el segundo. De manera equivalente, retorna el primer operando multiplicado por
10**other
. El segundo operando debe ser un número entero.
-
shift
(other, context=None)¶ Retorna el resultado de cambiar los dígitos del primer operando en una cantidad especificada por el segundo operando. El segundo operando debe ser un número entero en el rango comprendido desde -precisión hasta precisión. El valor absoluto del segundo operando da el número de lugares a desplazar. Si el segundo operando es positivo, el desplazamiento es hacia la izquierda; de lo contrario, el desplazamiento es hacia la derecha. Los dígitos desplazados en el coeficiente son ceros. El signo y el exponente del primer operando no se modifican.
-
sqrt
(context=None)¶ Retorna la raíz cuadrada del argumento con precisión total.
-
to_eng_string
(context=None)¶ Convierte a una cadena de caracteres, usando notación de ingeniería si se necesita un exponente.
La notación de ingeniería tiene como exponente un múltiplo de 3. Esto puede dejar hasta 3 dígitos a la izquierda del punto decimal y puede requerir la adición de uno o dos ceros finales.
Por ejemplo, este método convierte
Decimal('123E+1')
enDecimal('1.23E+3')
.
-
to_integral
(rounding=None, context=None)¶ Idéntico al método
to_integral_value()
. El nombreto_integral
se ha mantenido por compatibilidad con versiones anteriores.
-
to_integral_exact
(rounding=None, context=None)¶ Redondea al entero más cercano, generando la señal
Inexact
oRounded
, según corresponda, si se produce un redondeo. El modo de redondeo está determinado por el parámetrorounding
si es proporcionado, o por el establecido en elcontext
proporcionado en caso contrario. Si no se proporciona ninguno de estos dos parámetros, se utiliza el modo de redondeo establecido en el contexto actual.
-
to_integral_value
(rounding=None, context=None)¶ Redondea al entero más cercano sin generar la señal
Inexact
oRounded
. Si se proporciona, se aplica el método de redondeo especificado por rounding; en caso contrario, se utiliza el método de redondeo del context proporcionado o el del contexto actual.
-
Operandos lógicos¶
The logical_and()
, logical_invert()
, logical_or()
,
and logical_xor()
methods expect their arguments to be logical
operands. A logical operand is a Decimal
instance whose
exponent and sign are both zero, and whose digits are all either
0
or 1
.
Objetos Context¶
Los contextos son entornos para operaciones aritméticas. Gobiernan la precisión, establecen reglas para el redondeo, determinan qué señales se tratan como excepciones y limitan el rango para los exponentes.
Cada hilo tiene su propio contexto actual, al que se accede o se reemplaza usando las funciones getcontext()
y setcontext()
respectivamente:
-
decimal.
getcontext
()¶ Retorna el contexto actual del hilo activo.
-
decimal.
setcontext
(c)¶ Establece c como contexto actual para el hilo activo.
También puedes usar la declaración with
y la función localcontext()
para cambiar temporalmente el contexto activo.
-
decimal.
localcontext
(ctx=None)¶ Retorna un gestor de contexto que establecerá el contexto actual para el hilo activo en una copia de ctx al ingresar en la declaración with y restaurará el contexto anterior al salir de la misma. Si no se especifica ningún contexto, se utiliza una copia del contexto actual.
Por ejemplo, el siguiente código establece la precisión decimal actual en 42 lugares, realiza un cálculo y luego restaura automáticamente el contexto anterior:
from decimal import localcontext with localcontext() as ctx: ctx.prec = 42 # Perform a high precision calculation s = calculate_something() s = +s # Round the final result back to the default precision
También se pueden crear nuevos contextos utilizando el constructor de la clase Context
que se describe a continuación. Además, el módulo proporciona tres contextos prediseñados:
-
class
decimal.
BasicContext
¶ Este es un contexto estándar definido por la Especificación general de la aritmética decimal. La precisión se establece en nueve. El redondeo se establece en
ROUND_HALF_UP
. Se restablecen todos los flags. Todas las trampas están habilitadas (las señales son tratadas como excepciones) exceptoInexact
,Rounded
ySubnormal
.Debido a que la mayoría de las trampas están habilitadas, este contexto es especialmente útil para la depuración.
-
class
decimal.
ExtendedContext
¶ Este es un contexto estándar definido por la Especificación general de la aritmética decimal. La precisión se establece en nueve. El redondeo se establece en
ROUND_HALF_EVEN
. Se restablecen todos los flags. No se habilitan trampas (para que no se generen excepciones durante los cálculos).Because the traps are disabled, this context is useful for applications that prefer to have result value of
NaN
orInfinity
instead of raising exceptions. This allows an application to complete a run in the presence of conditions that would otherwise halt the program.
-
class
decimal.
DefaultContext
¶ Este contexto es utilizado por el constructor de la clase
Context
como un prototipo para nuevos contextos. Cambiar un campo (como la precisión) tiene el efecto de cambiar el valor predeterminado para los nuevos contextos creados por el constructor deContext
.Este contexto es más útil en entornos con múltiples hilos. Cambiar uno de los campos antes de que se inicien los hilos tiene el efecto de establecer valores predeterminados en todo el sistema. No se recomienda cambiar los campos después de que se hayan iniciado los hilos, ya que requeriría el uso de mecanismos de sincronización para evitar condiciones de carrera entre los hilos.
En entornos de un solo hilo, es preferible no utilizar este contexto en absoluto. En su lugar, simplemente crea contextos explícitamente como se describe a continuación.
The default values are
Context.prec
=28
,Context.rounding
=ROUND_HALF_EVEN
, and enabled traps forOverflow
,InvalidOperation
, andDivisionByZero
.
Además de los tres contextos proporcionados, se pueden crear nuevos contextos mediante el constructor de la clase Context
.
-
class
decimal.
Context
(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)¶ Crea un nuevo contexto. Si no se especifica un campo, o es
None
, los valores predeterminados se copian deDefaultContext
. Si el campo flags no está especificado, o esNone
, se restablecen todas los flags.prec is an integer in the range [
1
,MAX_PREC
] that sets the precision for arithmetic operations in the context.La opción rounding es una de las constantes enumeradas en la sección Rounding Modes.
Los campos traps y flags enumeran las señales que se deben establecer. Generalmente, los nuevos contextos solo deben establecer trampas y dejar los flags sin establecer.
The Emin and Emax fields are integers specifying the outer limits allowable for exponents. Emin must be in the range [
MIN_EMIN
,0
], Emax in the range [0
,MAX_EMAX
].The capitals field is either
0
or1
(the default). If set to1
, exponents are printed with a capitalE
; otherwise, a lowercasee
is used:Decimal('6.02e+23')
.The clamp field is either
0
(the default) or1
. If set to1
, the exponente
of aDecimal
instance representable in this context is strictly limited to the rangeEmin - prec + 1 <= e <= Emax - prec + 1
. If clamp is0
then a weaker condition holds: the adjusted exponent of theDecimal
instance is at mostEmax
. When clamp is1
, a large normal number will, where possible, have its exponent reduced and a corresponding number of zeros added to its coefficient, in order to fit the exponent constraints; this preserves the value of the number but loses information about significant trailing zeros. For example:>>> Context(prec=6, Emax=999, clamp=1).create_decimal('1.23e999') Decimal('1.23000E+999')
A clamp value of
1
allows compatibility with the fixed-width decimal interchange formats specified in IEEE 754.The
Context
class defines several general purpose methods as well as a large number of methods for doing arithmetic directly in a given context. In addition, for each of theDecimal
methods described above (with the exception of theadjusted()
andas_tuple()
methods) there is a correspondingContext
method. For example, for aContext
instanceC
andDecimal
instancex
,C.exp(x)
is equivalent tox.exp(context=C)
. EachContext
method accepts a Python integer (an instance ofint
) anywhere that a Decimal instance is accepted.-
clear_flags
()¶ Resets all of the flags to
0
.
-
clear_traps
()¶ Resets all of the traps to
0
.Nuevo en la versión 3.3.
-
copy
()¶ Retorna un duplicado del contexto.
-
copy_decimal
(num)¶ Retorna una copia de la instancia de Decimal num.
-
create_decimal
(num)¶ Crea una nueva instancia de Decimal a partir de num pero usando self como contexto. A diferencia del constructor de
Decimal
, la precisión del contexto, el método de redondeo, los flags y las trampas se aplican a la conversión.Esto es útil porque las constantes a menudo se proporcionan con una precisión mayor que la que necesita la aplicación. Otro beneficio es que el redondeo elimina inmediatamente los efectos no deseados de los dígitos más allá de la precisión actual. En el siguiente ejemplo, usar entradas no redondeadas significa que agregar cero a una suma puede cambiar el resultado:
>>> getcontext().prec = 3 >>> Decimal('3.4445') + Decimal('1.0023') Decimal('4.45') >>> Decimal('3.4445') + Decimal(0) + Decimal('1.0023') Decimal('4.44')
Este método implementa la operación to-number de la especificación de IBM. Si el argumento es una cadena de caracteres, no se permiten espacios en blanco ni guiones bajos, ni al principio ni al final.
-
create_decimal_from_float
(f)¶ Crea una nueva instancia de Decimal a partir de un flotante f, pero redondeando usando self como contexto. A diferencia del método de clase
Decimal.from_float()
, la precisión del contexto, el método de redondeo, los flags y las trampas se aplican a la conversión.>>> context = Context(prec=5, rounding=ROUND_DOWN) >>> context.create_decimal_from_float(math.pi) Decimal('3.1415') >>> context = Context(prec=5, traps=[Inexact]) >>> context.create_decimal_from_float(math.pi) Traceback (most recent call last): ... decimal.Inexact: None
Nuevo en la versión 3.1.
-
Etiny
()¶ Retorna un valor igual a
Emin - prec + 1
que es el valor mínimo del exponente para resultados subnormales. Cuando ocurre un desbordamiento numérico negativo («underflow»), el exponente se establece enEtiny
.
-
Etop
()¶ Retorna un valor igual a
Emax - prec + 1
.
El enfoque habitual para trabajar con decimales es crear instancias de la clase
Decimal
y luego aplicar operaciones aritméticas que tienen lugar dentro del contexto actual para el hilo activo. Un enfoque alternativo es utilizar métodos de contexto para calcular dentro de un contexto específico. Los métodos son similares a los de la claseDecimal
y aquí solo se relatan brevemente.-
abs
(x)¶ Retorna el valor absoluto de x.
-
add
(x, y)¶ Retorna la suma de x e y.
-
canonical
(x)¶ Retorna el mismo objeto Decimal x.
-
compare
(x, y)¶ Compara x e y numéricamente.
-
compare_signal
(x, y)¶ Compara los valores de los dos operandos numéricamente.
-
compare_total
(x, y)¶ Compara los dos operandos utilizando su representación abstracta.
-
compare_total_mag
(x, y)¶ Compara los dos operandos utilizando su representación abstracta, ignorando el signo.
-
copy_abs
(x)¶ Retorna una copia de x con el signo establecido en 0.
-
copy_negate
(x)¶ Retorna una copia de x con el signo invertido.
-
copy_sign
(x, y)¶ Copia el signo de y en x.
-
divide
(x, y)¶ Retorna x dividido entre y.
-
divide_int
(x, y)¶ Retorna x dividido entre y, truncando el resultado a un número entero.
-
divmod
(x, y)¶ Divide dos números y retorna la parte entera del resultado.
-
exp
(x)¶ Returns
e ** x
.
-
fma
(x, y, z)¶ Retorna x multiplicado por y, más z.
-
is_canonical
(x)¶ Retorna
True
si x está en forma canónica, en caso contrario retornaFalse
.
-
is_finite
(x)¶ Retorna
True
si x es un valor finito, en caso contrario retornaFalse
.
-
is_infinite
(x)¶ Retorna
True
si x es un valor infinito, en caso contrario retornaFalse
.
-
is_nan
(x)¶ Retorna
True
si x es un valor qNaN o sNaN , en caso contrario retornaFalse
.
-
is_normal
(x)¶ Retorna
True
si x es un número normal, en caso contrario retornaFalse
.
-
is_qnan
(x)¶ Retorna
True
si x es un NaN silencioso, en caso contrario retornaFalse
.
-
is_signed
(x)¶ Retorna
True
si x es un valor negativo, en caso contrario retornaFalse
.
-
is_snan
(x)¶ Retorna
True
si x es un NaN señalizador, en caso contrario retornaFalse
.
-
is_subnormal
(x)¶ Retorna
True
si x es un número subnormal, en caso contrario retornaFalse
.
-
is_zero
(x)¶ Retorna
True
si x es un cero, en caso contrario retornaFalse
.
-
ln
(x)¶ Retorna el logaritmo natural (base e) de x.
-
log10
(x)¶ Retorna el logaritmo en base 10 de x.
-
logb
(x)¶ Retorna el exponente de la magnitud del MSD («dígito más significativo») del operando.
-
logical_and
(x, y)¶ Aplica la operación lógica and entre los dígitos de cada operando.
-
logical_invert
(x)¶ Invierte todos los dígitos en x.
-
logical_or
(x, y)¶ Aplica la operación lógica or entre los dígitos de cada operando.
-
logical_xor
(x, y)¶ Aplica la operación lógica xor entre los dígitos de cada operando.
-
max
(x, y)¶ Compara dos valores numéricamente y retorna el mayor de ellos.
-
max_mag
(x, y)¶ Compara los valores numéricamente ignorando sus signos.
-
min
(x, y)¶ Compara dos valores numéricamente y retorna el menor de ellos.
-
min_mag
(x, y)¶ Compara los valores numéricamente ignorando sus signos.
-
minus
(x)¶ Se corresponde con el operador unario de resta (prefijo) de Python.
-
multiply
(x, y)¶ Retorna el producto de x por y.
-
next_minus
(x)¶ Retorna el número más grande representable menor que x.
-
next_plus
(x)¶ Retorna el número más pequeño representable mayor que x.
-
next_toward
(x, y)¶ Retorna el número más cercano a x, en la dirección de y.
-
normalize
(x)¶ Reduce x a su forma más simple.
-
number_class
(x)¶ Retorna una cadena de caracteres indicando la clase de x.
-
plus
(x)¶ Se corresponde con el operador unario de suma (prefijo) de Python. Esta operación aplica la precisión y el redondeo establecidos en el contexto, por lo que no es una operación de identidad.
-
power
(x, y, modulo=None)¶ Retorna
x
elevado a la potenciay
, reconduciendo al módulomodulo
si se proporciona.With two arguments, compute
x**y
. Ifx
is negative theny
must be integral. The result will be inexact unlessy
is integral and the result is finite and can be expressed exactly in “precision” digits. The rounding mode of the context is used. Results are always correctly rounded in the Python version.Decimal(0) ** Decimal(0)
da como resultadoInvalidOperation
, y siInvalidOperation
no es atrapada, entonces da como resultadoDecimal('NaN')
.Distinto en la versión 3.3: The C module computes
power()
in terms of the correctly roundedexp()
andln()
functions. The result is well-defined but only «almost always correctly rounded».Con tres argumentos, calcula
(x**y) % modulo
. Para la forma de tres argumentos, se mantienen las siguientes restricciones sobre los argumentos:los tres argumentos deben ser enteros
y
debe ser un valor no negativoal menos uno,
x
oy
, no debe ser ceromodulo
no debe ser cero y tener como mínimo los dígitos de la “precisión”
El valor resultante de
Context.power(x, y, modulo)
es igual al valor que se obtendría calculando(x**y) % modulo
con precisión ilimitada, la diferencia es que se calcula de manera más eficiente . El exponente del resultado es cero, independientemente de los exponentes dex
,y
ymodulo
. El resultado siempre es exacto.
-
quantize
(x, y)¶ Retorna un valor igual a x (redondeado), pero que tiene el exponente de y.
-
radix
()¶ Simplemente retorna 10, ya que es Decimal, :)
-
remainder
(x, y)¶ Retorna el resto de la división entera.
El signo del resultado, si no es cero, es el mismo que el del dividendo original.
-
remainder_near
(x, y)¶ Retorna
x - y * n
, donde n es el número entero más cercano al valor exacto dex / y
(si el resultado es 0, entonces su signo será el signo de x).
-
rotate
(x, y)¶ Retorna una copia de x rotada y veces.
-
same_quantum
(x, y)¶ Retorna
True
si los dos operandos tienen el mismo exponente.
-
scaleb
(x, y)¶ Retorna el primer operando después de agregar el segundo valor a su exponente.
-
shift
(x, y)¶ Retorna una copia de x desplazada y veces.
-
sqrt
(x)¶ Retorna la raíz cuadrada de un número no negativo para la precisión del contexto.
-
subtract
(x, y)¶ Retorna la diferencia entre x e y.
-
to_eng_string
(x)¶ Convierte a una cadena de caracteres, usando notación de ingeniería si se necesita un exponente.
La notación de ingeniería tiene como exponente un múltiplo de 3. Esto puede dejar hasta 3 dígitos a la izquierda del punto decimal y puede requerir la adición de uno o dos ceros finales.
-
to_integral_exact
(x)¶ Redondea a un entero.
-
to_sci_string
(x)¶ Convierte un número en una cadena de caracteres usando notación científica.
-
Constantes¶
Las constantes detalladas en esta sección solo son relevantes para el módulo de C. Se incluyen también en la versión pura de Python por compatibilidad.
32-bit |
64-bit |
|
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
-
decimal.
HAVE_THREADS
¶ El valor es
True
. Está obsoleta, debido ha que Python ahora siempre tiene soporte para hilos.
Obsoleto desde la versión 3.9.
-
decimal.
HAVE_CONTEXTVAR
¶ El valor predeterminado es
True
. Si Python seconfigura usando --without-decimal-contextvar
, la versión de C usa un contexto de hilos-locales en lugar de un contexto de corrutinas-locales y el valor de la constante esFalse
. Esto es algo más rápido en algunos escenarios de contexto anidado.
Nuevo en la versión 3.9: retro-portado a las versiones 3.7 y 3.8.
Modos de redondeo¶
-
decimal.
ROUND_CEILING
¶ Round towards
Infinity
.
-
decimal.
ROUND_DOWN
¶ Redondear hacia cero.
-
decimal.
ROUND_FLOOR
¶ Round towards
-Infinity
.
-
decimal.
ROUND_HALF_DOWN
¶ Redondear al valor contiguo más cercano, con empates hacia cero.
-
decimal.
ROUND_HALF_EVEN
¶ Redondear al valor contiguo más cercano, con empates al entero par contiguo.
-
decimal.
ROUND_HALF_UP
¶ Redondear al valor contiguo más cercano, con empates alejándose de cero.
-
decimal.
ROUND_UP
¶ Redondear alejándose de cero.
-
decimal.
ROUND_05UP
¶ Si el último dígito después de redondear hacia cero es 0 ó 5, redondear alejándose de cero, en caso contrario, redondear hacia cero.
Señales¶
Las señales representan condiciones que surgen durante el cálculo. Cada una se corresponde con un solo flag de contexto y un habilitador de trampas de contexto.
El flag de contexto se establece siempre que se encuentra la condición. Después del cálculo, los flags pueden comprobarse con fines informativos (por ejemplo, para determinar si un cálculo fue exacto). Después de verificar los flags, asegúrate de borrarlos antes de comenzar con el siguiente cálculo.
Si el habilitador de trampas del contexto está configurado para la señal, entonces la condición hace que se lance una excepción de Python. Por ejemplo, si se establece la trampa DivisionByZero
, se genera una excepción DivisionByZero
al encontrar la condición.
-
class
decimal.
Clamped
¶ Cambia un exponente para ajustar las restricciones de representación.
Typically, clamping occurs when an exponent falls outside the context’s
Emin
andEmax
limits. If possible, the exponent is reduced to fit by adding zeros to the coefficient.
-
class
decimal.
DecimalException
¶ Clase base para otras señales. Es una subclase de
ArithmeticError
.
-
class
decimal.
DivisionByZero
¶ Señala la división de un número no infinito entre cero.
Can occur with division, modulo division, or when raising a number to a negative power. If this signal is not trapped, returns
Infinity
or-Infinity
with the sign determined by the inputs to the calculation.
-
class
decimal.
Inexact
¶ Indica que se produjo un redondeo y el resultado no es exacto.
Señala que se descartaron dígitos distintos de cero durante el redondeo. Se retorna el resultado redondeado. El flag o la trampa de señal se utiliza para detectar cuando los resultados son inexactos.
-
class
decimal.
InvalidOperation
¶ Señala que se realizó una operación no válida.
Indicates that an operation was requested that does not make sense. If not trapped, returns
NaN
. Possible causes include:Infinity - Infinity 0 * Infinity Infinity / Infinity x % 0 Infinity % x sqrt(-x) and x > 0 0 ** 0 x ** (non-integer) x ** Infinity
-
class
decimal.
Overflow
¶ Desbordamiento numérico.
Indicates the exponent is larger than
Context.Emax
after rounding has occurred. If not trapped, the result depends on the rounding mode, either pulling inward to the largest representable finite number or rounding outward toInfinity
. In either case,Inexact
andRounded
are also signaled.
-
class
decimal.
Rounded
¶ Se produjo un redondeo, aunque posiblemente no hubo pérdida de información.
Signaled whenever rounding discards digits; even if those digits are zero (such as rounding
5.00
to5.0
). If not trapped, returns the result unchanged. This signal is used to detect loss of significant digits.
-
class
decimal.
Subnormal
¶ Exponent was lower than
Emin
prior to rounding.Ocurre cuando el resultado de una operación es subnormal (el exponente es demasiado pequeño). Si no está atrapada, se retorna el resultado sin cambios.
-
class
decimal.
Underflow
¶ Desbordamiento numérico negativo con resultado redondeado a cero.
Ocurre cuando un resultado subnormal se lleva a cero mediante redondeo.
Inexact
ySubnormal
también se señalan.
-
class
decimal.
FloatOperation
¶ Habilita una semántica más estricta para mezclar flotantes y objetos Decimal.
Si la señal no está atrapada (predeterminado), se permite mezclar flotantes y objetos Decimal en el constructor de
Decimal
, en el métodocreate_decimal()
y en todos los operadores de comparación. Tanto la conversión como las comparaciones son exactas. Cualquier ocurrencia de una operación mixta se registra silenciosamente estableciendoFloatOperation
a los flags del contexto. Las conversiones explícitas usandofrom_float()
ocreate_decimal_from_float()
no establecen el flag.En caso contrario (la señal está atrapada), solo las comparaciones de igualdad y las conversiones explícitas permanecen silenciadas. Todas las demás operaciones mixtas lanzan una excepción
FloatOperation
.
La siguiente tabla resume la jerarquía de señales:
exceptions.ArithmeticError(exceptions.Exception)
DecimalException
Clamped
DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
Inexact
Overflow(Inexact, Rounded)
Underflow(Inexact, Rounded, Subnormal)
InvalidOperation
Rounded
Subnormal
FloatOperation(DecimalException, exceptions.TypeError)
Notas sobre la representación en coma flotante¶
Mitigación del error de redondeo usando mayor precisión¶
The use of decimal floating point eliminates decimal representation error
(making it possible to represent 0.1
exactly); however, some operations
can still incur round-off error when non-zero digits exceed the fixed precision.
Los efectos del error de redondeo pueden amplificarse mediante la suma o resta de cantidades casi compensadas, lo que da como resultado una pérdida de significación. Knuth proporciona dos ejemplos instructivos en los que la aritmética de coma flotante redondeada con precisión insuficiente provoca la ruptura de las propiedades asociativas y distributivas de la suma:
# Examples from Seminumerical Algorithms, Section 4.2.2.
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 8
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.5111111')
>>> u + (v + w)
Decimal('10')
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.01')
>>> u * (v+w)
Decimal('0.0060000')
El módulo decimal
permite restaurar las identidades ampliando la precisión lo suficiente para evitar la pérdida de significación:
>>> getcontext().prec = 20
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.51111111')
>>> u + (v + w)
Decimal('9.51111111')
>>>
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.0060000')
>>> u * (v+w)
Decimal('0.0060000')
Valores especiales¶
The number system for the decimal
module provides special values
including NaN
, sNaN
, -Infinity
, Infinity
,
and two zeros, +0
and -0
.
Los infinitos se pueden construir directamente con Decimal('Infinity')
. Además, pueden surgir al dividir entre cero cuando la señal DivisionByZero
no es interceptada. Asimismo, cuando la señal Overflow
no es interceptada, un infinito puede resultar del redondeo más allá de los límites del mayor número representable.
Los infinitos tienen signo (afín) y se pueden usar en operaciones aritméticas donde se tratan como números muy grandes e indeterminados. Por ejemplo, adicionar una constante a infinito resulta en otro infinito.
Some operations are indeterminate and return NaN
, or if the
InvalidOperation
signal is trapped, raise an exception. For example,
0/0
returns NaN
which means «not a number». This variety of
NaN
is quiet and, once created, will flow through other computations
always resulting in another NaN
. This behavior can be useful for a
series of computations that occasionally have missing inputs — it allows the
calculation to proceed while flagging specific results as invalid.
A variant is sNaN
which signals rather than remaining quiet after every
operation. This is a useful return value when an invalid result needs to
interrupt a calculation for special handling.
The behavior of Python’s comparison operators can be a little surprising where a
NaN
is involved. A test for equality where one of the operands is a
quiet or signaling NaN
always returns False
(even when doing
Decimal('NaN')==Decimal('NaN')
), while a test for inequality always returns
True
. An attempt to compare two Decimals using any of the <
,
<=
, >
or >=
operators will raise the InvalidOperation
signal
if either operand is a NaN
, and return False
if this signal is
not trapped. Note that the General Decimal Arithmetic specification does not
specify the behavior of direct comparisons; these rules for comparisons
involving a NaN
were taken from the IEEE 854 standard (see Table 3 in
section 5.7). To ensure strict standards-compliance, use the compare()
and compare_signal()
methods instead.
Los ceros con signo pueden resultar de cálculos que desbordan la precisión establecida. Mantienen el signo que habría resultado si el cálculo se hubiera realizado con mayor precisión. Dado que su magnitud es cero, los ceros positivos y negativos se tratan como iguales y su signo es solo informativo.
Además de los dos ceros con signo, que son distintos pero iguales, hay varias representaciones del cero con diferente precisión pero equivalentes en valor. Esto requiere de algo de tiempo para acostumbrarse. Para un ojo habituado a las representaciones normalizadas de coma flotante, no es inmediatamente obvio que el siguiente cálculo retorne un valor igual a cero:
>>> 1 / Decimal('Infinity')
Decimal('0E-1000026')
Trabajando con hilos¶
La función getcontext()
accede a un objeto Context
diferente para cada hilo. Tener contextos de hilo separados significa que los hilos pueden realizar cambios (como getcontext().prec=10
) sin interferir con otros hilos.
Asimismo, la función setcontext()
asigna automáticamente su objetivo al hilo actual.
Si setcontext()
no ha sido invocada antes de getcontext()
, entonces getcontext()
creará automáticamente un nuevo contexto para usar en el hilo actual.
El nuevo contexto es copiado a partir de un contexto prototipo llamado DefaultContext. Modifica directamente el objeto DefaultContext para controlar los valores predeterminados, de modo que cada hilo utilice los mismos valores en toda la aplicación. Esto debe hacerse antes de que se inicien los hilos, para evitar que tenga lugar una condición de carrera entre los mismos al invocar a getcontext()
. Por ejemplo:
# Set applicationwide defaults for all threads about to be launched
DefaultContext.prec = 12
DefaultContext.rounding = ROUND_DOWN
DefaultContext.traps = ExtendedContext.traps.copy()
DefaultContext.traps[InvalidOperation] = 1
setcontext(DefaultContext)
# Afterwards, the threads can be started
t1.start()
t2.start()
t3.start()
. . .
Casos prácticos¶
A continuación hay algunos casos prácticos que sirven como funciones de utilidad y que muestran formas de trabajar con la clase Decimal
:
def moneyfmt(value, places=2, curr='', sep=',', dp='.',
pos='', neg='-', trailneg=''):
"""Convert Decimal to a money formatted string.
places: required number of places after the decimal point
curr: optional currency symbol before the sign (may be blank)
sep: optional grouping separator (comma, period, space, or blank)
dp: decimal point indicator (comma or period)
only specify as blank when places is zero
pos: optional sign for positive numbers: '+', space or blank
neg: optional sign for negative numbers: '-', '(', space or blank
trailneg:optional trailing minus indicator: '-', ')', space or blank
>>> d = Decimal('-1234567.8901')
>>> moneyfmt(d, curr='$')
'-$1,234,567.89'
>>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')
'1.234.568-'
>>> moneyfmt(d, curr='$', neg='(', trailneg=')')
'($1,234,567.89)'
>>> moneyfmt(Decimal(123456789), sep=' ')
'123 456 789.00'
>>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')
'<0.02>'
"""
q = Decimal(10) ** -places # 2 places --> '0.01'
sign, digits, exp = value.quantize(q).as_tuple()
result = []
digits = list(map(str, digits))
build, next = result.append, digits.pop
if sign:
build(trailneg)
for i in range(places):
build(next() if digits else '0')
if places:
build(dp)
if not digits:
build('0')
i = 0
while digits:
build(next())
i += 1
if i == 3 and digits:
i = 0
build(sep)
build(curr)
build(neg if sign else pos)
return ''.join(reversed(result))
def pi():
"""Compute Pi to the current precision.
>>> print(pi())
3.141592653589793238462643383
"""
getcontext().prec += 2 # extra digits for intermediate steps
three = Decimal(3) # substitute "three=3.0" for regular floats
lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
while s != lasts:
lasts = s
n, na = n+na, na+8
d, da = d+da, da+32
t = (t * n) / d
s += t
getcontext().prec -= 2
return +s # unary plus applies the new precision
def exp(x):
"""Return e raised to the power of x. Result type matches input type.
>>> print(exp(Decimal(1)))
2.718281828459045235360287471
>>> print(exp(Decimal(2)))
7.389056098930650227230427461
>>> print(exp(2.0))
7.38905609893
>>> print(exp(2+0j))
(7.38905609893+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num = 0, 0, 1, 1, 1
while s != lasts:
lasts = s
i += 1
fact *= i
num *= x
s += num / fact
getcontext().prec -= 2
return +s
def cos(x):
"""Return the cosine of x as measured in radians.
The Taylor series approximation works best for a small value of x.
For larger values, first compute x = x % (2 * pi).
>>> print(cos(Decimal('0.5')))
0.8775825618903727161162815826
>>> print(cos(0.5))
0.87758256189
>>> print(cos(0.5+0j))
(0.87758256189+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
def sin(x):
"""Return the sine of x as measured in radians.
The Taylor series approximation works best for a small value of x.
For larger values, first compute x = x % (2 * pi).
>>> print(sin(Decimal('0.5')))
0.4794255386042030002732879352
>>> print(sin(0.5))
0.479425538604
>>> print(sin(0.5+0j))
(0.479425538604+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
Preguntas frecuentes sobre Decimal¶
P. Es engorroso escribir decimal.Decimal('1234.5')
. ¿Hay alguna forma de minimizar la escritura cuando se usa el intérprete interactivo?
R. Algunos usuarios abrevian el constructor a una sola letra:
>>> D = decimal.Decimal
>>> D('1.23') + D('3.45')
Decimal('4.68')
P. En una aplicación de coma fija con dos decimales, algunas entradas tienen muchos dígitos decimales y deben redondearse. En cambio, otras no tienen dígitos en exceso y deben ser validadas. ¿Qué métodos deben utilizarse?
A. The quantize()
method rounds to a fixed number of decimal places. If
the Inexact
trap is set, it is also useful for validation:
>>> TWOPLACES = Decimal(10) ** -2 # same as Decimal('0.01')
>>> # Round to two places
>>> Decimal('3.214').quantize(TWOPLACES)
Decimal('3.21')
>>> # Validate that a number does not exceed two places
>>> Decimal('3.21').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Decimal('3.21')
>>> Decimal('3.214').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Traceback (most recent call last):
...
Inexact: None
P. Si tengo entradas validadas con dos dígitos decimales, ¿cómo mantengo eso invariante en una aplicación?
A. Some operations like addition, subtraction, and multiplication by an integer
will automatically preserve fixed point. Others operations, like division and
non-integer multiplication, will change the number of decimal places and need to
be followed-up with a quantize()
step:
>>> a = Decimal('102.72') # Initial fixed-point values
>>> b = Decimal('3.17')
>>> a + b # Addition preserves fixed-point
Decimal('105.89')
>>> a - b
Decimal('99.55')
>>> a * 42 # So does integer multiplication
Decimal('4314.24')
>>> (a * b).quantize(TWOPLACES) # Must quantize non-integer multiplication
Decimal('325.62')
>>> (b / a).quantize(TWOPLACES) # And quantize division
Decimal('0.03')
In developing fixed-point applications, it is convenient to define functions
to handle the quantize()
step:
>>> def mul(x, y, fp=TWOPLACES):
... return (x * y).quantize(fp)
>>> def div(x, y, fp=TWOPLACES):
... return (x / y).quantize(fp)
>>> mul(a, b) # Automatically preserve fixed-point
Decimal('325.62')
>>> div(b, a)
Decimal('0.03')
Q. There are many ways to express the same value. The numbers 200
,
200.000
, 2E2
, and .02E+4
all have the same value at
various precisions. Is there a way to transform them to a single recognizable
canonical value?
A. The normalize()
method maps all equivalent values to a single
representative:
>>> values = map(Decimal, '200 200.000 2E2 .02E+4'.split())
>>> [v.normalize() for v in values]
[Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')]
P. Algunos valores decimales siempre se imprimen usando notación exponencial. ¿Hay alguna forma de obtener una representación no exponencial?
A. For some values, exponential notation is the only way to express the number
of significant places in the coefficient. For example, expressing
5.0E+3
as 5000
keeps the value constant but cannot show the
original’s two-place significance.
Si una aplicación no necesita preocuparse por el seguimiento de significación, es fácil eliminar el exponente y los ceros finales, perdiendo significación, pero manteniendo el valor sin cambios:
>>> def remove_exponent(d):
... return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')
P. ¿Hay alguna forma de convertir un flotante regular en un Decimal
?
R. Sí, cualquier número de coma flotante binario se puede expresar exactamente mediante un Decimal, aunque una conversión exacta puede requerir más precisión de la que sugiere la intuición:
>>> Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')
P. Dentro de un cálculo complejo, cómo puedo asegurarme de que no he obtenido un resultado adulterado debido a una precisión insuficiente o anomalías de redondeo.
R. El módulo decimal facilita la comprobación de resultados. Una buena práctica es volver a ejecutar los cálculos con mayor precisión y con varios modos de redondeo. La obtención de resultados muy dispares indica una precisión insuficiente, problemas relacionados con el modo de redondeo, entradas mal acondicionadas o un algoritmo numéricamente inestable.
P. Noté que la precisión del contexto se aplica a los resultados de las operaciones pero no a las entradas. ¿Hay algo a tener en cuenta al mezclar valores con distintas precisiones?
R. Sí. El principio es que todos los valores se consideran exactos y también lo es la aritmética de esos valores. Solo se redondean los resultados. La ventaja para las entradas es que «lo que escribes es lo que obtienes». Una desventaja es que los resultados pueden parecer extraños si olvidas que las entradas no se han redondeado:
>>> getcontext().prec = 3
>>> Decimal('3.104') + Decimal('2.104')
Decimal('5.21')
>>> Decimal('3.104') + Decimal('0.000') + Decimal('2.104')
Decimal('5.20')
La solución es aumentar la precisión o forzar el redondeo de las entradas utilizando la operación unaria más:
>>> getcontext().prec = 3
>>> +Decimal('1.23456789') # unary plus triggers rounding
Decimal('1.23')
Alternativamente, las entradas se pueden redondear en el momento que se crean usando el método Context.create_decimal()
:
>>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678')
Decimal('1.2345')
P. ¿La implementación de CPython es rápida para números grandes?
A. Yes. In the CPython and PyPy3 implementations, the C/CFFI versions of
the decimal module integrate the high speed libmpdec library for
arbitrary precision correctly rounded decimal floating point arithmetic 1.
libmpdec
uses Karatsuba multiplication
for medium-sized numbers and the Number Theoretic Transform
for very large numbers.
The context must be adapted for exact arbitrary precision arithmetic. Emin
and Emax
should always be set to the maximum values, clamp
should always be 0 (the default). Setting prec
requires some care.
The easiest approach for trying out bignum arithmetic is to use the maximum
value for prec
as well 2:
>>> setcontext(Context(prec=MAX_PREC, Emax=MAX_EMAX, Emin=MIN_EMIN))
>>> x = Decimal(2) ** 256
>>> x / 128
Decimal('904625697166532776746648320380374280103671755200316906558262375061821325312')
Para resultados inexactos, MAX_PREC
es demasiado grande en plataformas de 64 bits y la memoria disponible será insuficiente:
>>> Decimal(1) / 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
MemoryError
On systems with overallocation (e.g. Linux), a more sophisticated approach is to
adjust prec
to the amount of available RAM. Suppose that you have 8GB of
RAM and expect 10 simultaneous operands using a maximum of 500MB each:
>>> import sys
>>>
>>> # Maximum number of digits for a single operand using 500MB in 8-byte words
>>> # with 19 digits per word (4-byte and 9 digits for the 32-bit build):
>>> maxdigits = 19 * ((500 * 1024**2) // 8)
>>>
>>> # Check that this works:
>>> c = Context(prec=maxdigits, Emax=MAX_EMAX, Emin=MIN_EMIN)
>>> c.traps[Inexact] = True
>>> setcontext(c)
>>>
>>> # Fill the available precision with nines:
>>> x = Decimal(0).logical_invert() * 9
>>> sys.getsizeof(x)
524288112
>>> x + 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.Inexact: [<class 'decimal.Inexact'>]
En general (y especialmente en sistemas sin sobreasignación), se recomienda estimar límites aún más estrictos y establecer la trampa Inexact
si se espera que todos los cálculos sean exactos.