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.
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.
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,
>>> 125650429603636838/(2**53)
13.949999999999999
>>> 234042163/(2**24)
13.949999988079071
>>> a = 13.946
>>> print(a)
13.946
>>> print("%.2f" % a)
13.95
>>> round(a,2)
13.949999999999999
>>> print("%.2f" % round(a, 2))
13.95
>>> print("{:.2f}".format(a))
13.95
>>> print("{:.2f}".format(round(a, 2)))
13.95
>>> print("{:.15f}".format(round(a, 2)))
13.949999999999999
Se você tiver apenas duas casas decimais (para exibir um valor da moeda, por exemplo), terá algumas opções melhores:
"%.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:
"{:.2f}".format(13.949999999999999)
Nota 1: o exemplo acima retorna uma string. Para obter o float, basta enrolar com float(...)
:
float("{:.2f}".format(13.949999999999999))
Nota 2: embrulhar com float()
não muda nada:
>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True
'{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:
>>> round(14.22222223, 2)
14.22
Confira a documentação .
round(2.16, 1)
dar 2.2
por python apenas oferecer uma truncate
func
>>> round(2.675, 2) 2.67
docs.python.org/2/tutorial/floatingpoint.html
Note 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:
a = 13.949999999999999
format(a, '.2f')
13.95
Isso produz um número flutuante como uma string arredondada para duas casas decimais.
Usar
print"{:.2f}".format(a)
ao invés de
print"{0:.2f}".format(a)
Porque o último pode levar a erros de saída ao tentar gerar várias variáveis (consulte os comentários).
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.)
>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'
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.
Experimente o código abaixo:
>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
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.
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() ...
ou Decimal -> 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 :
import random
from decimal import Decimal
for x in iter(random.random, None): # Verify FOREVER that rounding is fixed :-)
assert float(repr(x)) == x # Reversible repr() conversion.
assert float(Decimal(repr(x))) == x
assert len(repr(round(x, 10))) <= 12 # Smart decimal places in repr() after round.
if x >= 0.1: # Implicit rounding to 12 significant digits
assert str(x) == repr(round(x, 12)) # by str() is good enough for small errors.
y = 1000 * x # Decimal type is excessive for shopping
assert str(y) == repr(round(y, 12 - 3)) # in a supermaket with Python 2.7+ :-)
Veja as notas de versão Python 2.7 - Other Language Altera o quarto parágrafo:
Conversões entre números de ponto flutuante e seqüências de caracteres agora são arredondadas corretamente na maioria das plataformas. Essas conversões ocorrem em muitos lugares diferentes: str () em carros alegóricos e números complexos; os flutuadores e construtores complexos; formatação numérica; serializar e desserializar flutuadores e números complexos usando o
marshal
,pickle
ejson
módulos; análise de literais flutuantes e imaginários no código Python; e conversão decimal em flutuante.Relacionado a isso, o repr () de um número de ponto flutuante x agora retorna um resultado com base na menor string decimal que é garantida para arredondar de volta para x sob o arredondamento correto (com o modo de arredondamento de metade para metade). Anteriormente, fornecia uma string com base no arredondamento de x para 17 dígitos decimais.
Mais informações: A formatação float
anterior ao Python 2.7 era semelhante à atual numpy.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 ele np.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__
float
(precisão dupla) e normal round
, 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
contra b*a
. Obrigado pelos links - Nostalgia.
Com Python <3 (por exemplo, 2.6 ou 2.7), há duas maneiras de fazer isso.
# Option one
older_method_string = "%.9f" % numvar
# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)
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
numvar=12.456
, então "{:.2f}".format(numvar)
produz, 12.46
mas "{:2i}".format(numvar)
dá um erro e eu estou esperando 12
.
Você pode modificar o formato de saída:
>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
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:
>>> f'{a:.2f}'
Também funciona bem com exemplos mais longos, com operadores e sem necessidade de parênteses:
>>> print(f'Completed in {time.time() - start:.2f}s')
Você pode usar o operador de formato para arredondar o valor até duas casas decimais em python:
print(format(14.4499923, '.2f')) // output is 14.45
No Python 2.7:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
output
tem exatamente o mesmo valor que a
, então você pode ter escrito em print a
vez da print output
última linha.
13.95
. Mas o mesmo acontece print a
com esse valor específico de a
, 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:
>>> 0.1 0.10000000000000001
você pode ficar tentado a usar a
round()
função para reduzi-la ao dígito que você espera. Mas isso não faz diferença:>>> round(0.1, 1) 0.10000000000000001
O problema é que o valor do ponto flutuante binário armazenado para
“0.1”
já era a melhor aproximação binária possível de1/10
, portanto, tentar arredondá-lo novamente não pode torná-lo melhor: ele já .Outra consequência é que, uma vez que
0.1
não é exatamente1/10
, a soma de dez valores de0.1
pode não render exatamente1.0
:>>> sum = 0.0 >>> for i in range(10): ... sum += 0.1 ... >>> sum 0.99999999999999989
Uma alternativa e solução para seus problemas seria usar o decimal
módulo.
Como o @Matt apontou, o Python 3.6 fornece strings-f , e eles também podem usar parâmetros aninhados :
value = 2.34558
precision = 2
width = 4
print(f'result: {value:{width}.{precision}f}')
que exibirá result: 2.35
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 .
Use a combinação do objeto Decimal e do método round ().
Python 3.7.3
>>> from decimal import Decimal
>>> d1 = Decimal (13.949999999999999) # define a Decimal
>>> d1
Decimal('13.949999999999999289457264239899814128875732421875')
>>> d2 = round(d1, 2) # round to 2 decimals
>>> d2
Decimal('13.95')
Para corrigir o ponto flutuante em linguagens dinâmicas de tipo como Python e JavaScript, eu uso essa técnica
# For example:
a = 70000
b = 0.14
c = a * b
print c # Prints 980.0000000002
# Try to fix
c = int(c * 10000)/100000
print c # Prints 980
Você também pode usar decimal como a seguir:
from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
# Results in 6 precision -> Decimal('0.142857')
getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal('0.1428571428571428571428571429')
getcontext().prec = 6
funciona apenas para o escopo da função ou para todos os lugares?
from decimal import Decimal
def round_float(v, ndigits=2, rt_str=False):
d = Decimal(v)
v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
if rt_str:
return v_str
return Decimal(v_str)
Resultados:
Python 3.6.1 (default, Dec 11 2018, 17:41:10)
>>> round_float(3.1415926)
Decimal('3.14')
>>> round_float(3.1445926)
Decimal('3.14')
>>> round_float(3.1455926)
Decimal('3.15')
>>> round_float(3.1455926, rt_str=True)
'3.15'
>>> str(round_float(3.1455926))
'3.15'
Que tal uma função lambda como esta:
arred = lambda x,n : x*(10**n)//1/(10**n)
Dessa forma, você pode simplesmente fazer:
arred(3.141591657,2)
e pegue
3.14
É 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:
d.quantize(Decimal('0.01'))
resultará com Decimal('10000000.00')
def round_decimal(number, exponent='0.01'):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(exponent))
OU
def round_decimal(number, decimal_places=2):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(10) ** -decimal_places)
PS: crítica dos outros: a formatação não é arredondada.
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):
>>> import numpy as np
>>> value = 13.949999999999999
>>> resolution = 0.01
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
13.95
>>> resolution = 0.5
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
14.0
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 em float
ou simplesmente usá-lo round(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 o float
exemplo @szeitlin. Obrigado pelo seu comentário extra. (Desculpe, mas eu não te
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.
float = str(float)[:5]
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!