decimal
— Aritmética de ponto fixo decimal e ponto flutuante¶
Código-fonte: 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 “é baseado em um modelo de ponto flutuante que foi projetado com as pessoas em mente e necessariamente tem um princípio orientador primordial – os computadores devem fornecer uma aritmética que funcione da mesma maneira que a aritmética que as pessoas aprendem na escola”. – trecho da especificação 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
.Diferentemente do ponto flutuante binário baseado em hardware, o módulo decimal possui uma precisão alterável pelo usuário (padrão de 28 casas), que pode ser tão grande quanto necessário para um determinado problema:
>>> from decimal import * >>> getcontext().prec = 6 >>> Decimal(1) / Decimal(7) Decimal('0.142857') >>> getcontext().prec = 28 >>> Decimal(1) / Decimal(7) Decimal('0.1428571428571428571428571429')
O ponto flutuante binário e decimal é implementado em termos de padrões publicados. Enquanto o tipo ponto flutuante embutido expõe apenas uma parte modesta de seus recursos, o módulo decimal expõe todas as partes necessárias do padrão. Quando necessário, o programador tem controle total sobre o arredondamento e o manuseio do sinal. Isso inclui uma opção para impor aritmética exata usando exceções para bloquear quaisquer operações inexatas.
O módulo decimal foi projetado para dar suporte, “sem prejuízo, a aritmética decimal não arredondada exata (às vezes chamada aritmética de ponto fixo) e aritmética arredondada de ponto flutuante”. – trecho da especificação aritmética decimal.
O design do módulo é centrado em torno de três conceitos: o número decimal, o contexto da aritmética e os sinais.
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
.
O contexto da aritmética é um ambiente que especifica precisão, regras de arredondamento, limites de expoentes, sinalizadores indicando os resultados das operações e ativadores de interceptação que determinam se os sinais são tratados como exceções. As opções de arredondamento incluem ROUND_CEILING
, ROUND_DOWN
, ROUND_FLOOR
, ROUND_HALF_DOWN
, ROUND_HALF_EVEN
, ROUND_HALF_UP
, ROUND_UP
e ROUND_05UP
.
Sinais são grupos de condições excepcionais que surgem durante o curso da computação. Dependendo das necessidades do aplicativo, os sinais podem ser ignorados, considerados informativos ou tratados como exceções. Os sinais no módulo decimal são: Clamped
, InvalidOperation
, DivisionByZero
, Inexact
, Rounded
, Subnormal
, Overflow
, Underflow
e FloatOperation
.
Para cada sinal, há um sinalizador e um ativador de interceptação. Quando um sinal é encontrado, seu sinalizador é definido como um e, se o ativador de interceptação estiver definido como um, uma exceção será gerada. Os sinalizadores são fixos; portanto, o usuário precisa redefini-los antes de monitorar um cálculo.
Ver também
IBM’s General Decimal Arithmetic Specification, The General Decimal Arithmetic Specification.
Tutorial de início rápido¶
O início usual do uso de decimais é importar o módulo, exibir o contexto atual com getcontext()
e, se necessário, definir novos valores para precisão, arredondamento ou armadilhas ativados:
>>> 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')
Se o sinal FloatOperation
for capturado na armadilha, a mistura acidental de decimais e pontos flutuantes em construtores ou comparações de ordenação levanta uma exceção:
>>> 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
Novo na versão 3.3.
O significado de um novo decimal é determinado apenas pelo número de dígitos inseridos. A precisão e o arredondamento do contexto só entram em jogo durante operações 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 os limites internos da versão C forem excedidos, a construção de um decimal levanta InvalidOperation
:
>>> Decimal("1e9999999999999999999")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
Alterado na versão 3.3.
Os decimais interagem bem com grande parte do resto do Python. Aqui está um pequeno circo voador de ponto flutuante 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')
E algumas funções matemáticas também estão disponíveis no 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 mostrado acima, a função getcontext()
acessa o contexto atual e permite que as configurações sejam alteradas. Essa abordagem atende às necessidades da maioria das aplicações.
Para trabalhos mais avançados, pode ser útil criar contextos alternativos usando o construtor Context(). Para ativar uma alternativa, use a função setcontext()
.
De acordo com o padrão, o módulo decimal
fornece dois contextos padrão prontos para uso, BasicContext
e ExtendedContext
. O primeiro é especialmente útil para depuração porque muitas das armadilhas estão ativadas:
>>> 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
A maioria dos programas ajusta o contexto atual apenas uma vez, no início do programa. E, em muitas aplicações, os dados são convertidos para Decimal
com uma única conversão dentro de um loop. Com o conjunto de contextos e decimais criados, a maior parte do programa manipula os dados de maneira diferente do que com outros tipos numéricos do Python.
Objetos de Decimal¶
- class decimal.Decimal(value='0', context=None)¶
Constrói um novo objeto de
Decimal
com base em value.value pode ser um inteiro, string, tupla,
float
ou outro objeto deDecimal
. Se nenhum value for fornecido, retornaráDecimal('0')
. Se value for uma string, ele deverá estar em conformidade com a sintaxe da string numérica decimal após caracteres de espaço em branco à esquerda e à direita, bem como sublinhados em toda parte, serem removidos: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
Outros dígitos decimais Unicode também são permitidos onde
digit
aparece acima. Isso inclui dígitos decimais de vários outros alfabetos (por exemplo, dígitos em árabes-índicos e devanágaris), além dos dígitos de largura total'\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')
.Se value é um
float
, o valor do ponto flutuante binário é convertido sem perdas no seu equivalente decimal exato. Essa conversão geralmente requer 53 ou mais dígitos de precisão. Por exemplo,Decimal(float('1.1'))
converte paraDecimal('1.100000000000000088817841970012523233890533447265625')
.A precisão context não afeta quantos dígitos estão armazenados. Isso é determinado exclusivamente pelo número de dígitos em value. Por exemplo,
Decimal('3.00000')
registra todos os cinco zeros, mesmo que a precisão do contexto seja apenas três.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
.Uma vez construídos, objetos de
Decimal
são imutáveis.Alterado na versão 3.2: O argumento para o construtor agora pode ser uma instância de
float
.Alterado na versão 3.3: Os argumentos de
float
levantam uma exceção se a armadilhaFloatOperation
estiver definida. Por padrão, a armadilha está desativada.Alterado na versão 3.6: Sublinhados são permitidos para agrupamento, como nos literais de ponto flutuante e integral no código.
Objetos decimais de ponto flutuante compartilham muitas propriedades com outros tipos numéricos embutidos, como
float
eint
. Todas as operações matemáticas usuais e métodos especiais se aplicam. Da mesma forma, objetos decimais podem ser copiados, separados, impressos, usados como chaves de dicionário, usados como elementos de conjunto, comparados, classificados e coagidos a outro tipo (comofloat
ouint
).Existem algumas pequenas diferenças entre aritmética em objetos decimais e aritmética em números inteiros e flutuantes. Quando o operador de resto
%
é aplicado a objetos decimais, o sinal do resultado é o sinal do dividend em vez do sinal do divisor:>>> (-7) % 4 1 >>> Decimal(-7) % Decimal(4) Decimal('-3')
O operador de divisão inteira
//
se comporta de maneira análoga, retornando a parte inteira do quociente verdadeiro (truncando em direção a zero) em vez de seu resto, de modo a preservar a identidade usualx == (x // y) * y + x % y
:>>> -7 // 4 -2 >>> Decimal(-7) // Decimal(4) Decimal('-1')
Os operadores
%
e//
implementam as operações demódulo
edivisão inteira
(respectivamente) como descrito na especificação.Objetos decimais geralmente não podem ser combinados com pontos flutuantes ou instâncias de
fractions.Fraction
em operações aritméticas: uma tentativa de adicionar umDecimal
a umfloat
, por exemplo, vai levantar umTypeError
. No entanto, é possível usar os operadores de comparação do Python para comparar uma instância deDecimal
x
com outro númeroy
. Isso evita resultados confusos ao fazer comparações de igualdade entre números de tipos diferentes.Alterado na versão 3.2: As comparações de tipos mistos entre instâncias de
Decimal
e outros tipos numéricos agora são totalmente suportadas.Além das propriedades numéricas padrão, os objetos de ponto flutuante decimal também possuem vários métodos especializados:
- adjusted()¶
Retorna o expoente ajustado depois de deslocar os dígitos mais à direita do coeficiente até restar apenas o dígito principal:
Decimal('321e+5').adjusted()
retorna sete. Usado para determinar a posição do dígito mais significativo em relação ao ponto decimal.
- as_integer_ratio()¶
Retorna um par
(n, d)
de números inteiros que representam a instância dadaDecimal
como uma fração, nos termos mais baixos e com um denominador positivo:>>> Decimal('-3.14').as_integer_ratio() (-157, 50)
A conversão é exata. Levanta OverflowError em infinitos e ValueError em NaNs.
Novo na versão 3.6.
- as_tuple()¶
Retorna uma representação de tupla nomeada do número:
DecimalTuple(sign, digits, exponent)
.
- canonical()¶
Retorna a codificação canônica do argumento. Atualmente, a codificação de uma instância de
Decimal
é sempre canônica, portanto, esta operação retorna seu argumento inalterado.
- compare(other, context=None)¶
Compara os valores de duas instâncias decimais.
compare()
retorna uma instância decimal, e se qualquer operando for um NaN, o resultado será um 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 operação é idêntica ao método
compare()
, exceto que todos os NaNs sinalizam. Ou seja, se nenhum operando for um NaN sinalizador, qualquer operando NaN silencioso será tratado como se fosse um NaN sinalizador.
- compare_total(other, context=None)¶
Compara dois operandos usando sua representação abstrata em vez de seu valor numérico. Semelhante ao método
compare()
, mas o resultado fornece uma ordem total nas instâncias deDecimal
. Duas instâncias deDecimal
com o mesmo valor numérico, mas diferentes representações, se comparam desiguais nesta ordem:>>> Decimal('12.0').compare_total(Decimal('12')) Decimal('-1')
Os NaNs silenciosos e sinalizadores também estão incluídos no pedido total. O resultado dessa função é
Decimal('0')
se os dois operandos tiverem a mesma representação,Decimal('-1')
se o primeiro operando for menor na ordem total que o segundo eDecimal('1')
se o primeiro operando for maior na ordem total que o segundo operando. Veja a especificação para detalhes da ordem total.Esta operação não é afetada pelo contexto e é silenciosa: nenhum sinalizador é alterado e nenhum arredondamento é executado. Como uma exceção, a versão C pode levantar InvalidOperation se o segundo operando não puder ser convertido exatamente.
- compare_total_mag(other, context=None)¶
Compara dois operandos usando sua representação abstrata em vez de seu valor, como em
compare_total()
, mas ignorando o sinal de cada operando.x.compare_total_mag(y)
é equivalente ax.copy_abs().compare_total(y.copy_abs())
.Esta operação não é afetada pelo contexto e é silenciosa: nenhum sinalizador é alterado e nenhum arredondamento é executado. Como uma exceção, a versão C pode levantar InvalidOperation se o segundo operando não puder ser convertido exatamente.
- conjugate()¶
Apenas retorna a si próprio, sendo esse método apenas para atender à Especificação de Decimal.
- copy_abs()¶
Retorna o valor absoluto do argumento. Esta operação não é afetada pelo contexto e é silenciosa: nenhum sinalizador é alterado e nenhum arredondamento é executado.
- copy_negate()¶
Retorna a negação do argumento. Esta operação não é afetada pelo contexto e é silenciosa: nenhum sinalizador é alterado e nenhum arredondamento é executado.
- copy_sign(other, context=None)¶
Retorna uma cópia do primeiro operando com o sinal definido para ser o mesmo que o sinal do segundo operando. Por exemplo:
>>> Decimal('2.3').copy_sign(Decimal('-1.5')) Decimal('-2.3')
Esta operação não é afetada pelo contexto e é silenciosa: nenhum sinalizador é alterado e nenhum arredondamento é executado. Como uma exceção, a versão C pode levantar InvalidOperation se o segundo operando não puder ser convertido exatamente.
- exp(context=None)¶
Retorna o valor da função exponencial (natural)
e**x
no número especificado. O resultado é arredondado corretamente usando o modo de arredondamentoROUND_HALF_EVEN
.>>> Decimal(1).exp() Decimal('2.718281828459045235360287471') >>> Decimal(321).exp() Decimal('2.561702493119680037517373933E+139')
- classmethod from_float(f)¶
Construtor alternativo que aceita apenas instâncias de
float
ouint
.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
A partir do Python 3.2 em diante, uma instância de
Decimal
também pode ser construída diretamente a partir de umfloat
.>>> 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')
Novo na versão 3.1.
- fma(other, third, context=None)¶
Multiplicação e adição fundidos. Retorna self*other+third sem arredondamento do produto intermediário self*other.
>>> Decimal(2).fma(3, 5) Decimal('11')
- is_canonical()¶
Retorna
True
se o argumento for canônico eFalse
caso contrário. Atualmente, uma instância deDecimal
é sempre canônica, portanto, esta operação sempre retornaTrue
.
- is_finite()¶
Retorna
True
se o argumento for um número finito eFalse
se o argumento for um infinito ou um NaN.
- is_infinite()¶
Retorna
True
se o argumento for infinito positivo ou negativo eFalse
caso contrário.
- is_normal(context=None)¶
Retorna
True
se o argumento for um número finito normal. RetornaFalse
se o argumento for zero, subnormal, infinito ou NaN.
- is_signed()¶
Retorna
True
se o argumento tiver um sinal negativo eFalse
caso contrário. Observe que zeros e NaNs podem carregar sinais.
- ln(context=None)¶
Retorna o logaritmo (base e) natural do operando. O resultado é arredondado corretamente usando o modo de arredondamento
ROUND_HALF_EVEN
.
- log10(context=None)¶
Retorna o logaritmo da base dez do operando. O resultado é arredondado corretamente usando o modo de arredondamento
ROUND_HALF_EVEN
.
- logb(context=None)¶
Para um número diferente de zero, retorna o expoente ajustado de seu operando como uma instância de
Decimal
. Se o operando é zero,Decimal('-Infinity')
é retornado e o sinalizadorDivisionByZero
é levantado. Se o operando for um infinito,Decimal('Infinity')
será retornado.
- logical_and(other, context=None)¶
logical_and()
é uma operação lógica que leva dois operandos lógicos (consulte Operandos lógicos). O resultado é oand
dígito a dígito dos dois operandos.
- logical_invert(context=None)¶
logical_invert()
é uma operação lógica. O resultado é a inversão dígito a dígito do operando.
- logical_or(other, context=None)¶
logical_or()
é uma operação lógica que leva dois operandos lógicos (consulte Operandos lógicos). O resultado é oor
dígito a dígito dos dois operandos.
- logical_xor(other, context=None)¶
logical_xor()
é uma operação lógica que leva dois operandos lógicos (consulte Operandos lógicos). O resultado é o “ou exclusivo” dígito a dígito ou dos dois 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)¶
Semelhante ao método
max()
, mas a comparação é feita usando os valores absolutos dos 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)¶
Semelhante ao método
min()
, mas a comparação é feita usando os valores absolutos dos operandos.
- next_minus(context=None)¶
Retorna o maior número representável no contexto fornecido (ou no contexto atual da thread, se nenhum contexto for fornecido) que seja menor que o operando especificado.
- next_plus(context=None)¶
Retorna o menor número representável no contexto fornecido (ou no contexto atual da thread, se nenhum contexto for fornecido) que seja maior que o operando fornecido.
- next_toward(other, context=None)¶
Se os dois operandos forem desiguais, retorna o número mais próximo ao primeiro operando na direção do segundo operando. Se os dois operandos forem numericamente iguais, retorna uma cópia do primeiro operando com o sinal configurado para ser o mesmo que o sinal do segundo operando.
- normalize(context=None)¶
Used for producing canonical values of an equivalence class within either the current context or the specified context.
This has the same semantics as the unary plus operation, except that if the final result is finite it is reduced to its simplest form, with all trailing zeros removed and its sign preserved. That is, while the coefficient is non-zero and a multiple of ten the coefficient is divided by ten and the exponent is incremented by 1. Otherwise (the coefficient is zero) the exponent is set to 0. In all cases the sign is unchanged.
For example,
Decimal('32.100')
andDecimal('0.321000e+2')
both normalize to the equivalent valueDecimal('32.1')
.Note that rounding is applied before reducing to simplest form.
In the latest versions of the specification, this operation is also known as
reduce
.
- number_class(context=None)¶
Retorna uma string descrevendo a classe do operando. O valor retornado é uma das dez sequências a seguir.
"-Infinity"
, indicando que o operando é infinito negativo."-Normal"
, indicando que o operando é um número normal negativo."-Subnormal"
, indicando que o operando é negativo e subnormal."-Zero"
, indicando que o operando é um zero negativo."+Zero"
, indicando que o operando é um zero positivo."+Subnormal"
, indicando que o operando é positivo e subnormal."+Normal"
, indicando que o operando é um número normal positivo."+Infinity"
, indicando que o operando é infinito positivo."NaN"
, indicando que o operando é um NaN (“Not a Number”) silencioso."sNaN"
, indicando que o operando é um NaN sinalizador.
- quantize(exp, rounding=None, context=None)¶
Retorna um valor igual ao primeiro operando após o arredondamento e com o expoente do segundo operando.
>>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414')
Diferentemente de outras operações, se o comprimento do coeficiente após a operação de quantização for maior que a precisão, então
InvalidOperation
é sinalizado. Isso garante que, a menos que haja uma condição de erro, o expoente quantizado é sempre igual ao do operando do lado direito.Também, diferentemente de outras operações, a quantização nunca sinaliza Underflow, mesmo que o resultado seja subnormal e inexato.
Se o expoente do segundo operando for maior que o do primeiro, o arredondamento poderá ser necessário. Nesse caso, o modo de arredondamento é determinado pelo argumento
rounding
, se fornecido, ou pelo argumentocontext
fornecido; se nenhum argumento for fornecido, o modo de arredondamento do contexto da thread atual será usado.An error is returned whenever the resulting exponent is greater than
Emax
or less thanEtiny()
.
- radix()¶
Retorna
Decimal(10)
, a raiz (base) na qual a classeDecimal
faz toda a sua aritmética. Incluído para compatibilidade com a especificação.
- remainder_near(other, context=None)¶
Retorna o resto da divisão de self por other. Isso é diferente de
self % other
, pois o sinal do resto é escolhido para minimizar seu valor absoluto. Mais precisamente, o valor de retorno éself - n * other
, onden
é o número inteiro mais próximo do valor exato deself / other
, e se dois números inteiros estiverem igualmente próximos, o par será é escolhido.Se o resultado for zero, seu sinal será o sinal 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 o resultado da rotação dos dígitos do primeiro operando em uma quantidade especificada pelo segundo operando. O segundo operando deve ser um número inteiro no intervalo - precisão através da precisão. O valor absoluto do segundo operando fornece o número de locais a serem rotacionados. Se o segundo operando for positivo, a rotação será para a esquerda; caso contrário, a rotação será para a direita. O coeficiente do primeiro operando é preenchido à esquerda com zeros na precisão do comprimento, se necessário. O sinal e o expoente do primeiro operando não são alterados.
- same_quantum(other, context=None)¶
Test whether self and other have the same exponent or whether both are
NaN
.Esta operação não é afetada pelo contexto e é silenciosa: nenhum sinalizador é alterado e nenhum arredondamento é executado. Como uma exceção, a versão C pode levantar InvalidOperation se o segundo operando não puder ser convertido exatamente.
- scaleb(other, context=None)¶
Retorna o primeiro operando com o expoente ajustado pelo segundo. Da mesma forma, retorna o primeiro operando multiplicado por
10**other
. O segundo operando deve ser um número inteiro.
- shift(other, context=None)¶
Retorna o resultado da troca dos dígitos do primeiro operando em uma quantidade especificada pelo segundo operando. O segundo operando deve ser um número inteiro no intervalo - precisão através da precisão. O valor absoluto do segundo operando fornece o número de locais a serem deslocados. Se o segundo operando for positivo, o deslocamento será para a esquerda; caso contrário, a mudança é para a direita. Os dígitos deslocados para o coeficiente são zeros. O sinal e o expoente do primeiro operando não são alterados.
- sqrt(context=None)¶
Retorna a raiz quadrada do argumento para a precisão total.
- to_eng_string(context=None)¶
Converte em uma string, usando notação de engenharia, se for necessário um expoente.
A notação de engenharia possui um expoente que é múltiplo de 3. Isso pode deixar até 3 dígitos à esquerda da casa decimal e pode exigir a adição de um ou dois zeros à direita.
Por exemplo, isso converte
Decimal('123E+1')
paraDecimal('1.23E+3')
.
- to_integral(rounding=None, context=None)¶
Idêntico ao método
to_integral_value()
. O nometo_integral
foi mantido para compatibilidade com versões mais antigas.
- to_integral_exact(rounding=None, context=None)¶
Arredonda para o número inteiro mais próximo, sinalizando
Inexact
ouRounded
, conforme apropriado, se o arredondamento ocorrer. O modo de arredondamento é determinado pelo parâmetrorouding
, se fornecido, ou pelocontext
especificado. Se nenhum parâmetro for fornecido, o modo de arredondamento do contexto atual será usado.
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 de contexto¶
Contextos são ambientes para operações aritméticas. Eles governam a precisão, estabelecem regras para arredondamento, determinam quais sinais são tratados como exceções e limitam o intervalo dos expoentes.
Cada thread possui seu próprio contexto atual que é acessado ou alterado usando as funções getcontext()
e setcontext()
:
- decimal.getcontext()¶
Retorna o contexto atual para a thread ativa.
- decimal.setcontext(c)¶
Define o contexto atual para a thread ativa como C.
Você também pode usar a instrução with
e a função localcontext()
para alterar temporariamente o contexto ativo.
- decimal.localcontext(ctx=None, **kwargs)¶
Return a context manager that will set the current context for the active thread to a copy of ctx on entry to the with-statement and restore the previous context when exiting the with-statement. If no context is specified, a copy of the current context is used. The kwargs argument is used to set the attributes of the new context.
Por exemplo, o código a seguir define a precisão decimal atual para 42 casas, executa um cálculo e restaura automaticamente o 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
Using keyword arguments, the code would be the following:
from decimal import localcontext with localcontext(prec=42) as ctx: s = calculate_something() s = +s
Raises
TypeError
if kwargs supplies an attribute thatContext
doesn’t support. Raises eitherTypeError
orValueError
if kwargs supplies an invalid value for an attribute.Alterado na versão 3.11:
localcontext()
now supports setting context attributes through the use of keyword arguments.
Novos contextos também podem ser criados usando o construtor Context
descrito abaixo. Além disso, o módulo fornece três contextos pré-criados:
- class decimal.BasicContext¶
Este é um contexto padrão definido pela Especificação Aritmética Decimal Geral. A precisão está definida como nove. O arredondamento está definido como
ROUND_HALF_UP
. Todos os sinalizadores estão limpos. Todos as armadilhas estão ativadas (tratadas como exceções), exceto porInexact
,Rounded
eSubnormal
.Como muitas das armadilhas estão ativadas, esse contexto é útil para depuração.
- class decimal.ExtendedContext¶
Este é um contexto padrão definido pela Especificação Aritmética Decimal Geral. A precisão está definida como nove. O arredondamento está definido como
ROUND_HALF_EVEN
. Todos os sinalizadores estão limpos. Nenhuma armadilha está ativada (de forma que exceções não são levantadas durante os 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 é usado pelo construtor
Context
como um protótipo para novos contextos. Alterar um campo (tal como precisão) tem o efeito de alterar o padrão para novos contextos criados pelo construtorContext
.Esse contexto é mais útil em ambientes multithread. A alteração de um dos campos antes do início das threads tem o efeito de definir os padrões para todo o sistema. Não é recomendável alterar os campos após o início das threads, pois exigiria sincronização de threads para evitar condições de corrida.
Em ambientes de thread única, é preferível não usar esse contexto. Em vez disso, basta criar contextos explicitamente, conforme descrito abaixo.
The default values are
Context.prec
=28
,Context.rounding
=ROUND_HALF_EVEN
, and enabled traps forOverflow
,InvalidOperation
, andDivisionByZero
.
Além dos três contextos fornecidos, novos contextos podem ser criados com o construtor Context
.
- class decimal.Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)¶
Cria um novo contexto. Se um campo não for especificado ou for
None
, os valores padrão serão copiados deDefaultContext
. Se o campo flags não for especificado ou forNone
, todos os sinalizadores serão limpados.prec is an integer in the range [
1
,MAX_PREC
] that sets the precision for arithmetic operations in the context.A opção rounding é uma das constantes listadas na seção Modos de arredondamento.
Os campos traps e flags listam todos os sinais a serem configurados. Geralmente, novos contextos devem apenas definir armadilhas e deixar os sinalizadores limpos.
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
.Novo na versão 3.3.
- copy()¶
Retorna uma duplicata do contexto.
- copy_decimal(num)¶
Retorna uma cópia da instância de Decimal num.
- create_decimal(num)¶
Cria uma nova instância decimal a partir de num, mas usando self como contexto. Diferentemente do construtor de
Decimal
, a precisão do contexto, o método de arredondamento, os sinalizadores e as armadilhas são aplicadas à conversão.Isso é útil porque as constantes geralmente são fornecidas com uma precisão maior do que a necessária pela aplicação. Outro benefício é que o arredondamento elimina imediatamente os efeitos indesejados dos dígitos além da precisão atual. No exemplo a seguir, o uso de entradas não arredondadas significa que adicionar zero a uma soma pode alterar o 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 a operação “to-number” da especificação IBM. Se o argumento for uma string, nenhum espaço em branco à esquerda ou à direita ou sublinhado serão permitidos.
- create_decimal_from_float(f)¶
Cria uma nova instância de Decimal a partir de um ponto flutuante f, mas arredondando usando self como contexto. Diferentemente do método da classe
Decimal.from_float()
, a precisão do contexto, o método de arredondamento, os sinalizadores e as armadilhas são aplicados à conversão.>>> 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
Novo na versão 3.1.
- Etiny()¶
Retorna um valor igual a
Emin - prec + 1
, que é o valor mínimo do expoente para resultados subnormais. Quando ocorre o estouro negativo, o expoente é definido comoEtiny
.
- Etop()¶
Retorna um valor igual a
Emax - prec + 1
.
A abordagem usual para trabalhar com decimais é criar instâncias de
Decimal
e depois aplicar operações aritméticas que ocorrem no contexto atual da thread ativa. Uma abordagem alternativa é usar métodos de contexto para calcular dentro de um contexto específico. Os métodos são semelhantes aos da classeDecimal
e são contados apenas brevemente aqui.- abs(x)¶
Retorna o valor absoluto de x.
- add(x, y)¶
Retorna a soma de x e y.
- canonical(x)¶
Retorna o mesmo objeto de Decimal x.
- compare(x, y)¶
Compara x e y numericamente.
- compare_signal(x, y)¶
Compara os valores dos dois operandos numericamente.
- compare_total(x, y)¶
Compara dois operandos usando sua representação abstrata.
- compare_total_mag(x, y)¶
Compara dois operandos usando sua representação abstrata, ignorando o sinal.
- copy_abs(x)¶
Retorna uma cópia de x com o sinal definido para 0.
- copy_negate(x)¶
Retorna uma cópia de x com o sinal invertido.
- copy_sign(x, y)¶
Copia o sinal de y para x.
- divide(x, y)¶
Retorna x dividido por y.
- divide_int(x, y)¶
Retorna x dividido por y, truncado para um inteiro.
- divmod(x, y)¶
Divide dois números e retorna a parte inteira do resultado.
- exp(x)¶
Returns
e ** x
.
- fma(x, y, z)¶
Retorna x multiplicado por y, mais z.
- is_canonical(x)¶
Retorna
True
se x for canonical; caso contrário, retornaFalse
.
- is_finite(x)¶
Retorna
True
se x for finito; caso contrário, retornaFalse
.
- is_infinite(x)¶
Retorna
True
se x for infinito; caso contrário, retornaFalse
.
- is_nan(x)¶
Retorna
True
se x for qNaN ou sNaN; caso contrário, retornaFalse
.
- is_normal(x)¶
Retorna
True
se x for um número normal; caso contrário, retornaFalse
.
- is_qnan(x)¶
Retorna
True
se x for um NaN silencioso; caso contrário, retornaFalse
.
- is_signed(x)¶
Retorna
True
se x for negativo; caso contrário, retornaFalse
.
- is_snan(x)¶
Retorna
True
se x for um NaN sinalizador; caso contrário, retornaFalse
.
- is_subnormal(x)¶
Retorna
True
se x for subnormal; caso contrário, retornaFalse
.
- is_zero(x)¶
Retorna
True
se x for zero; caso contrário, retornaFalse
.
- ln(x)¶
Retorna o logaritmo natural (base e) de x.
- log10(x)¶
Retorna o logaritmo de base 10 de x.
- logb(x)¶
Retorna o expoente da magnitude do MSD do operando.
- logical_and(x, y)¶
Aplica a operação lógica e entre cada dígito do operando.
- logical_invert(x)¶
Inverte todos os dígitos em x.
- logical_or(x, y)¶
Aplica a operação lógica ou entre cada dígito do operando.
- logical_xor(x, y)¶
Aplica a operação lógica ou exclusivo entre cada dígito do operando.
- max(x, y)¶
Compara dois valores numericamente e retorna o máximo.
- max_mag(x, y)¶
Compara dois valores numericamente com seu sinal ignorado.
- min(x, y)¶
Compara dois valores numericamente e retorna o mínimo.
- min_mag(x, y)¶
Compara dois valores numericamente com seu sinal ignorado.
- minus(x)¶
Minus corresponde ao operador de subtração de prefixo unário no Python.
- multiply(x, y)¶
Retorna o produto de x e y.
- next_minus(x)¶
Retorna o maior número representável menor que x.
- next_plus(x)¶
Retorna o menor número representável maior que x.
- next_toward(x, y)¶
Retorna o número mais próximo a x, em direção a y.
- normalize(x)¶
Reduz x para sua forma mais simples.
- number_class(x)¶
Retorna uma indicação da classe de x.
- plus(x)¶
Plus corresponde ao operador de soma de prefixo unário no Python. Esta operação aplica a precisão e o arredondamento do contexto, portanto não é uma operação de identidade.
- power(x, y, modulo=None)¶
Retorna
x
à potência dey
, com a redução de módulomodulo
se fornecido.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)
resulta emInvalidOperation
, e seInvalidOperation
não for capturado, resulta emDecimal('NaN')
.Alterado na versão 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”.Com três argumentos, calcula
(x**y) % modulo
. Para o formulário de três argumentos, as seguintes restrições nos argumentos são válidas:todos os três argumentos devem ser inteiros
y
não pode ser negativopelo menos um de
x
ouy
não pode ser negativomodulo
não pode ser zero e deve ter pelo menos “precisão” dígitos
O valor resultante de
Context.power(x, y, modulo)
é igual ao valor que seria obtido ao computar(x**y) % modulo
com precisão ilimitada, mas é calculado com mais eficiência . O expoente do resultado é zero, independentemente dos expoentes dex
,y
emodulo
. O resultado é sempre exato.
- quantize(x, y)¶
Retorna um valor igual a x (arredondado), com o expoente de y.
- radix()¶
Só retorna 10, já que isso é Decimal, :)
- remainder(x, y)¶
Retorna o resto da divisão inteira.
O sinal do resultado, se diferente de zero, é o mesmo que o do dividendo original.
- remainder_near(x, y)¶
Retorna
x - y * n
, onde n é o número inteiro mais próximo do valor exato dex / y
(se o resultado for 0, seu sinal será o sinal de x).
- rotate(x, y)¶
Retorna uma cópia re de x, y vezes.
- same_quantum(x, y)¶
Retorna
True
se os dois operandos tiverem o mesmo expoente.
- scaleb(x, y)¶
Retorna o primeiro operando após adicionar o segundo valor seu exp.
- shift(x, y)¶
Retorna uma cópia deslocada de x, y vezes.
- sqrt(x)¶
Raiz quadrada de um número não negativo para precisão do contexto.
- subtract(x, y)¶
Retorna a diferença entre x e y.
- to_eng_string(x)¶
Converte em uma string, usando notação de engenharia, se for necessário um expoente.
A notação de engenharia possui um expoente que é múltiplo de 3. Isso pode deixar até 3 dígitos à esquerda da casa decimal e pode exigir a adição de um ou dois zeros à direita.
- to_integral_exact(x)¶
Arredonda para um número inteiro.
- to_sci_string(x)¶
Converte um número em uma string usando notação científica.
Constantes¶
As constantes nesta seção são relevantes apenas para o módulo C. Eles também estão incluídos na versão pura do Python para compatibilidade.
32 bits |
64 bits |
|
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
- decimal.HAVE_THREADS¶
O valor é
True
. Descontinuado porque o Python agora sempre tem threads.
Obsoleto desde a versão 3.9.
- decimal.HAVE_CONTEXTVAR¶
O valor padrão é
True
. Se o Python forconfigurado usando a opção --without-decimal-contextvar
, a versão C usará um contexto local de thread em vez de local de corrotina e o valor seráFalse
. Isso é um pouco mais rápido em alguns cenários de contexto aninhados.
Novo na versão 3.9: backport realizado para 3.7 e 3.8.
Modos de arredondamento¶
- decimal.ROUND_CEILING¶
Round towards
Infinity
.
- decimal.ROUND_DOWN¶
Arredonda para zero.
- decimal.ROUND_FLOOR¶
Round towards
-Infinity
.
- decimal.ROUND_HALF_DOWN¶
Arrendonda para o mais próximo com empates tendendo a zero.
- decimal.ROUND_HALF_EVEN¶
Arredonda para o mais próximo com empates indo para o mais próximo inteiro par.
- decimal.ROUND_HALF_UP¶
Arrendonda para o mais próximo com empates se afastando de zero.
- decimal.ROUND_UP¶
Arredonda se afastando de zero.
- decimal.ROUND_05UP¶
Arredonda se afastando de zero se o último dígito após o arredondamento para zero fosse 0 ou 5; caso contrário, arredonda para zero.
Sinais¶
Sinais representam condições que surgem durante o cálculo. Cada um corresponde a um sinalizador de contexto e um ativador de armadilha de contexto.
O sinalizador de contexto é definido sempre que a condição é encontrada. Após o cálculo, os sinalizadores podem ser verificados para fins informativos (por exemplo, para determinar se um cálculo era exato). Depois de verificar os sinalizadores, certifique-se de limpar todos os sinalizadores antes de iniciar o próximo cálculo.
Se o ativador de armadilha de contexto estiver definido para o sinal, a condição fará com que uma exceção Python seja levantada. Por exemplo, se a armadilha DivisionByZero
for configurada, uma exceção DivisionByZero
será levantada ao encontrar a condição.
- class decimal.Clamped¶
Altera um expoente para ajustar as restrições de representação.
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¶
Classe base para outros sinais e uma subclasse de
ArithmeticError
.
- class decimal.DivisionByZero¶
Sinaliza a divisão de um número não infinito por zero.
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 o arredondamento ocorreu e o resultado não é exato.
Sinaliza quando dígitos diferentes de zero foram descartados durante o arredondamento. O resultado arredondado é retornado. O sinalizador ou armadilha de sinal é usado para detectar quando os resultados são inexatos.
- class decimal.InvalidOperation¶
Uma operação inválida foi realizada.
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¶
Estouro 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¶
O arredondamento ocorreu, embora possivelmente nenhuma informação tenha sido perdida.
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.Ocorre quando um resultado da operação é subnormal (o expoente é muito pequeno). Se não for capturado, retorna o resultado inalterado.
- class decimal.Underflow¶
Estouro negativo numérico com resultado arredondado para zero.
Ocorre quando um resultado subnormal é empurrado para zero arredondando.
Inexact
eSubnormal
também são sinalizados.
- class decimal.FloatOperation¶
Ativa semânticas mais rigorosas para misturar objetos de float com de Decimal.
Se o sinal não for capturado (padrão), a mistura de tipos float e Decimal será permitida no construtor
Decimal
,create_decimal()
e em todos os operadores de comparação. Tanto a conversão quanto as comparações são exatas. Qualquer ocorrência de uma operação mista é registrada silenciosamente pela configuraçãoFloatOperation
nos sinalizadores de contexto. Conversões explícitas comfrom_float()
oucreate_decimal_from_float()
não definem o sinalizador.Caso contrário (o sinal é capturado), apenas comparações de igualdade e conversões explícitas são silenciosas. Todas as outras operações mistas levantam
FloatOperation
.
A tabela a seguir resume a hierarquia de sinais:
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)
Observações sobre ponto flutuante¶
Atenuando o erro de arredondamento com maior precisão¶
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.
Os efeitos do erro de arredondamento podem ser amplificados pela adição ou subtração de quantidades quase compensadoras, resultando em perda de significância. Knuth fornece dois exemplos instrutivos em que a aritmética de ponto flutuante arredondado com precisão insuficiente causa a quebra das propriedades associativas e distributivas da adição:
# 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')
O módulo decimal
permite restaurar as identidades expandindo a precisão o suficiente para evitar perda de significância:
>>> 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 especiais¶
The number system for the decimal
module provides special values
including NaN
, sNaN
, -Infinity
, Infinity
,
and two zeros, +0
and -0
.
Os infinitos podem ser construídos diretamente com: Decimal('Infinity')
. Além disso, eles podem resultar da divisão por zero quando o sinal DivisionByZero
não é capturado. Da mesma forma, quando o sinal Overflow
não é capturado, o infinito pode resultar do arredondamento além dos limites do maior número representável.
Os infinitos contêm sinais (afins) e podem ser usados em operações aritméticas, onde são tratados como números muito grandes e indeterminados. Por exemplo, adicionar uma constante ao infinito fornece outro resultado 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.
Os zeros com sinais podem resultar de cálculos insuficientes. Eles mantêm o sinal que teria resultado se o cálculo tivesse sido realizado com maior precisão. Como sua magnitude é zero, os zeros positivos e negativos são tratados como iguais e seu sinal é informacional.
Além dos dois zeros com sinais que são distintos e iguais, existem várias representações de zero com diferentes precisões e ainda com valor equivalente. Isso leva um pouco de tempo para se acostumar. Para um olho acostumado a representações de ponto flutuante normalizadas, não é imediatamente óbvio que o seguinte cálculo retorne um valor igual a zero:
>>> 1 / Decimal('Infinity')
Decimal('0E-1000026')
Trabalhando com threads¶
A função getcontext()
acessa um objeto Context
diferente para cada thread. Ter contextos de threads separadas significa que as threads podem fazer alterações (como getcontext().prec=10
) sem interferir em outras threads.
Da mesma forma, a função setcontext()
atribui automaticamente seu alvo à thread atual.
Se setcontext()
não tiver sido chamado antes de getcontext()
, então getcontext()
criará automaticamente um novo contexto para uso na thread atual.
O novo contexto é copiado de um contexto protótipo chamado DefaultContext. Para controlar os padrões para que cada thread, use os mesmos valores em todo o aplicativo, modifique diretamente o objeto DefaultContext. Isso deve ser feito antes de qualquer thread ser iniciada, para que não haja uma condição de corrida entre as threads chamando getcontext()
. Por exemplo:
# 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()
. . .
Receitas¶
Aqui estão algumas receitas que servem como funções utilitárias e que demonstram maneiras de trabalhar com a classe 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
Perguntas Frequentes sobre Decimal¶
P. É complicado digitar decimal.Decimal('1234.5')
. Existe uma maneira de minimizar a digitação ao usar o interpretador interativo?
R. Alguns usuários abreviam o construtor para apenas uma única letra:
>>> D = decimal.Decimal
>>> D('1.23') + D('3.45')
Decimal('4.68')
P. Em uma aplicação de ponto fixo com duas casas decimais, algumas entradas têm muitas casas e precisam ser arredondadas. Outros não devem ter dígitos em excesso e precisam ser validados. Quais métodos devem ser usados?
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. Depois de validar entradas de duas casas, como mantenho essa invariável em uma aplicação?
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')]
Q. When does rounding occur in a computation?
A. It occurs after the computation. The philosophy of the decimal specification is that numbers are considered exact and are created independent of the current context. They can even have greater precision than current context. Computations process with those exact inputs and then rounding (or other context operations) is applied to the result of the computation:
>>> getcontext().prec = 5
>>> pi = Decimal('3.1415926535') # More than 5 digits
>>> pi # All digits are retained
Decimal('3.1415926535')
>>> pi + 0 # Rounded after an addition
Decimal('3.1416')
>>> pi - Decimal('0.00005') # Subtract unrounded numbers, then round
Decimal('3.1415')
>>> pi + 0 - Decimal('0.00005'). # Intermediate values are rounded
Decimal('3.1416')
P. Alguns valores decimais sempre são exibidas com notação exponencial. Existe uma maneira de obter uma representação não 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.
Se uma aplicação não se importa com o rastreamento da significância, é fácil remover o expoente e os zeros à direita, perdendo a significância, mas mantendo o valor inalterado:
>>> 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. Existe uma maneira de converter um float comum em um Decimal
?
R. Sim, qualquer número de ponto flutuante binário pode ser expresso exatamente como um Decimal, embora uma conversão exata possa exigir mais precisão do que a intuição sugere:
>>> Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')
P. Em um cálculo complexo, como posso ter certeza de que não obtive um resultado falso devido à precisão insuficiente ou a anomalias de arredondamento.
R. O módulo decimal facilita o teste de resultados. Uma prática recomendada é executar novamente os cálculos usando maior precisão e com vários modos de arredondamento. Resultados amplamente diferentes indicam precisão insuficiente, problemas no modo de arredondamento, entradas mal condicionadas ou um algoritmo numericamente instável.
P. Notei que a precisão do contexto é aplicada aos resultados das operações, mas não às entradas. Há algo a observar ao misturar valores de diferentes precisões?
R. Sim. O princípio é que todos os valores são considerados exatos, assim como a aritmética desses valores. Somente os resultados são arredondados. A vantagem das entradas é que “o que você vê é o que você obtém”. Uma desvantagem é que os resultados podem parecer estranhos se você esquecer que as entradas não foram arredondadas:
>>> getcontext().prec = 3
>>> Decimal('3.104') + Decimal('2.104')
Decimal('5.21')
>>> Decimal('3.104') + Decimal('0.000') + Decimal('2.104')
Decimal('5.20')
A solução é aumentar a precisão ou forçar o arredondamento das entradas usando a operação unária de mais:
>>> getcontext().prec = 3
>>> +Decimal('1.23456789') # unary plus triggers rounding
Decimal('1.23')
Como alternativa, as entradas podem ser arredondadas na criação usando o método Context.create_decimal()
:
>>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678')
Decimal('1.2345')
P. A implementação do CPython é 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 inexatos, MAX_PREC
é muito grande em plataformas de 64 bits e a memória disponível 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'>]
Em geral (e especialmente em sistemas sem alocação excessiva), recomenda-se estimar limites ainda mais apertados e definir a armadilha Inexact
se for esperado que todos os cálculos sejam mais precisos.