9.4. decimal
— Aritmética de ponto decimal fixo e ponto flutuante¶
Novo na versão 2.4.
The decimal
module provides support for 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.A exatidão transita para a aritmética. No ponto flutuante decimal,
0.1 + 0.1 + 0.1 - 0.3
é exatamente igual a zero. No ponto flutuante binário, o resultado é5.5511151231257827e-017
. Embora próximas de zero, as diferenças impedem o teste de igualdade confiável e as diferenças podem se acumular. Por esse motivo, o decimal é preferido em aplicativos de contabilidade que possuem invariáveis estritos de igualdade.O módulo decimal incorpora uma noção de casas significativas para que
1.30 + 1.20
seja2.50
. O zero à direita é mantido para indicar significância. Esta é a apresentação habitual para aplicações monetárias. Para multiplicação, a abordagem “livro escolar” usa todas as figuras nos multiplicandos. Por exemplo,1.3 * 1.2
é igual a1.56
enquanto1.30 * 1.20
é igual a1.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.
Um número decimal é imutável. Possui um sinal, dígitos de coeficiente e um expoente. Para preservar a significância, os dígitos do coeficiente não truncam zeros à direita. Os decimais também incluem valores especiais, tais como Infinity
, -Infinity
e NaN
. O padrão também diferencia -0
de +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
.
Signals are groups of exceptional conditions arising during the course of
computation. Depending on the needs of the application, signals may be ignored,
considered as informational, or treated as exceptions. The signals in the
decimal module are: Clamped
, InvalidOperation
,
DivisionByZero
, Inexact
, Rounded
, Subnormal
,
Overflow
, and Underflow
.
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.
9.4.1. 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=-999999999, Emax=999999999,
capitals=1, 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.41421356237')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.414213562373095048801688724')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')
O significado de um novo decimal é determinado apenas pelo número de dígitos digitados. 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')
Os decimais interagem bem com grande parte do restante do Python. Aqui está um pequeno circo voador de ponto flutuante decimal:
>>> data = 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) # round() first converts to binary floating point
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')
O método quantize()
arredonda um número para um expoente fixo. Esse método é útil para aplicativos monetários que geralmente arredondam os resultados para um número fixo de locais:
>>> 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=-999999999, Emax=999999999,
capitals=1, 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
Os contextos também possuem sinalizadores para monitorar condições excepcionais encontradas durante os cálculos. Os sinalizadores permanecem definidos até que sejam explicitamente limpos, portanto, é melhor limpar os sinalizadores antes de cada conjunto de cálculos monitorados usando o método clear_flags()
.
>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
capitals=1, flags=[Rounded, Inexact], traps=[])
A entrada flags mostra que a aproximação racional de Pi
foi arredondada (dígitos além da precisão do contexto foram descartados) e que o resultado é inexato (alguns dos dígitos descartados eram diferentes de zero).
As armadilhas individuais são definidas usando o dicionário no campo traps
de um contexto:
>>> 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.
9.4.2. Objetos de Decimal¶
-
class
decimal.
Decimal
([value[, context]])¶ Constrói um novo objeto de
Decimal
com base em value.value can be an integer, string, tuple,
float
, or anotherDecimal
object. If no value is given, returnsDecimal('0')
. If value is a string, it should conform to the decimal numeric string syntax after leading and trailing whitespace characters are removed: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
If value is a unicode string then other Unicode decimal digits are also permitted where
digit
appears above. These include decimal digits from various other alphabets (for example, Arabic-Indic and Devanāgarī digits) along with the fullwidth digitsu'\uff10'
throughu'\uff19'
.Se value for uma
tupla
, ele deverá ter três componentes, um sinal (0
para positivo ou1
para negativo), umatupla
de dígitos e um expoente inteiro. Por exemplo,Decimal((0, (1, 4, 1, 4), -3))
returnaDecimal('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.O objetivo do argumento context é determinar o que fazer se value for uma string malformada. Se o contexto capturar
InvalidOperation
, uma exceção será levantada; caso contrário, o construtor retornará um novo decimal com o valor deNaN
.Uma vez construídos, objetos de
Decimal
são imutáveis.Alterado na versão 2.6: leading and trailing whitespace characters are permitted when creating a Decimal instance from a string.
Alterado na versão 2.7: O argumento para o construtor agora pode ser uma instância
float
.Decimal floating point objects share many properties with the other built-in numeric types such as
float
andint
. All of the usual math operations and special methods apply. Likewise, decimal objects can be copied, pickled, printed, used as dictionary keys, used as set elements, compared, sorted, and coerced to another type (such asfloat
orlong
).Existem algumas pequenas diferenças entre aritmética em objetos decimais e aritmética em números inteiros e flutuantes. Quando o operador restante
%
é 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 piso, 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.Decimal objects cannot generally be combined with floats in arithmetic operations: an attempt to add a
Decimal
to afloat
, for example, will raise aTypeError
. There’s one exception to this rule: it’s possible to use Python’s comparison operators to compare afloat
instancex
with aDecimal
instancey
. Without this exception, comparisons betweenDecimal
andfloat
instances would follow the general rules for comparing objects of different types described in the Expressões section of the reference manual, leading to confusing results.Alterado na versão 2.7: A comparison between a
float
instancex
and aDecimal
instancey
now returns a result based on the values ofx
andy
. In earlier versionsx < y
returned the same (arbitrary) result for anyDecimal
instancex
and anyfloat
instancey
.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_tuple
()¶ Retorna uma representação de tupla nomeada do número:
DecimalTuple(sinal, dígitos, exponente)
.Alterado na versão 2.6: Use a named tuple.
-
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.Novo na versão 2.6.
-
compare
(other[, context])¶ Compare the values of two Decimal instances. This operation behaves in the same way as the usual comparison method
__cmp__()
, except thatcompare()
returns a Decimal instance rather than an integer, and if either operand is a NaN then the result is a 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])¶ 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.Novo na versão 2.6.
-
compare_total
(other)¶ 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.Novo na versão 2.6.
-
compare_total_mag
(other)¶ 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())
.Novo na versão 2.6.
-
conjugate
()¶ Apenas retorna a si próprio, sendo esse método apenas para atender à Especificação Decimal.
Novo na versão 2.6.
-
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.
Novo na versão 2.6.
-
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.
Novo na versão 2.6.
-
copy_sign
(other)¶ 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')
This operation is unaffected by the context and is quiet: no flags are changed and no rounding is performed.
Novo na versão 2.6.
-
exp
([context])¶ 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')
Novo na versão 2.6.
-
from_float
(f)¶ Método de classe que converte um ponto flutuante em um número decimal, exatamente.
Observe que Decimal.from_float(0.1) não é o mesmo que Decimal(‘0.1’). Como 0.1 não é exatamente representável no ponto flutuante binário, o valor é armazenado como o valor representável mais próximo que é 0x1.999999999999ap-4. Esse valor equivalente em decimal é 0.1000000000000000055511151231257827021181583404541015625.
>>> 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 2.7.
-
fma
(other, third[, context])¶ 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')
Novo na versão 2.6.
-
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
.Novo na versão 2.6.
-
is_finite
()¶ Retorna
True
se o argumento for um número finito eFalse
se o argumento for um infinito ou um NaN.Novo na versão 2.6.
-
is_infinite
()¶ Retorna
True
se o argumento for infinito positivo ou negativo eFalse
caso contrário.Novo na versão 2.6.
-
is_nan
()¶ Retorna
True
se o argumento for NaN (silencioso ou sinalizador) eFalse
caso contrário.Novo na versão 2.6.
-
is_normal
()¶ Return
True
if the argument is a normal finite non-zero number with an adjusted exponent greater than or equal to Emin. ReturnFalse
if the argument is zero, subnormal, infinite or a NaN. Note, the term normal is used here in a different sense with thenormalize()
method which is used to create canonical values.Novo na versão 2.6.
-
is_qnan
()¶ Retorna
True
se o argumento for um NaN silencioso, eFalse
caso contrário.Novo na versão 2.6.
-
is_signed
()¶ Retorna
True
se o argumento tiver um sinal negativo eFalse
caso contrário. Observe que zeros e NaNs podem carregar sinais.Novo na versão 2.6.
-
is_subnormal
()¶ Return
True
if the argument is subnormal, andFalse
otherwise. A number is subnormal is if it is nonzero, finite, and has an adjusted exponent less than Emin.Novo na versão 2.6.
-
is_zero
()¶ Retorna
True
se o argumento for um zero (positivo ou negativo) eFalse
caso contrário.Novo na versão 2.6.
-
ln
([context])¶ Retorna o logaritmo (base e) natural do operando. O resultado é arredondado corretamente usando o modo de arredondamento
ROUND_HALF_EVEN
.Novo na versão 2.6.
-
log10
([context])¶ Retorna o logaritmo da base dez do operando. O resultado é arredondado corretamente usando o modo de arredondamento
ROUND_HALF_EVEN
.Novo na versão 2.6.
-
logb
([context])¶ 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.Novo na versão 2.6.
-
logical_and
(other[, context])¶ logic_and()
é uma operação lógica que leva dois operandos lógicos (consulte logic_operands_label). O resultado é oand
dígito a dígito dos dois operandos.Novo na versão 2.6.
-
logical_invert
([context])¶ logical_invert()
é uma operação lógica. O resultado é a inversão dígito a dígito do operando.Novo na versão 2.6.
-
logical_or
(other[, context])¶ logic_or()
é uma operação lógica que leva dois operandos lógicos (consulte logic_operands_label). O resultado é oor
dígito a dígito dos dois operandos.Novo na versão 2.6.
-
logical_xor
(other[, context])¶ logical_xor()
é uma operação lógica que leva dois operandos lógicos (consulte logic_operands_label). O resultado é o ou exclusivo dígito a dígito ou dos dois operandos.Novo na versão 2.6.
-
max
(other[, context])¶ Semelhante a
max(self, other)
, exceto que a regra de arredondamento de contexto é aplicada antes de retornar e que os valoresNaN
são sinalizados ou ignorados (dependendo do contexto e se estão sinalizando ou silenciosos).
-
max_mag
(other[, context])¶ Semelhante ao método
max()
, mas a comparação é feita usando os valores absolutos dos operandos.Novo na versão 2.6.
-
min
(other[, context])¶ Semelhante a
min(self, other)
, exceto que a regra de arredondamento de contexto é aplicada antes de retornar e que os valoresNaN
são sinalizados ou ignorados (dependendo do contexto e se estão sinalizando ou silenciosos).
-
min_mag
(other[, context])¶ Semelhante ao método
min()
, mas a comparação é feita usando os valores absolutos dos operandos.Novo na versão 2.6.
-
next_minus
([context])¶ 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.
Novo na versão 2.6.
-
next_plus
([context])¶ 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.
Novo na versão 2.6.
-
next_toward
(other[, context])¶ 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, retorne uma cópia do primeiro operando com o sinal configurado para ser o mesmo que o sinal do segundo operando.
Novo na versão 2.6.
-
normalize
([context])¶ Normaliza o número eliminando os zeros à direita e convertendo qualquer resultado igual a
Decimal('0')
paraDecimal('0e0')
. Usado para produzir valores canônicos para atributos de uma classe de equivalência. Por exemplo,Decimal('32.100')
eDecimal('0.321000e+2')
normalizam com o valor equivalenteDecimal('32.1')
.
-
number_class
([context])¶ 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 silencioso (não é um número)."sNaN"
, indicando que o operando é um NaN sinalizador.
Novo na versão 2.6.
-
quantize
(exp[, rounding[, context[, watchexp]]])¶ 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.If watchexp is set (default), then 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.Novo na versão 2.6.
-
remainder_near
(other[, context])¶ 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])¶ 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.
Novo na versão 2.6.
-
same_quantum
(other[, context])¶ Testa se “self” e “other” têm o mesmo expoente ou se ambos são
NaN
.
-
scaleb
(other[, context])¶ 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.Novo na versão 2.6.
-
shift
(other[, context])¶ 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.
Novo na versão 2.6.
-
sqrt
([context])¶ Retorna a raiz quadrada do argumento para a precisão total.
-
to_eng_string
([context])¶ 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[, context]])¶ Idêntico ao método
to_integral_value()
. O nometo_integral
foi mantido para compatibilidade com versões mais antigas.
-
to_integral_exact
([rounding[, context]])¶ 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âmetro rouding`, se fornecido, ou pelocontext
especificado. Se nenhum parâmetro for fornecido, o modo de arredondamento do contexto atual será usado.Novo na versão 2.6.
-
to_integral_value
([rounding[, context]])¶ Arredonda para o número inteiro mais próximo sem sinalizar
Inexact
ouRounding
. Se fornecido, aplica rounding; caso contrário, usa o método de arredondamento no context especificado ou no contexto atual.Alterado na versão 2.6: renamed from
to_integral
toto_integral_value
. The old name remains valid for compatibility.
-
9.4.3. 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 alcance 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.
Beginning with Python 2.5, you can also use the with
statement and
the localcontext()
function to temporarily change the active context.
-
decimal.
localcontext
([c])¶ Return a context manager that will set the current context for the active thread to a copy of c 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.
Novo na versão 2.5.
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 with localcontext(BasicContext): # temporarily use the BasicContext print Decimal(1) / Decimal(7) print Decimal(355) / Decimal(113)
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 sã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).Como as armadilhas estão desativadas, esse contexto é útil para aplicativos que preferem ter o valor de resultado de
NaN
ouInfinity
em vez de levantar exceções. Isso permite que um aplicativo conclua uma execução na presença de condições que interromperiam o programa.
-
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 precision=28, rounding=ROUND_HALF_EVEN, and enabled traps for Overflow, InvalidOperation, and DivisionByZero.
Além dos três contextos fornecidos, novos contextos podem ser criados com o construtor Context
.
-
class
decimal.
Context
(prec=None, rounding=None, traps=None, flags=None, Emin=None, Emax=None, capitals=1)¶ 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.The prec field is a positive integer that sets the precision for arithmetic operations in the context.
The rounding option is one of:
ROUND_CEILING
(towardsInfinity
),ROUND_DOWN
(towards zero),ROUND_FLOOR
(towards-Infinity
),ROUND_HALF_DOWN
(to nearest with ties going towards zero),ROUND_HALF_EVEN
(to nearest with ties going to nearest even integer),ROUND_HALF_UP
(to nearest with ties going away from zero), orROUND_UP
(away from zero).ROUND_05UP
(away from zero if last digit after rounding towards zero would have been 0 or 5; otherwise towards zero)
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.
O campo capitals é
0
ou1
(o padrão). Se definido como1
, os expoentes serão impressos com umE
maiúsculo; caso contrário, ume
minúscula é usado:Decimal('6.02e+23')
.Alterado na versão 2.6: The
ROUND_05UP
rounding mode was added.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
orlong
) anywhere that a Decimal instance is accepted.-
clear_flags
()¶ Redefine todos os sinalizadores para
0
.
-
copy
()¶ Retorna uma duplicata do contexto.
-
copy_decimal
(num)¶ Retorna uma cópia de uma 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 pelo aplicativo. 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')
This method implements the to-number operation of the IBM specification. If the argument is a string, no leading or trailing whitespace is permitted.
-
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): ... Inexact: None
Novo na versão 2.7.
-
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 abastrata.
-
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)¶ Retorna e ** x.
-
fma
(x, y, z)¶ Retorna x multiplicado por y, mais z.
-
is_canonical
(x)¶ Retorna
True
se x for canonical; do contrário, retornaFalse
.
-
is_finite
(x)¶ Retorna
True
se x for finito; do 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; do 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; do 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 eclusivo 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])¶ Retorna
x
à potência dey
, com a redução de módulomodulo
if given.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 result should always be correctly rounded, using the rounding mode of the current thread’s context.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 mais dígitos de “precisão”
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.Alterado na versão 2.6:
y
may now be nonintegral inx**y
. Stricter requirements for the three-argument version.
-
quantize
(x, y)¶ Retorna um valor igual a x (arredondado), tendo 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 girada 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 sua 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.
9.4.4. Sinais¶
Sinais representam condições que surgem durante o cálculo. Cada um corresponde a um sinalizador de contexto e um ativador de armalhida 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
¶ Alterou um expoente para ajustar as restrições de representação.
Normalmente, a fixação ocorre quando um expoente fica fora dos limites do contexto
Emin
e attr:Emax. Se possível, o expoente é reduzido para caber adicionando zeros ao coeficiente.
-
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.
Pode ocorrer com divisão, divisão de módulo ou ao elevar um número a uma potência negativa. Se este sinal não for capturado, retornará
Infinity
ou-Infinity
com o sinal determinado pelas entradas do cálculo.
-
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.
Indica que uma operação foi solicitada que não faz sentido. Se não for capturado, retorna
NaN
. As possíveis causas incluem:Infinity - Infinity 0 * Infinity Infinity / Infinity x % 0 Infinity % x x._rescale( non-integer ) sqrt(-x) and x > 0 0 ** 0 x ** (non-integer) x ** Infinity
-
class
decimal.
Overflow
¶ Estouro numérico
Indica que o expoente é maior que
Emax
após o arredondamento ocorrer. Se não for capturado, o resultado depende do modo de arredondamento, puxando para dentro para o maior número finito representável ou arredondando para fora paraInfinity
. Nos dois casos,Inexact
eRounded
também são sinalizados.
-
class
decimal.
Rounded
¶ O arredondamento ocorreu, embora possivelmente nenhuma informação tenha sido perdida.
Sinalizado sempre que o arredondamento descarta dígitos; mesmo que esses dígitos sejam zero (como arredondamento
5.00
a5.0
). Se não for capturado, retorna o resultado inalterado. Este sinal é usado para detectar a perda de dígitos significativos.
-
class
decimal.
Subnormal
¶ O expoente foi menor que
Emin
antes do arredondamento.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.
A tabela a seguir resume a hierarquia de sinais:
exceptions.ArithmeticError(exceptions.StandardError)
DecimalException
Clamped
DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
Inexact
Overflow(Inexact, Rounded)
Underflow(Inexact, Rounded, Subnormal)
InvalidOperation
Rounded
Subnormal
9.4.5. Observações sobre ponto flutuante¶
9.4.5.1. Atenuando o erro de arredondamento com maior precisão¶
O uso do ponto flutuante decimal elimina o erro de representação decimal (possibilitando representar 0.1
de forma exata); no entanto, algumas operações ainda podem sofrer erros de arredondamento quando dígitos diferentes de zero excederem a precisão fixa.
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')
9.4.5.2. Valores especiais¶
O sistema numérico para o módulo decimal
fornece valores especiais, incluindo NaN
, sNaN
, -Infinity
, Infinity
e dois zeros, +0
e -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.
Algumas operações são indeterminadas e retornam NaN
ou, se o sinal InvalidOperation
for capturado, levanta uma exceção. Por exemplo, 0/0
retorna NaN
, que significa “não é um número” em inglês. Esta variação de NaN
é silenciosa e, uma vez criada, fluirá através de outros cálculos sempre resultando em outra NaN
. Esse comportamento pode ser útil para uma série de cálculos que ocasionalmente têm entradas ausentes — ele permite que o cálculo continue enquanto sinaliza resultados específicos como inválidos.
Uma variante é sNaN
, que sinaliza em vez de permanecer em silêncio após cada operação. Esse é um valor de retorno útil quando um resultado inválido precisa interromper um cálculo para tratamento especial.
O comportamento dos operadores de comparação do Python pode ser um pouco surpreendente onde um NaN
está envolvido. Um teste de igualdade em que um dos operandos é um NaN
silencioso ou sinalizador sempre retorna False
(mesmo ao fazer Decimal('NaN')==Decimal('NaN')
), enquanto um teste de desigualdade sempre retorna True
. Uma tentativa de comparar dois decimais usando qualquer um dos operadores <
, <=
, >
ou >=
levantará o sinal InvalidOperation
se um dos operandos for um NaN
e retorna False
se esse sinal não for capturado. Observe que a especificação aritmética decimal geral não especifica o comportamento das comparações diretas; estas regras para comparações envolvendo a NaN
foram retiradas do padrão IEEE 854 (consulte a Tabela 3 na seção 5.7). Para garantir uma rígida conformidade com os padrões, use os métodos compare()
e compare-signal()
.
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 é informativo.
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-1000000026')
9.4.6. Trabalhando com threads¶
The getcontext()
function accesses a different Context
object for
each thread. Having separate thread contexts means that threads may make
changes (such as getcontext.prec=10
) without interfering with other threads.
Da mesma forma, a função setcontext()
atribui automaticamente seu destino à 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()
. . .
9.4.7. 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 = map(str, digits)
build, next = result.append, digits.pop
if sign:
build(trailneg)
for i in range(places):
build(next() if digits else '0')
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.
>>> 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.
>>> 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
9.4.8. Perguntas Frequentes sobre o 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 um aplicativo 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?
Q. O método quantize()
arredonda para um número fixo de casas decimais. Se a armadilha Inexact
estiver configurada, também será útil para validação:
>>> 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?
R. Algumas operações como adição, subtração e multiplicação por um número inteiro preservam automaticamente o ponto fixo. Outras operações, como divisão e multiplicação não inteira, alteram o número de casas decimais e precisam ser seguidas com uma etapa quantize()
:
>>> 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')
No desenvolvimento de aplicativos de ponto fixo, é conveniente definir funções para lidar com a etapa quantize()
:
>>> 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')
P. Existem várias maneiras de expressar o mesmo valor. Os números 200
, 200.000
, const:2E2 e 02E+4
têm todos o mesmo valor em várias precisões. Existe uma maneira de transformá-los em um único valor canônico reconhecível?
R. O método normalize()
mapeia todos os valores equivalentes para um único representativo:
>>> 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. Alguns valores decimais sempre são impressos com notação exponencial. Existe uma maneira de obter uma representação não exponencial?
R. Para alguns valores, a notação exponencial é a única maneira de expressar o número de casas significativas no coeficiente. Por exemplo, expressar 5.0E+3
como 5000
mantém o valor constante, mas não pode mostrar a significância de duas casa do original.
If an application does not care about tracking significance, it is easy to remove the exponent and trailing zeros, losing significance, but keeping the value unchanged:
def remove_exponent(d):
'''Remove exponent and trailing zeros.
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')
'''
return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
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')