Como arredondar um valor flutuante (como 37,777779) para duas casas decimais (37,78) em C?
c
floating-point
decimal
Sakib Arifin
fonte
fonte
float
(edouble
) não são vírgulas flutuantes decimais - elas são vírgulas flutuantes binárias -, portanto, o arredondamento para as casas decimais não faz sentido. Você pode arredondar a saída, no entanto.Respostas:
Se você deseja arredondar o número apenas para fins de saída, a
"%.2f"
sequência de formatação é realmente a resposta correta. No entanto, se você realmente deseja arredondar o valor do ponto flutuante para cálculos adicionais, algo como o seguinte funciona:Observe que você pode escolher três regras de arredondamento diferentes: arredondar para baixo (ou seja, truncar após duas casas decimais), arredondar para o mais próximo e arredondar para cima. Normalmente, você deseja arredondar para o mais próximo.
Como vários outros apontaram, devido às peculiaridades da representação de ponto flutuante, esses valores arredondados podem não ser exatamente os valores decimais "óbvios", mas estarão muito próximos.
Para muito (muito!) Mais informações sobre arredondamento, e especialmente sobre regras de desempate para arredondar para o mais próximo, consulte o artigo da Wikipedia sobre Arredondamento .
fonte
doubles
alguma maneira? Parece não fazer o trabalho que eu quero :( (usandofloor
eceil
). #Usando % .2f em printf. Imprime apenas 2 casas decimais.
Exemplo:
Resultado:
fonte
float
alcance, poisval * 100
poderia estourar.Supondo que você esteja falando sobre o valor da impressão, as respostas de Andrew Coleson e AraK estão corretas:
Mas observe que, se você deseja arredondar o número para exatamente 37,78 para uso interno (por exemplo, comparar com outro valor), isso não é uma boa ideia, devido à maneira como os números de ponto flutuante funcionam: você normalmente não deseja fazer comparações de igualdade para ponto flutuante; em vez disso, use um valor-alvo +/- um valor sigma. Ou codifique o número como uma sequência com uma precisão conhecida e compare-a.
Veja o link na resposta de Greg Hewgill para uma pergunta relacionada , que também cobre por que você não deve usar ponto flutuante para cálculos financeiros.
fonte
printf("%.*f", (int)precision, (double)number);
Que tal agora:
fonte
Se você deseja gravar na string C:
fonte
Não existe uma maneira de arredondar de um
float
para outrofloat
porque o arredondadofloat
pode não ser representável (uma limitação dos números de ponto flutuante). Por exemplo, digamos que você arredonde 37.777779 para 37.78, mas o número representável mais próximo é 37.781.No entanto, você pode "arredondar" a
float
usando uma função de seqüência de caracteres de formato.fonte
float
a n casas decimais e esperar que o resultado sempre tenha n casas decimais. Você ainda receberá umfloat
, mas não o que você esperava.Além disso, se você estiver usando C ++, você pode apenas criar uma função como esta:
Em seguida, você pode emitir qualquer duplo
myDouble
comn
casas após o ponto decimal com código como este:fonte
Você ainda pode usar:
exemplo:
fonte
No C ++ (ou no C com conversão no estilo C), você pode criar a função:
Então
std::cout << showDecimals(37.777779,2);
produziria: 37.78.Obviamente, você realmente não precisa criar todas as 5 variáveis nessa função, mas eu as deixo lá para que você possa ver a lógica. Provavelmente existem soluções mais simples, mas isso funciona bem para mim - especialmente porque me permite ajustar o número de dígitos após a casa decimal conforme necessário.
fonte
Sempre use a
printf
família de funções para isso. Mesmo se você quiser obter o valor como flutuante, é melhor usá-losnprintf
para obter o valor arredondado como uma sequência e analisá-lo novamente comatof
:Digo isso porque a abordagem mostrada pela resposta atualmente mais votada e várias outras aqui - multiplicando por 100, arredondando para o número inteiro mais próximo e depois dividindo por 100 novamente - é falha de duas maneiras:
Para ilustrar o primeiro tipo de erro - a direção do arredondamento às vezes está errada - tente executar este programa:
Você verá esta saída:
Observe que o valor com o qual começamos era menor que 0,015 e, portanto, a resposta matematicamente correta ao arredondá-lo para 2 casas decimais é 0,01. Obviamente, 0,01 não é exatamente representável como um dobro, mas esperamos que nosso resultado seja o dobro mais próximo de 0,01. Usar
snprintf
nos dá esse resultado, mas usarround(100 * x) / 100
nos dá 0,02, o que está errado. Por quê? Porque100 * x
nos dá exatamente 1,5 como resultado. Multiplicar por 100 altera a direção correta para arredondar.Para ilustrar o segundo tipo de erro - o resultado, às vezes, é errado devido
* 100
e/ 100
não é realmente um inverso um do outro - podemos fazer um exercício semelhante com um número muito grande:Nosso número agora nem tem uma parte fracionária; é um valor inteiro, apenas armazenados com o tipo
double
. Então o resultado após o arredondamento deve ser o mesmo número com o qual começamos, certo?Se você executar o programa acima, verá:
Opa Nosso
snprintf
método retorna o resultado certo novamente, mas a abordagem de multiplicar, arredondar e dividir falha. Isso porque o valor matematicamente correta de8631192423766613.0 * 100
,863119242376661300.0
, não é exatamente representável como um duplo; o valor mais próximo é863119242376661248.0
. Quando você divide isso de volta por 100, obtém8631192423766612.0
- um número diferente do que você começou.Espero que seja uma demonstração suficiente de que o uso
roundf
para arredondar para um número de casas decimais está quebrado e que você deve usá-losnprintf
. Se isso parecer um truque horrível para você, talvez você fique tranquilo ao saber que é basicamente o que o CPython faz .fonte
Use
float roundf(float x)
."As funções arredondadas arredondam seu argumento para o valor inteiro mais próximo no formato de ponto flutuante, arredondando os casos até a metade do zero, independentemente da direção de arredondamento atual." C11dr §7.12.9.5
Dependendo da sua
float
implementação, os números que podem parecer a meio caminho não são. como ponto flutuante é tipicamente orientado para a base 2. Além disso, o arredondamento preciso para o mais próximo0.01
em todos os casos "na metade do caminho" é mais desafiador.Embora "1.115" esteja "no meio do caminho" entre 1.11 e 1.12, quando convertido para
float
, o valor é1.115000009537...
e não é mais "no meio do caminho", mas mais próximo do 1.12 e arredondado para o mais próximofloat
de1.120000004768...
"1.125" é "intermediário" entre 1.12 e 1.13, quando convertido para
float
, o valor é exatamente1.125
e é " intermediário ". Arredonda para 1,13 devido a vínculos com a regra par e arredonda para o mais próximofloat
de1.129999995232...
Embora "1.135" esteja "no meio do caminho" entre 1,13 e 1,14, quando convertido para
float
, o valor é1.134999990463...
e não é mais "no meio do caminho", mas mais próximo do 1,13 e arredondado para o mais próximofloat
de1.129999995232...
Se código usado
Apesar de "1.135" é "meio caminho" entre 1,13 e 1,14, quando convertido para
float
, o valor é1.134999990463...
e não é "meio caminho", mas mais perto de 1.13, mas incorretamente rodadas parafloat
de1.139999985695...
, devido à precisão mais limitada defloat
vs.double
. Esse valor incorreto pode ser visto como correto, dependendo das metas de codificação.fonte
Eu fiz essa macro para arredondar números flutuantes. Adicione-o no seu cabeçalho / sendo do arquivo
Aqui está um exemplo:
x é igual a 3,14 :)
fonte
Aqui
n
está o número de casas decimaisexemplo:
fonte
dval
for enorme 3) o estranhoif
/else
bloco em que você faz exatamente a mesma coisa em cada ramificação e 4) o uso excessivamente complicado desprintf
para criar o especificador de formato para uma segundasprintf
chamada; é mais simples usar.*
e passar o valor duplo e o número de casas decimais como argumentos para a mesmasprintf
chamada.Definição de código:
Resultados :
fonte
Deixe-me primeiro tentar justificar minha razão para adicionar mais uma resposta a esta pergunta. Em um mundo ideal, arredondar não é realmente um grande problema. No entanto, em sistemas reais, você pode precisar lidar com vários problemas que podem resultar em arredondamentos que podem não ser o que você espera. Por exemplo, você pode estar executando cálculos financeiros em que os resultados finais são arredondados e exibidos aos usuários como duas casas decimais; esses mesmos valores são armazenados com precisão fixa em um banco de dados que pode incluir mais de duas casas decimais (por várias razões; não há um número ideal de locais a serem mantidos ... depende de situações específicas que cada sistema deve suportar, por exemplo, itens minúsculos cujos preços são frações de um centavo por unidade); e, cálculos de ponto flutuante executados em valores em que os resultados são mais / menos epsilon. Venho enfrentando essas questões e desenvolvendo minha própria estratégia ao longo dos anos. Não vou afirmar que enfrentei todos os cenários ou tenho a melhor resposta, mas abaixo está um exemplo da minha abordagem até agora que supera esses problemas:
Suponha que 6 casas decimais sejam consideradas como precisão suficiente para cálculos em flutuadores / duplos (uma decisão arbitrária para a aplicação específica), usando a seguinte função / método de arredondamento:
O arredondamento para duas casas decimais para a apresentação de um resultado pode ser realizado da seguinte forma:
Pois
val = 6.825
, o resultado é6.83
o esperado.Pois
val = 6.824999
, o resultado é6.82
. Aqui, a suposição é que o cálculo resultou exatamente6.824999
e a sétima casa decimal é zero.Pois
val = 6.8249999
, o resultado é6.83
. A sétima casa decimal,9
nesse caso, faz com que aRound(val,6)
função dê o resultado esperado. Nesse caso, pode haver qualquer número de9
s à direita .Pois
val = 6.824999499999
, o resultado é6.83
. Arredondar para a oitava casa decimal como primeiro passo, ou sejaRound(val,8)
, cuida do único caso desagradável pelo qual um resultado calculado de ponto flutuante calcula6.8249995
, mas é representado internamente como6.824999499999...
.Finalmente, o exemplo da pergunta ...
val = 37.777779
resulta em37.78
.Essa abordagem pode ser mais generalizada como:
onde N é precisão a ser mantida para todos os cálculos intermediários em flutuadores / duplos. Isso funciona com valores negativos também. Não sei se essa abordagem é matematicamente correta para todas as possibilidades.
fonte
Código C simples para arredondar um número:
Isso produzirá:
fonte
... ou você pode fazer da maneira antiga, sem bibliotecas:
Isso, é claro, se você deseja remover as informações extras do número.
fonte
esta função pega o número e a precisão e retorna o número arredondado
ele converte o número do ponto flutuante em int, deslocando o ponto à esquerda e verificando a condição maior que cinco.
fonte