algarismos significativos no módulo decimal
-
02-07-2019 - |
Pergunta
Então, eu decidi tentar resolver o meu física lição de casa, escrevendo alguns scripts python para resolver problemas para mim. Um problema que eu estou correndo em é que algarismos significativos nem sempre parecem sair corretamente. Por exemplo, este alças algarismos significativos corretamente:
from decimal import Decimal
>>> Decimal('1.0') + Decimal('2.0')
Decimal("3.0")
Mas isso não:
>>> Decimal('1.00') / Decimal('3.00')
Decimal("0.3333333333333333333333333333")
Assim, duas perguntas:
- Am I certo de que esta não é a quantidade esperada de dígitos significativos, ou que eu preciso para retocar em matemática significativa dígitos?
- Existe alguma maneira de fazer isso sem ter que definir a precisão decimal manualmente? Concedido, eu tenho certeza que posso usar numpy para fazer isso, mas eu só quero saber se há uma maneira de fazer isso com o módulo decimal por curiosidade.
Solução
Alterar o decimal de precisão trabalhando para 2 dígitos é não uma boa idéia, a menos que você absolutamente só vai realizar uma única operação.
Você deve sempre realizar cálculos em maior precisão do que o nível de significância, e apenas arredondar o resultado final. Se você executar uma longa sequência de cálculos e arredondar para o número de dígitos significativos em cada etapa, os erros se acumulam. O módulo decimal não sabe se qualquer operação particular é um em uma longa seqüência, ou o resultado final, por isso assume que ele não deve rodada mais do que o necessário. Idealmente seria usar precisão infinita, mas que é muito caro para que os desenvolvedores de Python resolvida por 28 dígitos.
Uma vez que você acabou de chegar ao resultado final, o que você provavelmente quer é quantize:
>>> (Decimal('1.00') / Decimal('3.00')).quantize(Decimal("0.001")) Decimal("0.333")
Você tem que manter o controle de significado manualmente. Se você quiser rastreamento significado automática, você deve usar aritmética de intervalo. Existem algumas bibliotecas disponíveis para Python, incluindo pyinterval e mpmath (que suporta precisão arbitrária). Também é simples de implementar aritmética intervalo com a biblioteca decimal, uma vez que suporta dirigido arredondamento.
Você também pode querer ler o Decimal Aritmética FAQ: É a aritmética decimal 'significado' aritmética?
Outras dicas
Decimals não vai jogar fora casas decimais assim. Se você realmente quiser precisão limite para 2 D.P. tente
decimal.getcontext().prec=2
EDIT:. Você pode, alternativamente, chamar quantize () cada vez que você multiplicar ou dividir (adição e subtração irá preservar os 2 dps)
Só por curiosidade ... é necessário utilizar o módulo decimal? Por que não ponto flutuante com uma significativa figuras arredondamento de números quando você está pronto para vê-los? Ou você está tentando manter o controle das figuras significativas da computação (como quando você tem que fazer uma análise de erro de um resultado, calculando o erro calculado em função das incertezas que entraram no cálculo)? Se você quer uma função de arredondamento que rounds da esquerda do número em vez do direito, tente:
def lround(x,leadingDigits=0):
"""Return x either as 'print' would show it (the default)
or rounded to the specified digit as counted from the leftmost
non-zero digit of the number, e.g. lround(0.00326,2) --> 0.0033
"""
assert leadingDigits>=0
if leadingDigits==0:
return float(str(x)) #just give it back like 'print' would give it
return float('%.*e' % (int(leadingDigits),x)) #give it back as rounded by the %e format
Os números vai olhar direito quando você imprimi-los ou convertê-los para cordas, mas se você está trabalhando no prompt e não imprimi-los explicitamente que pode parecer um pouco estranho:
>>> lround(1./3.,2),str(lround(1./3.,2)),str(lround(1./3.,4))
(0.33000000000000002, '0.33', '0.3333')
defaults decimal para 28 lugares de precisão.
A única maneira de limitar o número de dígitos que retorna é alterando a precisão.
Se eu undertand Decimal corretamente, a "precisão" é o número de dígitos depois do ponto decimal no decimal notação .
Você parece querer outra coisa: o número de dígitos significativos. Essa é um a mais que o número de dígitos depois do ponto decimal no notação científica .
Eu estaria interessado em aprender sobre um módulo Python que faz significativas dígitos-Aware cálculos de ponto em ponto flutuante.
errada do que com o ponto flutuante?
>>> "%8.2e"% ( 1.0/3.0 )
'3.33e-01'
Foi projetada para cálculos de estilo científico com um número limitado de dígitos significativos.