Gostaria de arredondar no máximo duas casas decimais, mas apenas se necessário .
Entrada:
10
1.7777777
9.1
Resultado:
10
1.78
9.1
Como posso fazer isso em JavaScript?
javascript
rounding
decimal-point
stinkycheeseman
fonte
fonte
Number.EPSILON
. UseMath.round( num * 100 + Number.EPSILON ) / 100
.Number.EPSILON
aqui?Respostas:
Usar
Math.round(num * 100) / 100
Editar: para garantir coisas como 1.005 arredondadas corretamente, usamos
Math.round((num + Number.EPSILON) * 100) / 100
fonte
Math.round((num + 0.00001) * 100) / 100
. TenteMath.round((1.005 + 0.00001) * 100) / 100
eMath.round((1.0049 + 0.00001) * 100) / 100
Se o valor for um tipo de texto:
Se o valor for um número:
Há uma desvantagem de que valores como 1,5 fornecerão "1,50" como saída. Uma correção sugerida por @minitech:
Parece que
Math.round
é uma solução melhor. Mas não é! Em alguns casos, NÃO arredondará corretamente:O toFixed () também NÃO será arredondado corretamente em alguns casos (testado no Chrome v.55.0.2883.87)!
Exemplos:
Eu acho que isso ocorre porque o 1.555 é na verdade algo como o float 1.55499994 nos bastidores.
A solução 1 é usar um script com o algoritmo de arredondamento necessário, por exemplo:
https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview
NOTA: Esta não é uma solução universal para todos. Existem vários algoritmos de arredondamento diferentes, sua implementação pode ser diferente, depende de seus requisitos. https://en.wikipedia.org/wiki/Rounding
A solução 2 é evitar cálculos de front-end e extrair valores arredondados do servidor back-end.
fonte
parseFloat(number.toFixed(decimalPlaces));
@PerLundbergparseFloat("55.555").toFixed(2)
retorna"55.55"
no console do desenvolvedor do Chrome.Você pode usar
Eu encontrei isso no MDN . O caminho deles evita o problema com 1.005 mencionado .
fonte
+(val)
é o equivalente de coerção do usoNumber(val)
. Concatenar "e-2" a um número resultou em uma sequência que precisava ser convertida novamente em um número.roundToTwo(1.0049999999999999)
sai como 1,01 (inevitavelmente, desde então1.0049999999999999 == 1.005
). Parece-me que o float que você obtém se digitarnum = 1.005
'obviamente' deve 'arredondar para 1,00, porque o valor exato de num é menor que 1,005. Obviamente, também me parece que a string '1.005' 'obviamente' 'deve ser arredondada para 1.01. O fato de pessoas diferentes parecerem ter intuições diferentes sobre qual é o comportamento correto real aqui faz parte do motivo pelo qual é complicado.1.0049999999999999
e1.005
, portanto, por definição, eles são o mesmo número. Isso é chamado de corte desagradável.1.00499 < 1.005
estivertrue
,1.0049999999999999 < 1.005
avalia comofalse
.A resposta de MarkG é a correta. Aqui está uma extensão genérica para qualquer número de casas decimais.
Uso:
Teste de unidade:
fonte
function round(number, decimals) { return +(Math.round(number + "e+" + decimals) + "e-" + decimals); }
(-1.005).round(2) === -1
Você deveria usar:
Ninguém parece estar ciente de
Number.EPSILON
.Também vale a pena notar que isso não é uma esquisitice do JavaScript, como algumas pessoas declararam.
É assim que os números de ponto flutuante funcionam em um computador. Como 99% das linguagens de programação, o JavaScript não possui números de ponto flutuante caseiros ; depende da CPU / FPU para isso. Um computador usa binário e, em binário, não há números como
0.1
, mas uma mera aproximação binária para isso. Por quê? Pela mesma razão que 1/3 não pode ser escrito em decimal: seu valor é 0,33333333 ... com um infinito de três.Aqui vem
Number.EPSILON
. Esse número é a diferença entre 1 e o próximo número existente nos números de ponto flutuante de precisão dupla. É isso: não há número entre1
e 1 +Number.EPSILON
.EDITAR:
Conforme solicitado nos comentários, vamos esclarecer uma coisa: adicionar
Number.EPSILON
é relevante apenas quando o valor a arredondar é o resultado de uma operação aritmética, pois pode engolir algum delta de erro de ponto flutuante.Não é útil quando o valor vem de uma fonte direta (por exemplo: literal, entrada do usuário ou sensor).
EDIT (2019):
Como o @maganap e algumas pessoas apontaram, é melhor adicionar
Number.EPSILON
antes de multiplicar:EDIT (dezembro de 2019):
Ultimamente, uso uma função semelhante a esta para comparar números com reconhecimento de epsilon:
Meu caso de uso é uma afirmação + validação de dados que estou desenvolvendo há muitos anos.
De fato, no código que estou usando
ESPILON_RATE = 1 + 4 * Number.EPSILON
eEPSILON_ZERO = 4 * Number.MIN_VALUE
(quatro vezes o epsilon), porque quero um verificador de igualdade solto o suficiente para acumular erro de ponto flutuante.Até agora, parece perfeito para mim. Eu espero que isso ajude.
fonte
Math.round( (num + Number.EPSILON) * 100) / 100
.. Concordo também que este é o método certo para arredondar corretamente (embora não seja exatamente o que foi solicitado nesta pergunta).0.004999999999999999
o resultado de um erro de ponto flutuante composto e o resultado matematicamente correto provavelmente foi de 0,005. Se é uma leitura de um sensor? Não muito.Math.round(1.5)
= 2, masMath.round(-1.5)
= -1. Portanto, isso é perfeitamente consistente. Aqui -1 é maior que -2, assim como -1000 é maior que -1000,01. Não deve ser confundido com números absolutos maiores.Pode-se usar
.toFixed(NumberOfDecimalPlaces)
.fonte
+(1.005).toFixed(2)
que retorna1
ao invés de1.01
.Number(9).toFixed(2).replace(/0+$/, '')
=> "9."Esta questão é complicada.
Suponha que tenhamos uma função,
roundTo2DP(num)
que aceita float como argumento e retorna um valor arredondado para 2 casas decimais. O que cada uma dessas expressões deve avaliar?roundTo2DP(0.014999999999999999)
roundTo2DP(0.0150000000000000001)
roundTo2DP(0.015)
A resposta 'óbvia' é que o primeiro exemplo deve arredondar para 0,01 (porque é mais próximo de 0,01 do que 0,02), enquanto os outros dois devem arredondar para 0,02 (porque 0,01500000000000000000001 está mais próximo de 0,02 do que 0,01 e porque 0,015 está exatamente na metade do caminho eles e existe uma convenção matemática de que esses números são arredondados).
O problema, que você deve ter adivinhado, é que
roundTo2DP
não pode ser implementado para dar essas respostas óbvias, porque todos os três números passados para ele são o mesmo número . Os números binários de ponto flutuante IEEE 754 (o tipo usado pelo JavaScript) não podem representar exatamente a maioria dos números não inteiros e, portanto, todos os três literais numéricos acima são arredondados para um número de ponto flutuante válido nas proximidades. Esse número, por acaso, é exatamente0.01499999999999999944488848768742172978818416595458984375
que é mais próximo de 0,01 do que 0,02.
Você pode ver que todos os três números são iguais no console do navegador, no shell do nó ou em outro intérprete JavaScript. Basta compará-los:
Então, quando escrevo
m = 0.0150000000000000001
, o valor exato dom
qual acabo é mais próximo0.01
do que é0.02
. E, no entanto, se eu converterm
para uma String ...... recebo 0,015, que deve arredondar para 0,02, e que não é notavelmente o número de 56 casas decimais que eu disse anteriormente que todos esses números eram exatamente iguais a. Então, que magia negra é essa?
A resposta pode ser encontrada na especificação ECMAScript, na seção 7.1.12.1: ToString aplicada ao tipo Number . Aqui são estabelecidas as regras para converter algum número m em uma string. A parte da chave é o ponto 5, no qual um número inteiro s é gerado cujos dígitos serão usados na representação String de m :
A parte principal aqui é a exigência de que " k seja o menor possível". O que esse requisito equivale é um requisito que, dado um Número
m
, o valor deString(m)
deve ter o menor número possível de dígitos enquanto ainda satisfaz o requisito queNumber(String(m)) === m
. Como já sabemos disso0.015 === 0.0150000000000000001
, agora está claro por queString(0.0150000000000000001) === '0.015'
deve ser verdade.Obviamente, nenhuma dessas discussões respondeu diretamente o que
roundTo2DP(m)
deveria retornar. Sem
o valor exato for 0,01499999999999999944488848768742172978818416595458984375, mas sua representação de String for '0,015', qual é a resposta correta - matematicamente, praticamente, filosoficamente ou o que for - quando o arredondamos para duas casas decimais?Não existe uma resposta correta para isso. Depende do seu caso de uso. Você provavelmente deseja respeitar a representação String e arredondar para cima quando:
Por outro lado, você provavelmente quer respeitar o valor do ponto flutuante binário e arredondar para baixo quando o valor for de uma escala inerentemente contínua - por exemplo, se for uma leitura de um sensor.
Essas duas abordagens requerem código diferente. Para respeitar a representação String do número, podemos (com um pouco de código razoavelmente sutil) implementar nosso próprio arredondamento que atua diretamente na representação String, dígito por dígito, usando o mesmo algoritmo que você usaria na escola quando foram ensinados a arredondar números. Abaixo está um exemplo que respeita o requisito do OP de representar o número com 2 casas decimais "somente quando necessário" eliminando os zeros à direita após o ponto decimal; você pode, é claro, precisar ajustá-lo às suas necessidades precisas.
Exemplo de uso:
A função acima é provavelmente o que você deseja usar para evitar que os usuários assistam aos números digitados serem arredondados incorretamente.
(Como alternativa, você também pode tentar o biblioteca round10 , que fornece uma função de comportamento semelhante com uma implementação totalmente diferente.)
Mas e se você tiver o segundo tipo de Número - um valor extraído de uma escala contínua, onde não há razão para pensar que representações decimais aproximadas com menos casas decimais são mais precisas do que aquelas com mais? Nesse caso, nós não queremos respeitar a representação String, porque essa representação (conforme explicado na especificação) já é do tipo arredondada; não queremos cometer o erro de dizer "0,014999999 ... 375 arredonda para 0,015, que arredonda para 0,02, então 0,014999999 ... 375 arredonda para 0,02".
Aqui podemos simplesmente usar o
toFixed
método embutido . Observe que, chamandoNumber()
a String retornada portoFixed
, obtemos um Número cuja representação de String não possui zeros à direita (graças à maneira como o JavaScript calcula a representação de String de um Número, discutida anteriormente nesta resposta).fonte
roundStringNumberWithoutTrailingZeroes(362.42499999999995, 2)
. Resultado esperado (como em PHPecho round(362.42499999999995, 2)
):362.43
. Resultado real:362.42
round
oferece 362,43. Isso parece intuitivamente errado, já que 362.42499999999995 é menor que 362.425 (em matemática e em código -362.42499999999995 < 362.425
é verdade tanto em JS quanto em PHP). A resposta do PHP também não minimiza a distância entre os números de ponto flutuante original e arredondado, desde então362.43 - 362.42499999999995 > 362.42499999999995 - 362.42
. De acordo com php.net/manual/en/function.round.php , o PHPround
segue o padrão C99; Vou ter que me aventurar na terra de C para entender o que está acontecendo.Considere
.toFixed()
e.toPrecision()
:http://www.javascriptkit.com/javatutors/formatnumber.shtml
fonte
Um método de arredondamento preciso. Fonte: Mozilla
Exemplos:
fonte
Math.round10(3544.5249, -2)
retorna 3544,52 em vez de 3544,533544.5249
duas casas decimais é3544.52
(erro = 0,0049). Se fosse3544.53
, o erro seria 0,0051. Você está fazendo um arredondamento sucessivo, ou seja, Math.round10 (Math.round10 (3544.5249, -3), -2), que gera um erro de arredondamento maior e, portanto, não é desejável.number += 0.00011
Math.round10( Math.round10(3544.5249, -3) , -2)
Nenhuma das respostas encontradas aqui está correta . @stinkycheeseman pediu para arredondar , todos vocês arredondaram o número.
Para arredondar, use o seguinte:
fonte
Math.ceil(1.1 * 100)/100;
- ele retorna1.11
, porque o 1.1 * 100 está de110.00000000000001
acordo com os novos navegadores modernos Firefox, Chrome, Safari e Opera ... IE, à moda antiga, ainda pensa1.1*100=1100
.Math.ceil(num.toFixed(4) * 100) / 100
Math.ceil((1.1).toFixed(4) * 100) / 100
também retornará1.11
no Firefox, o problema / bug dos navegadores modernos é a multiplicação e as pessoas devem saber disso (trabalhei em um jogo de loteria dessa vez, por exemplo).Aqui está uma maneira simples de fazer isso:
Você pode ir em frente e criar uma função separada para fazer isso por você:
Então você simplesmente passaria o valor.
Você pode aprimorá-lo para arredondar para qualquer número arbitrário de casas decimais adicionando um segundo parâmetro.
fonte
fonte
+(0.015).toFixed(2) == 0.01
,.Para mim, Math.round () não estava dando a resposta correta. Achei que oFixed (2) funciona melhor. Abaixo estão exemplos de ambos:
fonte
1.005
.(1.005).toFixed(2)
ainda resulta em1.00
.Use esta função
Number(x).toFixed(2);
fonte
Number
novamente, se você não quer que ele voltou como uma string:Number(Number(x).toFixed(2));
Number
ligação não é necessária,x.toFixed(2)
funciona.(1).toFixed(2)
retorna1.00
, mas o questionador é necessário1
neste caso.1.005.toFixed(2)
rende"1"
quando deveria ser"1.01"
.2017
Basta usar código nativo
.toFixed()
Se você precisar ser rigoroso e adicionar dígitos, se necessário, ele poderá usar
replace
fonte
toFixed
sugerido apenas por várias respostas anos antes da sua, mas também não satisfaz a condição "somente se necessário" da pergunta;(1).toFixed(2)
dá"1.00"
onde o autor da pergunta desejou"1"
.Experimente esta solução leve :
fonte
return Number(x.toFixed(digits))
?.toFixed()
permite apenas números de qualquer maneira.round(1.005, 2)
e veja o resultado de em1
vez de1.01
.round(0.995, 2) => 0.99
;round(1.006, 2) => 1.01
;round(1.005, 2) => 1
Existem algumas maneiras de fazer isso. Para pessoas como eu, a variante do Lodash
Uso:
Se o seu projeto usa jQuery ou lodash, você também pode encontrar
round
método nas bibliotecas.Atualização 1
Eu removi a variante
n.toFixed(2)
, porque não está correta. Obrigado @ avalanche1fonte
Number.toFixed()
retornará uma string, mas com um símbolo de adição antes, o interpretador JS converterá a string em um número. Este é um açúcar de sintaxe.alert((+1234).toFixed(2))
mostra "1234.00".alert(+1234.toFixed(2))
jogaSyntaxError: identifier starts immediately after numeric literal
. Eu fico com a 1ª opção.362.42499999999995
. Resultado esperado (como em PHPecho round(362.42499999999995, 2)
):362.43
. Resultado real:362.42
Se você estiver usando a biblioteca lodash, poderá usar o método round da lodash como a seguir.
Por exemplo:
fonte
Desde o ES6, existe uma maneira 'adequada' (sem substituir as estáticas e criar soluções alternativas) para fazer isso usando toPrecision
então você pode simplesmente
parseFloat
e os zeros 'desaparecem'.No entanto, ele não resolve o 'problema de arredondamento 1.005' - pois é intrínseco ao modo como as frações flutuantes estão sendo processadas .
Se você estiver aberto para bibliotecas, poderá usar o bignumber.js
fonte
(1.005).toPrecision(3)
ainda retorna em1.00
vez de1.01
realmente.toPrecision
retorna uma string que altera o tipo de saída desejado..toPrecision
método, é uma especificidade de números de ponto flutuante (que são números em JS) - tente1.005 - 0.005
, ele retornará0.9999999999999999
.(1).toPrecision(3)
retorna '1,00', mas o questionador queria ter1
nesse caso.toPrecision
faz o formato, não o último, e não é uma resposta para a pergunta do OP, embora possa parecer relevante a princípio, ele erra muito. Consulte en.wikipedia.org/wiki/Significant_figures . Por exemploNumber(123.4).toPrecision(2)
retornos"1.2e+2"
eNumber(12.345).toPrecision(2)
retornos"12"
. Eu também concordo com o argumento de @ adamduren de que ele retorna uma string que não é desejável (não é um grande problema, mas não é desejável).MarkG e Lavamantis ofereceram uma solução muito melhor do que a que foi aceita. É uma pena que eles não recebam mais votos!
Aqui está a função que eu uso para resolver os problemas de decimais de ponto flutuante também baseados no MDN . É ainda mais genérico (mas menos conciso) do que a solução de Lavamantis:
Use-o com:
Comparado à solução da Lavamantis, podemos fazer ...
fonte
Isso pode ajudá-lo a:
para mais informações, você pode dar uma olhada neste link
Math.round (num) vs num.toFixed (0) e inconsistências do navegador
fonte
A abordagem mais fácil seria usar o toFixed e depois remover zeros à direita usando a função Number:
fonte
15.00
? Os números em JS não armazenam as casas decimais e qualquer exibição trunca automaticamente as casas decimais em excesso (quaisquer zeros no final).toFixed(2)
aqui 2 é o número de dígitos até o qual queremos arredondar esse número.fonte
Pode funcionar para você,
saber a diferença entre toFixed e round. Você pode dar uma olhada nas inconsistências Math.round (num) vs num.toFixed (0) e no navegador .
fonte
Caminho mais fácil:
+num.toFixed(2)
Ele o converte em uma sequência e depois volta para um número inteiro / float.
fonte
toFixed()
para 3. Assim seria+num.toFixed(3)
. Isso funciona da forma como é suposto, 1.005 é arredondado para 1,00, o que é igual a 1Aqui está um método de protótipo:
fonte
Use algo parecido com isto "parseFloat (parseFloat (value) .toFixed (2))"
fonte
Uma maneira de obter esse arredondamento apenas se necessário é usar Number.prototype.toLocaleString () :
Isso fornecerá exatamente a saída que você espera, mas como strings. Você ainda pode convertê-los novamente em números, se esse não for o tipo de dados que você espera.
fonte
toLocaleString
.Depois de executar várias iterações de todas as formas possíveis para obter uma precisão exata de arredondamento decimal, é claro que a solução mais precisa e eficiente é usar Number.EPSILON. Isso fornece uma verdadeira solução matemática para o problema da precisão matemática de ponto flutuante. Ele pode ser facilmente preenchido como mostrado aqui: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON para oferecer suporte a todos os últimos usuários restantes do IE (talvez seja necessário deve parar de fazer isso).
Adaptado da solução fornecida aqui: https://stackoverflow.com/a/48850944/6910392
Uma solução simples que fornece arredondamento decimal preciso, piso e teto, com uma variável de precisão opcional sem adicionar uma biblioteca inteira.
ATUALIZAÇÃO: Como Sergey observou nos comentários, há uma limitação a este (ou a qualquer outro) método que vale a pena ressaltar. No caso de números como 0,014999999999999999, você ainda terá imprecisões que resultam de atingir o limite absoluto das limitações de precisão para armazenamento de valor de ponto flutuante. Não há matemática ou outra solução que possa ser aplicada para explicar isso, pois o valor em si é imediatamente avaliado como 0,015. Você pode confirmar isso simplesmente invocando esse valor sozinho no console. Devido a essa limitação, nem seria possível usar a manipulação de strings para reduzir esse valor, pois sua representação de strings é simplesmente "0,015". Qualquer solução para explicar isso precisaria ser aplicada logicamente na origem dos dados antes de aceitar o valor em um script,
fonte
Essa é a solução mais simples e elegante (e eu sou a melhor do mundo;):
fonte
E
notação.roundToX(362.42499999999995, 2)
. Resultado esperado (como em PHPecho round(362.42499999999995, 2)
):362.43
. Resultado real:362.42