Eu continuo tropeçando nos especificadores de formato para a família de funções printf (). O que eu quero é poder imprimir um double (ou float) com um número máximo de dígitos após a vírgula decimal. Se eu usar:
printf("%1.3f", 359.01335);
printf("%1.3f", 359.00999);
eu recebo
359.013
359.010
Em vez do desejado
359.013
359.01
Alguém pode me ajudar?
Respostas:
Isso não pode ser feito com os
printf
especificadores de formato normal . O mais próximo que você poderia chegar seria:mas o ".6" é a largura numérica total, então
quebra.
O que você pode fazer é transferir
sprintf("%.20g")
o número para um buffer de string e manipular a string para ter apenas N caracteres após o ponto decimal.Supondo que seu número esteja na variável num, a função a seguir removerá todos, exceto os primeiros
N
decimais e, em seguida, removerá os zeros à direita (e o ponto decimal se todos fossem zeros).Se você não estiver satisfeito com o aspecto de truncamento (que se transformaria
0.12399
em, em0.123
vez de arredondá-lo0.124
), pode usar os recursos de arredondamento já fornecidos porprintf
. Você só precisa analisar o número de antemão para criar dinamicamente as larguras e usá-las para transformar o número em uma string:Todo o ponto de
nDecimals()
, neste caso, é trabalhar corretamente as larguras de campo, em seguida, formatar o número usando uma seqüência de formato com base nisso. O equipamento de testemain()
mostra isso em ação:Depois de ter o valor arredondado corretamente, você pode mais uma vez passá-lo para
morphNumericString()
para remover os zeros finais simplesmente alterando:para dentro:
(ou chamando
morphNumericString
no final denDecimals
, mas, nesse caso, provavelmente combinaria os dois em uma função), e você terminaria com:fonte
.
Em alguns locais, a casa decimal é na verdade uma,
vírgula.atof
retornar o mesmo valor.0.10000000000000000555
será0.1
quando retirado. O problema pode surgir se você tiver um valor ligeiramente abaixo, como se a representação mais próxima de42.1
fosse42.099999999314159
. Se você realmente quiser lidar com isso, provavelmente precisará arredondar com base no último dígito removido, em vez de truncar.printf
funções semelhantes a-como elas já suportam parâmetros dinâmicos (*
caractere especial): por exemplo,printf("%*.*f", total, decimals, x);
gera um número com o comprimento total do campo especificado dinamicamente e decimais.Para se livrar dos zeros à direita, você deve usar o formato "% g":
Depois que a questão foi esclarecida um pouco, suprimir zeros não é a única coisa que foi feita, mas também foi necessário limitar a saída a três casas decimais. Acho que isso não pode ser feito apenas com strings de formato sprintf. Como Pax Diablo apontou, a manipulação das cordas seria necessária.
fonte
Gosto da resposta da R. ligeiramente ajustada:
'1000' determina a precisão.
Potência para o arredondamento de 0,5.
EDITAR
Ok, esta resposta foi editada algumas vezes e eu perdi a noção do que estava pensando há alguns anos (e originalmente não preenchia todos os critérios). Portanto, aqui está uma nova versão (que preenche todos os critérios e trata os números negativos corretamente):
E os casos de teste:
E o resultado dos testes:
Agora, todos os critérios foram atendidos:
Infelizmente, esta resposta é de duas linhas, pois
sprintf
não retorna a string.fonte
Eu procuro a string (começando mais à direita) para o primeiro caractere no intervalo
1
para9
(valor ASCII49
-57
) entãonull
(definido para0
) cada caractere à direita dele - veja abaixo:fonte
Que tal algo assim (pode ter erros de arredondamento e problemas de valor negativo que precisam de depuração, deixado como um exercício para o leitor):
É ligeiramente programático, mas pelo menos não obriga você a fazer qualquer manipulação de string.
fonte
Uma solução simples, mas que dá conta do recado, atribui um comprimento e uma precisão conhecidos e evita a chance de entrar no formato exponencial (o que é um risco quando você usa% g):
Adicione ou remova "outros" se quiser um máximo de 2 decimais; 4 decimais; etc.
Por exemplo, se você quiser 2 casas decimais:
Se você deseja especificar a largura mínima para manter os campos alinhados, aumente conforme necessário, por exemplo:
Você também pode converter isso em uma função em que passa a largura desejada do campo:
fonte
d = 0.0001
: entãofloor(d)
é0
, então a diferença é maior que 0,000001, entãoDoubleEquals
é falso, então não usará o"%.0f"
especificador: você verá zeros à direita de"%*.2f"
ou"%*.3f"
. Portanto, não responde à pergunta.Encontrei problemas em algumas das soluções postadas. Eu montei isso com base nas respostas acima. Parece funcionar para mim.
fonte
Algumas das soluções mais votadas sugerem o
%g
especificador de conversão deprintf
. Isso está errado porque há casos em%g
que produzirá notação científica. Outras soluções usam matemática para imprimir o número desejado de dígitos decimais.Acho que a solução mais fácil é usar
sprintf
com o%f
especificador de conversão e remover manualmente os zeros à direita e possivelmente um ponto decimal do resultado. Aqui está uma solução C99:Observe que os caracteres usados para dígitos e o separador decimal dependem do local atual. O código acima assume uma localidade C ou inglês dos EUA.
fonte
Aqui está minha primeira tentativa de resposta:
Bugs conhecidos: Possível estouro de buffer dependendo do formato. E se "." está presente por outro motivo que não% f pode ocorrer um resultado errado.
fonte
Por que não fazer isso?
fonte
Ligeira variação acima:
Codifique aqui:
Ele ainda tem potencial para transbordar, então tome cuidado; P
fonte
Eu diria que você deveria usar
printf("%.8g",value);
Se você usar
"%.6g"
, não obterá a saída desejada para alguns números como.32.230210, deve imprimir,32.23021
mas imprime32.2302
fonte
Seu código é arredondado para três casas decimais devido ao ".3" antes de f
Portanto, se você arredondar a segunda linha para duas casas decimais, deverá alterá-la para:
Esse código produzirá os resultados desejados:
* Observe que isso pressupõe que você já tenha a impressão em linhas separadas; caso contrário, o seguinte irá impedi-la de imprimir na mesma linha:
O seguinte código-fonte do programa foi meu teste para esta resposta
fonte