Quero remover dígitos de um ponto flutuante para ter um número fixo de dígitos após o ponto, como:
1.923328437452 -> 1.923
Preciso dar saída como string para outra função, não imprimir.
Também quero ignorar os dígitos perdidos, não arredondá-los.
python
floating-point
Joan Venge
fonte
fonte
Respostas:
Primeiro, a função, para aqueles que querem apenas um código de copiar e colar:
Isso é válido no Python 2.7 e 3.1+. Para versões mais antigas, não é possível obter o mesmo efeito de "arredondamento inteligente" (pelo menos, não sem muitos códigos complicados), mas arredondar para 12 casas decimais antes do truncamento funcionará na maior parte do tempo:
Explicação
O núcleo do método subjacente é converter o valor em uma string com precisão total e, em seguida, cortar tudo além do número desejado de caracteres. A última etapa é fácil; pode ser feito com manipulação de string
ou o
decimal
móduloA primeira etapa, a conversão para uma string, é bastante difícil porque existem alguns pares de literais de ponto flutuante (ou seja, o que você escreve no código-fonte) que produzem a mesma representação binária e, ainda assim, devem ser truncados de forma diferente. Por exemplo, considere 0,3 e 0,29999999999999998. Se você escrever
0.3
em um programa Python, o compilador o codifica usando o formato de ponto flutuante IEEE na sequência de bits (assumindo um float de 64 bits)Este é o valor mais próximo de 0,3 que pode ser representado com precisão como um flutuador IEEE. Mas se você escrever
0.29999999999999998
em um programa Python, o compilador o traduzirá exatamente no mesmo valor . Em um caso, você pretendia que fosse truncado (para um dígito) como0.3
, enquanto no outro caso você pretendia que fosse truncado como0.2
, mas Python pode dar apenas uma resposta. Esta é uma limitação fundamental do Python, ou mesmo de qualquer linguagem de programação sem avaliação preguiçosa. A função de truncamento só tem acesso ao valor binário armazenado na memória do computador, não à string que você realmente digitou no código-fonte. 1Se você decodificar a sequência de bits de volta para um número decimal, novamente usando o formato de ponto flutuante IEEE de 64 bits, você obtém
portanto, uma implementação ingênua surgiria,
0.2
mesmo que provavelmente não seja o que você deseja. Para obter mais informações sobre o erro de representação de ponto flutuante, consulte o tutorial Python .É muito raro trabalhar com um valor de ponto flutuante tão próximo a um número redondo e, ainda assim, intencionalmente não igual a esse número redondo. Portanto, ao truncar, provavelmente faz sentido escolher a representação decimal "mais adequada" de todas as que podem corresponder ao valor na memória. O Python 2.7 e superior (mas não 3.0) inclui um algoritmo sofisticado para fazer exatamente isso , que podemos acessar por meio da operação de formatação de string padrão.
A única ressalva é que isso funciona como uma
g
especificação de formato, no sentido de que usa notação exponencial (1.23e+4
) se o número for grande ou pequeno o suficiente. Portanto, o método deve capturar esse caso e tratá-lo de maneira diferente. Existem alguns casos em que o uso de umaf
especificação de formato causa um problema, como tentar truncar3e-10
para 28 dígitos de precisão (produz0.0000000002999999999999999980
), e ainda não tenho certeza da melhor forma de lidar com isso.Se você realmente estiver trabalhando com
float
s que são muito próximos de números redondos, mas intencionalmente não iguais a eles (como 0,29999999999999998 ou 99,959999999999994), isso produzirá alguns falsos positivos, ou seja, arredondará números que você não deseja arredondar. Nesse caso, a solução é especificar uma precisão fixa.O número de dígitos de precisão a ser usado aqui não importa realmente, ele só precisa ser grande o suficiente para garantir que qualquer arredondamento executado na conversão de string não "aumente" o valor para sua bela representação decimal. Acho que
sys.float_info.dig + n + 2
pode ser suficiente em todos os casos, mas, se não,2
talvez seja necessário aumentar, e não faz mal fazê-lo.Em versões anteriores do Python (até 2.6 ou 3.0), a formatação do número de ponto flutuante era muito mais rudimentar e costumava produzir coisas como
Se esta é sua situação, se você não quiser usar "nice" representações decimais para truncagem, tudo o que você pode fazer (tanto quanto eu sei) é escolher um número de dígitos, menos do que o representável precisão total por um
float
, e volta a número com essa quantidade de dígitos antes de truncá-lo. Uma escolha típica é 12,mas você pode ajustar isso para se adequar aos números que está usando.
1 Bem ... eu menti. Tecnicamente, você pode instruir o Python a analisar novamente seu próprio código-fonte e extrair a parte correspondente ao primeiro argumento que você passa para a função de truncamento. Se esse argumento for um literal de ponto flutuante, você pode simplesmente cortá-lo com um certo número de casas após o ponto decimal e retornar isso. No entanto, essa estratégia não funciona se o argumento for uma variável, o que o torna bastante inútil. O seguinte é apresentado apenas para valor de entretenimento:
Generalizar isso para lidar com o caso em que você passa uma variável parece uma causa perdida, já que você teria que rastrear a execução do programa até encontrar o literal de ponto flutuante que deu à variável seu valor. Se houver um. A maioria das variáveis será inicializada a partir da entrada do usuário ou de expressões matemáticas, caso em que a representação binária é tudo o que existe.
fonte
applymap()
). Talvez haja uma maneira de tornar toda a operação mais eficiente, mas isso seria um assunto para outra questão.Consulte a documentação do Python sobre os tipos padrão . Você precisará rolar um pouco para baixo para chegar à função round. Essencialmente, o segundo número diz para quantas casas decimais ele deve ser arredondado.
fonte
O resultado de
round
é um float, então fique atento (o exemplo é do Python 2.6):Você ficará melhor ao usar uma string formatada:
fonte
round(1.23456, 3)
é1.235
e não é1.2350000000000001
fonte
2
, você terá um ponto decimal.
no final da string - não é realmente uma boa solução, eu acho.No meu prompt Python 2.7:
>>> int(1.923328437452 * 1000)/1000.0 1.923
fonte
Script python simples -
fonte
Isso deve funcionar. Ele deve fornecer o truncamento que você está procurando.
fonte
A maneira verdadeiramente pythônica de fazer isso é
ou mais curto:
Atualizar
Normalmente, o problema não está em truncar os próprios flutuadores, mas no uso impróprio de números flutuantes antes do arredondamento.
Por exemplo:
int(0.7*3*100)/100 == 2.09
.Se você for forçado a usar floats (digamos, você está acelerando seu código com
numba
), é melhor usar centavos como "representação interna" de preços: (70*3 == 210
) e multiplicar / dividir as entradas / saídas.fonte
int(0.7*3*100)/100 == 2.09
. Para onde foi meu 1 centavo?ImportError: cannot import name 'D'
, acredito que você queria fazer uma importação nomeada, não?Muitas das respostas dadas para esta pergunta estão completamente erradas. Eles arredondam os flutuadores (em vez de truncar) ou não funcionam para todos os casos.
Este é o principal resultado do Google quando procuro por 'Python truncate float', um conceito realmente direto e que merece respostas melhores. Eu concordo com Hatchkins que usar o
decimal
módulo é a maneira pítônica de fazer isso, então eu dou aqui uma função que acho que responde a pergunta corretamente e que funciona conforme o esperado para todos os casos.Como uma nota lateral, valores fracionários, em geral, não podem ser representados exatamente por variáveis binárias de ponto flutuante (veja aqui uma discussão sobre isso), e é por isso que minha função retorna uma string.
fonte
Eu fiz algo assim:
fonte
Você pode fazer:
testando:
fonte
Se você gosta de matemática, isso funciona para + cinco números:
fonte
Ao usar um pandas df, isso funcionou para mim
fonte
Só queria mencionar que o velho truque de "arredondar () com chão ()"
pode ser girado para tornar o piso () de redondo ()
Embora ambas as regras quebrem em torno de números negativos, usá-las é menos do que ideal:
fonte
int (16,5); isso dará um valor inteiro de 16, ou seja, trunc, não será capaz de especificar decimais, mas acho que você pode fazer isso
fonte
Esta é uma maneira fácil:
para num = 1,923328437452, resulta em 1,923
fonte
fonte
Uma função geral e simples de usar:
fonte
Existe uma solução alternativa fácil em python 3. Onde cortar eu defini com uma variável de ajuda decPlace para facilitar a adaptação.
Resultado:
Espero que ajude.
fonte
fonte
Variante curta e fácil
fonte
A maioria das respostas é muito complicada na minha opinião, que tal isso?
Simplesmente digitalizando o índice de '.' e truncar conforme desejado (sem arredondamento). Converta a string em flutuante como etapa final.
Ou, no seu caso, se você receber um float como entrada e quiser uma string como saída:
fonte
# divida e multiplique por 10 ** número de dígitos desejados
fonte
use numpy.round
fonte
Algo simples o suficiente para caber em uma compreensão de lista, sem bibliotecas ou outras dependências externas. Para Python> = 3.6, é muito simples escrever com strings f.
A ideia é permitir que a conversão de string faça o arredondamento para um lugar a mais do que você precisa e, em seguida, corte o último dígito.
Claro, há é arredondamento acontecendo aqui (nomeadamente para o quarto dígito), mas o arredondamento em algum momento é unvoidable. Caso a transição entre truncamento e arredondamento seja relevante, aqui está um exemplo um pouco melhor:
Bônus: remover zeros à direita
fonte
A ideia central apresentada aqui me parece ser a melhor abordagem para esse problema. Infelizmente, ele recebeu menos votos, enquanto a resposta posterior que tem mais votos não está completa (conforme observado nos comentários). Felizmente, a implementação a seguir fornece uma solução curta e completa para truncamento .
que deve cuidar de todos os casos extremos encontrados aqui e aqui .
fonte
Também sou um novato em python e depois de usar alguns pedaços aqui, ofereço meus dois centavos
str (int (time.time ())) pegará o período de tempo como int e o converterá em string e se unirá com ... str (datetime.now (). microssegundo) [: 3] que retorna apenas os microssegundos, converter para string e truncar para os primeiros 3 caracteres
fonte
fonte
Se você quer dizer ao imprimir, o seguinte deve funcionar:
fonte