Eu quero a
ser arredondado para 13,95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
A round
função não funciona da maneira que eu esperava.
python
floating-point
rounding
precision
ShadowRanger
fonte
fonte
Respostas:
Você está enfrentando o problema antigo com números de ponto flutuante que nem todos os números podem ser representados exatamente. A linha de comando está apenas mostrando o formulário completo de ponto flutuante da memória.
Com a representação de ponto flutuante, sua versão arredondada é o mesmo número. Como os computadores são binários, eles armazenam números de ponto flutuante como um número inteiro e o dividem por uma potência de dois, para que 13,95 sejam representados de maneira semelhante a 125650429603636838 / (2 ** 53).
Os números de precisão dupla têm 53 bits (16 dígitos) de precisão e os flutuadores regulares têm 24 bits (8 dígitos) de precisão. O tipo de ponto flutuante no Python usa precisão dupla para armazenar os valores.
Por exemplo,
Se você tiver apenas duas casas decimais (para exibir um valor da moeda, por exemplo), terá algumas opções melhores:
fonte
"%.2f" % round(a,2)
você pode colocar em não só no printf, mas também em tais coisas comostr()
float
) é apenas a aproximação mais próxima disponível do número decimal (que você conhece como ser humano). Não existe um valor binário (finitamente representável) como 0,245. Simplesmente não existe e matematicamente não pode existir. O valor binário mais próximo de 0,245 é um pouco menor que 0,245; portanto, naturalmente é arredondado para baixo. Da mesma forma, não existe 0,225 em binário, mas o valor binário mais próximo de 0,225 é um pouco maior que 0,225, então, naturalmente, ele é arredondado.Decimal
, e essa foi uma das soluções apresentadas nesta resposta. A outra era converter suas quantidades em número inteiro e usar aritmética de número inteiro. Ambas as abordagens também apareceram em outras respostas e comentários.Existem novas especificações de formato, mini-idioma de especificação de formato de string :
Você pode fazer o mesmo que:
Nota 1: o exemplo acima retorna uma string. Para obter o float, basta enrolar com
float(...)
:Nota 2: embrulhar com
float()
não muda nada:fonte
'{0:,.2f}'.format(1333.949999999)
quais impressões'1,333.95'
.float()
;float("{0:.2f}".format(13.9499999))
f"Result is {result:.2f}"
O built-in
round()
funciona bem no Python 2.7 ou posterior.Exemplo:
Confira a documentação .
fonte
round(2.16, 1)
dar2.2
por python apenas oferecer umatruncate
func>>> round(2.675, 2) 2.67
docs.python.org/2/tutorial/floatingpoint.htmlNote The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float.
Eu sinto que a abordagem mais simples é usar a
format()
função.Por exemplo:
Isso produz um número flutuante como uma string arredondada para duas casas decimais.
fonte
Usar
ao invés de
Porque o último pode levar a erros de saída ao tentar gerar várias variáveis (consulte os comentários).
fonte
A maioria dos números não pode ser representada exatamente em carros alegóricos. Se você deseja arredondar o número, porque é isso que sua fórmula ou algoritmo matemático exige, você deve usar o arredondamento. Se você deseja restringir a exibição a uma certa precisão, nem use round e apenas formate-a como essa string. (Se você deseja exibi-lo com algum método alternativo de arredondamento e houver toneladas, misture as duas abordagens.)
E, por último, embora talvez o mais importante, se você deseja matemática exata , não deseja carros alegóricos. O exemplo usual é lidar com dinheiro e armazenar 'centavos' como um número inteiro.
fonte
Experimente o código abaixo:
fonte
round
função em primeiro lugar. Por outro lado, como essa solução ainda usa ponto flutuante, o problema original do OP permanece, mesmo para a versão "corrigida" dessa "solução".round
função (que foi usada na pergunta).round()
não funcionar como o OP mencionado.TLDR;)
O problema de arredondamento de entrada / saída foi resolvido definitivamente pelo Python 2.7.0 e 3.1 .
Um número arredondado corretamente pode ser convertido reversivelmente para frente e para trás:
str -> float() -> repr() -> float() ...
ouDecimal -> float -> str -> Decimal
Um tipo decimal não é mais necessário para armazenamento.
(Naturalmente, pode ser necessário arredondar um resultado da adição ou subtração de números arredondados para eliminar os erros acumulados no último bit. Uma aritmética decimal explícita ainda pode ser útil, mas uma conversão em string por
str()
(ou seja, arredondar para 12 dígitos válidos) ) é bom o suficiente geralmente se não for necessária precisão extrema ou número extremo de operações aritméticas sucessivas.)Teste infinito :
Documentação
Veja as notas de versão Python 2.7 - Other Language Altera o quarto parágrafo:
A questão relacionada
Mais informações: A formatação
float
anterior ao Python 2.7 era semelhante à atualnumpy.float64
. Ambos os tipos usam a mesma precisão dupla IEEE 754 de 64 bits com mantissa de 52 bits. Uma grande diferença é que elenp.float64.__repr__
é formatado frequentemente com um número decimal excessivo, para que nenhum bit possa ser perdido, mas não existe um número IEEE 754 válido entre 13.949999999999999 e 13.950000000000001. O resultado não é bom e a conversão é formatada para que cada dígito seja importante; a sequência é sem lacunas e a conversão é reversível. Simplesmente: se você tiver um número numpy.float64, converta-o em float normal para poder ser formatado para humanos, não para processadores numéricos; caso contrário, nada mais será necessário com o Python 2.7+.repr(float(number_as_string))
não é reversível com numpy. Por outro lado:float.__repr__
fonte
float
(precisão dupla) e normalround
, não sobre numpy.double e sua conversão em string. O arredondamento simples do Python realmente não pode ser melhor do que no Python 2.7. A maioria das respostas foi escrita antes da versão 2.7, mas elas estão obsoletas, apesar de serem muito boas originalmente. Esta é a razão da minha resposta.1
, exceto durante o "underflow gradual".a*b
contrab*a
. Obrigado pelos links - Nostalgia.Com Python <3 (por exemplo, 2.6 ou 2.7), há duas maneiras de fazer isso.
Mas observe que para versões do Python acima de 3 (por exemplo, 3,2 ou 3,3), a opção dois é preferida .
Para obter mais informações sobre a opção dois, sugiro este link sobre formatação de string na documentação do Python .
E para obter mais informações sobre a opção um, este link será suficiente e terá informações sobre os vários sinalizadores .
Referência: converta o número do ponto flutuante em uma certa precisão e copie para a string
fonte
numvar=12.456
, então"{:.2f}".format(numvar)
produz,12.46
mas"{:2i}".format(numvar)
dá um erro e eu estou esperando12
.Você pode modificar o formato de saída:
fonte
Ninguém aqui parece ter mencionado isso ainda, então deixe-me dar um exemplo no formato f-string / template-string do Python 3.6, que eu acho lindamente elegante:
Também funciona bem com exemplos mais longos, com operadores e sem necessidade de parênteses:
fonte
Você pode usar o operador de formato para arredondar o valor até duas casas decimais em python:
fonte
No Python 2.7:
fonte
output
tem exatamente o mesmo valor quea
, então você pode ter escrito emprint a
vez daprint output
última linha.13.95
. Mas o mesmo aconteceprint a
com esse valor específico dea
, no Python 2.7, então não está realmente claro qual era o objetivo da etapa de formatação.a == output
o código que mostra? DáTrue
para mim, e suspeito que também faz para você.O tutorial do Python possui um apêndice chamado Aritmética de ponto flutuante: problemas e limitações . Leia-o. Ele explica o que está acontecendo e por que o Python está fazendo o seu melhor. Tem até um exemplo que corresponde ao seu. Deixe-me citar um pouco:
Uma alternativa e solução para seus problemas seria usar o
decimal
módulo.fonte
Como o @Matt apontou, o Python 3.6 fornece strings-f , e eles também podem usar parâmetros aninhados :
que exibirá
result: 2.35
fonte
Ele está fazendo exatamente o que você pediu e está funcionando corretamente. Leia mais sobre confusão de ponto flutuante e talvez tente objetos decimais .
fonte
Use a combinação do objeto Decimal e do método round ().
fonte
Para corrigir o ponto flutuante em linguagens dinâmicas de tipo como Python e JavaScript, eu uso essa técnica
Você também pode usar decimal como a seguir:
fonte
getcontext().prec = 6
funciona apenas para o escopo da função ou para todos os lugares?Resultados:
fonte
fonte
Que tal uma função lambda como esta:
Dessa forma, você pode simplesmente fazer:
e pegue
fonte
É simples como 1,2,3:
usar decimal módulo para aritmética rápida do ponto flutuante decimal corretamente arredondado:
d = decimal (10000000.0000009)
para obter arredondamentos:
resultará com
Decimal('10000000.00')
OU
PS: crítica dos outros: a formatação não é arredondada.
fonte
Para arredondar um número para uma resolução, a melhor maneira é a seguinte, que pode funcionar com qualquer resolução (0,01 para duas casas decimais ou até outras etapas):
fonte
numpy.round
exatidão / precisão. Portanto, é necessário defini-lo como int antes da multiplicação com resolução. Eu atualizei o código. Obrigado por isso!numpy.float64
resultado de np.round emfloat
ou simplesmente usá-loround(value, 2)
. Não existe um número IEEE 754 válido entre 13.949999999999999 (= 1395 / 100.) e 3.950000000000001 (= 1395 * .01). Por que você acha que seu método é o melhor? O valor original 13.949999999999999289 (= value = round (value, 2)) é ainda mais exato que o 13.95000000000000178 (impresso por np.float96). Mais informações também para numpy agora são adicionadas à minha resposta, que você provavelmente recebeu voto por engano. Não se tratava de numpy originalmente.int
você também pode usar ofloat
exemplo @szeitlin. Obrigado pelo seu comentário extra. (Desculpe, mas eu não telambda x, n: int (x * 10 n + .5) / 10 n trabalha há muitos anos para mim em vários idiomas.
fonte
O método que eu uso é o de cortar fatias. É relativamente rápido e simples.
Primeiro, converta o flutuador em uma string, e escolha o comprimento que você deseja que seja.
Na linha única acima, convertemos o valor em uma string e mantivemos a string apenas nos quatro primeiros dígitos ou caracteres (inclusive).
Espero que ajude!
fonte