Preciso arredondar um flutuador para ser exibido em uma interface do usuário. Por exemplo, para uma figura significativa:
1234 -> 1000
0,12 -> 0,1
0,012 -> 0,01
0,062 -> 0,06
6253 -> 6000
1999 -> 2000
Existe uma boa maneira de fazer isso usando a biblioteca Python, ou eu mesmo tenho que escrever?
Respostas:
Você pode usar números negativos para arredondar números inteiros:
Portanto, se você precisar apenas do dígito mais significativo:
Você provavelmente terá que cuidar de transformar float em número inteiro se for maior que 1.
fonte
log10
é a única maneira adequada de determinar como arredondá-lo.log10(abs(x))
, caso contrário, os números negativos irá falhar (E tratarx == 0
separadamente, é claro)round_to_n = lambda x, n: x if x == 0 else round(x, -int(math.floor(math.log10(abs(x)))) + (n - 1))
protegex==0
ex<0
obrigado @RoyHyunjinHan e @TobiasKienzler. Não protegidos contra indefinido como math.inf, ou lixo como Nenhum etc% g na formatação de string formatará um float arredondado para um número significativo de números. Às vezes, ele usa a notação científica 'e'; portanto, converta a string arredondada de volta em um float e, em seguida, através da formatação da string% s.
fonte
0.075
para0.08
. Ele retorna em0.07
vez disso.round_sig = lambda f,p: float(('%.' + str(p) + 'e') % f)
permite ajustar o número de dígitos significativos!Se você quiser ter um número decimal diferente de 1 (caso contrário, o mesmo que o Evgeny):
fonte
0.075
para0.08
. Ele retorna em0.07
vez disso.round
. docs.python.org/2/tutorial/floatingpoint.html#tut-fp-issuesEsta solução é diferente de todas as outras porque:
Para um número arbitrário
n
de números significativos, você pode usar:Teste:
Nota : com esta solução, não é possível adaptar dinamicamente o número de figuras significativas a partir da entrada, porque não existe uma maneira padrão de distinguir números com diferentes números de zeros à direita (
3.14 == 3.1400
). Se você precisar fazer isso, serão necessárias funções não padrão, como as fornecidas no pacote de precisão .fonte
:g
formatador que preserva números inteiros.2000.0
sugere 5 dígitos significativos, portanto é necessário{:g}
repetir.) Em geral, números inteiros com zeros à direita são ambíguos em relação a números significativos, a menos que alguma técnica (como overline acima da última significativa) seja usada.Eu criei o pacote com precisão que faz o que você deseja. Ele permite que você forneça números mais ou menos significativos.
Ele também gera notação padrão, científica e de engenharia com um número especificado de números significativos.
Na resposta aceita, há a linha
Na verdade, isso especifica 8 sig figs. Para o número 1234243, minha biblioteca exibe apenas uma figura significativa:
Ele também arredondará o último número significativo e poderá escolher automaticamente qual notação usar se uma notação não for especificada:
fonte
lambda x: to_precision(x, 2)
Para arredondar um número inteiro para 1 figura significativa, a idéia básica é convertê-lo em um ponto flutuante com 1 dígito antes do ponto e arredondá-lo e depois convertê-lo novamente em seu tamanho inteiro original.
Para fazer isso, precisamos conhecer a maior potência de 10 a menos que o número inteiro. Podemos usar o piso da função log 10 para isso.
fonte
Para responder diretamente à pergunta, aqui está minha versão usando a nomeação da função R :
Meu principal motivo para postar esta resposta são os comentários reclamando que "0,075" arredonda para 0,07 em vez de 0,08. Isso se deve, como apontado por "Iniciante C", a uma combinação de aritmética de ponto flutuante com precisão finita e uma representação de base 2 . O número mais próximo a 0,075 que pode realmente ser representado é um pouco menor; portanto, o arredondamento sai de maneira diferente do que você pode esperar ingenuamente.
Observe também que isso se aplica a qualquer uso de aritmética de ponto flutuante não decimal, por exemplo, C e Java têm o mesmo problema.
Para mostrar com mais detalhes, pedimos ao Python que formate o número no formato "hexadecimal":
o que nos dá:
0x1.3333333333333p-4
. A razão para fazer isso é que a representação decimal normal geralmente envolve arredondamentos e, portanto, não é como o computador "vê" o número. Se você não está acostumado a este formato, um par de referências úteis são os docs Python eo padrão C .Para mostrar como esses números funcionam um pouco, podemos voltar ao nosso ponto de partida fazendo:
que deve ser impresso
0.075
.16**13
é porque existem 13 dígitos hexadecimais após o ponto decimal e2**-4
porque os expoentes hexadecimais são base-2.Agora, temos uma idéia de como os carros alegóricos são representados. Podemos usar o
decimal
módulo para fornecer mais precisão, mostrando o que está acontecendo:dando:
0.07499999999999999722444243844
e esperançosamente explicando por queround(0.075, 2)
avalia0.07
fonte
0.074999999999999999
, o que esperaria obter nesse caso?Espero ter o melhor de todas as respostas acima (menos poder colocá-lo como uma linha lambda;)). Ainda não explorou, sinta-se à vontade para editar esta resposta:
fonte
Modifiquei a solução da indgar para lidar com números negativos e números pequenos (incluindo zero).
fonte
x == 0
? Se você gosta de uma frase, apenasreturn 0 if x==0 else round(...)
.0.970 == 0.97
). Eu acho que você poderia usar algumas das outras soluções de impressão, comof'{round_sig(0.9701, sig=3):0.3f}'
se você quiser imprimir o zero.Se você deseja arredondar sem envolver cordas, o link que encontrei enterrado nos comentários acima:
http://code.activestate.com/lists/python-tutor/70739/
me parece melhor. Então, quando você imprime com qualquer descritor de formatação de sequência, obtém uma saída razoável e pode usar a representação numérica para outros fins de cálculo.
O código no link é de três linhas: def, doc e return. Ele tem um bug: você precisa verificar se há logaritmos explosivos. Isso é fácil. Compare a entrada com
sys.float_info.min
. A solução completa é:Ele funciona para qualquer valor numérico escalar e n pode ser um
float
se você precisar alterar a resposta por algum motivo. Você pode realmente empurrar o limite para:sem provocar um erro, se por algum motivo você estiver trabalhando com valores minúsculos.
fonte
Não consigo pensar em nada que possa resolver isso imediatamente. Mas é razoavelmente bem tratado para números de ponto flutuante.
Inteiros são mais complicados. Eles não são armazenados como base 10 na memória, portanto lugares significativos não são uma coisa natural a se fazer. É bastante trivial de implementar uma vez que eles são uma string.
Ou para números inteiros:
Se você deseja criar uma função que lida com qualquer número, minha preferência seria convertê-los em strings e procurar uma casa decimal para decidir o que fazer:
Outra opção é verificar o tipo. Isso será muito menos flexível e provavelmente não funcionará bem com outros números, como
Decimal
objetos:fonte
A resposta postada foi a melhor disponível quando fornecida, mas possui várias limitações e não produz números significativos tecnicamente corretos.
numpy.format_float_positional suporta diretamente o comportamento desejado. O fragmento a seguir retorna o float
x
formatado para 4 números significativos, com a notação científica suprimida.fonte
print(*[''.join([np.format_float_positional(.01*a*n,precision=2,unique=False,fractional=False,trim='k',pad_right=5) for a in [.99, .999, 1.001]]) for n in [8,9,10,11,12,19,20,21]],sep='\n')
. Eu não verifiquei o próprio Dragon4.Encontrei isso também, mas precisava de controle sobre o tipo de arredondamento. Assim, escrevi uma função rápida (veja o código abaixo) que pode levar em consideração o valor, o tipo de arredondamento e os dígitos significativos desejados.
fonte
Usando a formatação de novo estilo do python 2.6+ (como% -style está obsoleto):
No python 2.7+, você pode omitir os
0
s principais .fonte
Esta função executa uma rodada normal se o número for maior que 10 ** (- posições_ decimais); caso contrário, adiciona mais casas decimais até que o número de casas decimais significativas seja atingido:
Espero que ajude.
fonte
https://stackoverflow.com/users/1391441/gabriel , o seguinte endereço aborda sua preocupação com rnd (0,075, 1)? Advertência: retorna valor como um float
fonte
Isso retorna uma string, para que resultados sem partes fracionárias e pequenos valores que, de outra forma, aparecessem na notação E sejam mostrados corretamente:
fonte
Dada uma pergunta tão bem respondida, por que não adicionar outra
Isso combina com minha estética um pouco melhor, embora muitos dos itens acima sejam comparáveis
Isso funciona para números individuais e matrizes numpy e deve funcionar bem para números negativos.
Há uma etapa adicional que poderíamos adicionar - np.round () retorna um número decimal, mesmo que arredondado seja um número inteiro (por exemplo, para significantFigures = 2, podemos esperar voltar -460, mas obtemos -460,0). Podemos adicionar esta etapa para corrigir isso:
Infelizmente, esta etapa final não funcionará para uma série de números - deixarei isso para você, querido leitor, para descobrir se você precisa.
fonte
O pacote / biblioteca sigfig cobre isso. Após a instalação, você pode fazer o seguinte:
fonte
fonte