Arredondamento até, no máximo, 2 casas decimais (apenas se necessário)
gostaria de arredondar no máximo 2 casas decimais, mas só se necessário.
Entrada:
10
1.7777777
9.1
resultado:
10
1.78
9.1
Como posso fazer isto?
30 answers
Utilizar Math.round(num * 100) / 100
Se o valor for um tipo de texto:
parseFloat("123.456").toFixed(2);
Se o valor for um número:
var numb = 123.23454;
numb = numb.toFixed(2);
Há um lado negativo que valores como 1,5 vão dar "1,50" como a saída. Uma correção sugerida por @minitech:
var numb = 1.5;
numb = +numb.toFixed(2);
// Note the plus sign that drops any "extra" zeroes at the end.
// It changes the result (which is a string) into a number again (think "0 + foo"),
// which means that it uses only as many digits as necessary.
Parece que Math.round
é uma solução melhor. Mas não é! em alguns casos, não irárodar correctamente:
Math.round(1.005 * 1000)/1000 // Returns 1 instead of expected 1.01!
ToFixed () will also NOT round correctly in some cases (tested in Chrome v. 55. 0. 2883. 87)!
Exemplos:
parseFloat("1.555").toFixed(2); // Returns 1.55 instead of 1.56.
parseFloat("1.5550").toFixed(2); // Returns 1.55 instead of 1.56.
// However, it will return correct result if you round 1.5551.
parseFloat("1.5551").toFixed(2); // Returns 1.56 as expected.
1.3555.toFixed(3) // Returns 1.355 instead of expected 1.356.
// However, it will return correct result if you round 1.35551.
1.35551.toFixed(2); // Returns 1.36 as expected.
Acho que isto é porque o 1.555 é algo como o float 1.554994 nos bastidores.
A solução 1 é usar um programa com o algoritmo de arredondamento necessário, por exemplo:
function roundNumber(num, scale) {
if(!("" + num).includes("e")) {
return +(Math.round(num + "e+" + scale) + "e-" + scale);
} else {
var arr = ("" + num).split("e");
var sig = ""
if(+arr[1] + scale > 0) {
sig = "+";
}
return +(Math.round(+arr[0] + "e" + sig + (+arr[1] + scale)) + "e-" + scale);
}
}
Https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview
A solução 2 é evitar os cálculos da extremidade dianteira e retirar os valores arredondados do servidor da infra-estrutura.
Pode utilizar
function roundToTwo(num) {
return +(Math.round(num + "e+2") + "e-2");
}
Encontrei isto em MDN . Seu caminho evita o problema com 1.005 que foi mencionado .
roundToTwo(1.005)
1.01
roundToTwo(10)
10
roundToTwo(1.7777777)
1.78
roundToTwo(9.1)
9.1
roundToTwo(1234.5678)
1234.57
Number.prototype.round = function(places) {
return +(Math.round(this + "e+" + places) + "e-" + places);
}
Utilização:
var n = 1.7777;
n.round(2); // 1.78
Teste unitário:
it.only('should round floats to 2 places', function() {
var cases = [
{ n: 10, e: 10, p:2 },
{ n: 1.7777, e: 1.78, p:2 },
{ n: 1.005, e: 1.01, p:2 },
{ n: 1.005, e: 1, p:0 },
{ n: 1.77777, e: 1.8, p:1 }
]
cases.forEach(function(testCase) {
var r = testCase.n.round(testCase.p);
assert.equal(r, testCase.e, 'didn\'t get right number');
});
})
Pode-se usar .toFixed(NumberOfDecimalPlaces)
.
var str = 10.234.toFixed(2); // => '10.23'
var number = Number(str); // => 10.23
Nenhuma das respostas encontradas aqui está correta. @stinkycheeseman pediu para reunir , todos arredondaram o número.
Para arredondar, use isto:
Math.ceil(num * 100)/100;
Um método de arredondamento preciso. Fonte: Mozilla
(function(){
/**
* Decimal adjustment of a number.
*
* @param {String} type The type of adjustment.
* @param {Number} value The number.
* @param {Integer} exp The exponent (the 10 logarithm of the adjustment base).
* @returns {Number} The adjusted value.
*/
function decimalAdjust(type, value, exp) {
// If the exp is undefined or zero...
if (typeof exp === 'undefined' || +exp === 0) {
return Math[type](value);
}
value = +value;
exp = +exp;
// If the value is not a number or the exp is not an integer...
if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
return NaN;
}
// Shift
value = value.toString().split('e');
value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
// Shift back
value = value.toString().split('e');
return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
}
// Decimal round
if (!Math.round10) {
Math.round10 = function(value, exp) {
return decimalAdjust('round', value, exp);
};
}
// Decimal floor
if (!Math.floor10) {
Math.floor10 = function(value, exp) {
return decimalAdjust('floor', value, exp);
};
}
// Decimal ceil
if (!Math.ceil10) {
Math.ceil10 = function(value, exp) {
return decimalAdjust('ceil', value, exp);
};
}
})();
Exemplos:
// Round
Math.round10(55.55, -1); // 55.6
Math.round10(55.549, -1); // 55.5
Math.round10(55, 1); // 60
Math.round10(54.9, 1); // 50
Math.round10(-55.55, -1); // -55.5
Math.round10(-55.551, -1); // -55.6
Math.round10(-55, 1); // -50
Math.round10(-55.1, 1); // -60
Math.round10(1.005, -2); // 1.01 -- compare this with Math.round(1.005*100)/100 above
// Floor
Math.floor10(55.59, -1); // 55.5
Math.floor10(59, 1); // 50
Math.floor10(-55.51, -1); // -55.6
Math.floor10(-51, 1); // -60
// Ceil
Math.ceil10(55.51, -1); // 55.6
Math.ceil10(51, 1); // 60
Math.ceil10(-55.59, -1); // -55.5
Math.ceil10(-59, 1); // -50
Suponha que temos uma função, roundTo2DP(num)
, que toma um flutuador como argumento e devolve um valor arredondado a 2 casas decimais. Para que devem avaliar cada uma destas expressões?
roundTo2DP(0.014999999999999999)
roundTo2DP(0.0150000000000000001)
roundTo2DP(0.015)
A resposta 'óbvia' é que o primeiro exemplo deve girar para 0,01 (porque está mais perto de 0,01 do que a 0,02) enquanto os outros dois devem girar para 0,02 (porque 0.015000000000000000001 é mais próximo de 0,02 do que 0,01, e porque 0,015 é exatamente meio caminho entre eles e há uma convenção matemática que esses números são arredondados para cima).
A captura, que você pode ter adivinhado, é que roundTo2DP
não é possível que seja implementado para dar essas respostas óbvias, porque todos os três números passados a ele são o mesmo número . IEEE 754 binários números de vírgula flutuante (o tipo usado por JavaScript) não pode representar exatamente a maioria dos números não-inteiros, e assim tudo três literais numéricos acima são arredondados para um número de vírgula flutuante válido nas proximidades. Este número, por acaso, é exactamente.
0.01499999999999999944488848768742172978818416595458984375
Que está mais perto de 0, 01 do que de 0, 02.
Você pode ver que todos os três números são os mesmos na sua consola de navegador, node shell, ou outro interpretador de JavaScript. Basta compará-los:
> 0.014999999999999999 === 0.0150000000000000001
true
Então, quando escrevo m = 0.0150000000000000001
, o valor exacto de m
that I end acima está mais perto de 0.01
do que de 0.02
. E ainda assim, se eu Converter m
para uma cadeia...
> var m = 0.0150000000000000001;
> console.log(String(m));
0.015
> var m = 0.014999999999999999;
> console.log(String(m));
0.015
... Eu recebo 0,015, que deve girar para 0,02, e que é visivelmente Não {[42] } O número de 56-decimal-lugar que eu disse anteriormente que todos estes números eram exatamente iguais. Que magia negra é esta?
A resposta pode ser encontrada na especificação ECMAScript, na secção 7.1.12.1: ToString aplicado ao tipo de número. Aqui as regras para a conversão de algum número m para uma cadeia de caracteres são estabelecidas. A parte chave é o ponto 5, no qual um inteiro S é gerado cujos dígitos serão usados na representação de texto de m:
Permitem - n, k, e s ser inteiros tais que k ≥ 1, 10k-1 ≤ s k, o valor do Número de s × 10n-k é m, e k é o mais pequeno possível. Nota-se que k é o número de algarismos na representação decimal de s, em que s não é divisível por 10, e que o dígito menos significativo do s não é, necessariamente, exclusivamente determinada por estes critérios.
A parte chave aqui é o requisito de que " k é o mais pequeno possível". O que este requisito representa é um requisito que, dado um número m
, o valor de String(m)
deve ter o menor número possível de algarismos ainda satisfazendo o requisito de que Number(String(m)) === m
. Uma vez que já sabemos que 0.015 === 0.0150000000000000001
, agora está claro porque String(0.0150000000000000001) === '0.015'
deve ser verdade.
roundTo2DP(m)
Se voltar. Se o valor exacto de m
for 0.01499999999999999944488848768742172978818416595458984375, mas a sua representação de cordas for '0.015', então qual é a respostacorrecta - matematicamente, praticamente, filosoficamente, ou seja lá o que for - quando o arredondamos a duas casas decimais?
Não há uma única resposta correcta para isto. Depende do seu caso de uso. Você provavelmente quer respeitar a representação de texto e girar para cima quando:
- O valor representado é inerentemente discreto, por exemplo, uma quantidade de moeda numa moeda com 3 casas decimais, como os Dinares. Neste caso, o valor verdadeiro de um número como 0, 015 é 0, 015, e o 0, 01499999... a representação que se obtém em ponto flutuante binário é um erro de arredondamento. (Claro, muitos argumentarão, razoavelmente, que você deve usar uma biblioteca decimal para lidar com tais valores e nunca representá-los como números binários de ponto flutuante em primeiro lugar.)
- o valor foi digitado por um utilizador. Neste caso, novamente, o número decimal exato introduzido é mais 'verdadeiro' do que a representação binária de ponto flutuante mais próxima.
/**
* Converts num to a decimal string (if it isn't one already) and then rounds it
* to at most dp decimal places.
*
* For explanation of why you'd want to perform rounding operations on a String
* rather than a Number, see http://stackoverflow.com/a/38676273/1709587
*
* @param {(number|string)} num
* @param {number} dp
* @return {string}
*/
function roundStringNumberWithoutTrailingZeroes (num, dp) {
if (arguments.length != 2) throw new Error("2 arguments required");
num = String(num);
if (num.indexOf('e+') != -1) {
// Can't round numbers this large because their string representation
// contains an exponent, like 9.99e+37
throw new Error("num too large");
}
if (num.indexOf('.') == -1) {
// Nothing to do
return num;
}
var parts = num.split('.'),
beforePoint = parts[0],
afterPoint = parts[1],
shouldRoundUp = afterPoint[dp] >= 5,
finalNumber;
afterPoint = afterPoint.slice(0, dp);
if (!shouldRoundUp) {
finalNumber = beforePoint + '.' + afterPoint;
} else if (/^9+$/.test(afterPoint)) {
// If we need to round up a number like 1.9999, increment the integer
// before the decimal point and discard the fractional part.
finalNumber = Number(beforePoint)+1;
} else {
// Starting from the last digit, increment digits until we find one
// that is not 9, then stop
var i = dp-1;
while (true) {
if (afterPoint[i] == '9') {
afterPoint = afterPoint.substr(0, i) +
'0' +
afterPoint.substr(i+1);
i--;
} else {
afterPoint = afterPoint.substr(0, i) +
(Number(afterPoint[i]) + 1) +
afterPoint.substr(i+1);
break;
}
}
finalNumber = beforePoint + '.' + afterPoint;
}
// Remove trailing zeroes from fractional part before returning
return finalNumber.replace(/0+$/, '')
}
Uso de exemplo:
> roundStringNumberWithoutTrailingZeroes(1.6, 2)
'1.6'
> roundStringNumberWithoutTrailingZeroes(10000, 2)
'10000'
> roundStringNumberWithoutTrailingZeroes(0.015, 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes('0.015000', 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes(1, 1)
'1'
> roundStringNumberWithoutTrailingZeroes('0.015', 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes(0.01499999999999999944488848768742172978818416595458984375, 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes('0.01499999999999999944488848768742172978818416595458984375', 2)
'0.01'
A função acima é provavelmente O que você quer usar para evitar que os utilizadores testemunhem números que eles introduziram sejam arredondados erradamente.
(Como alternativa, você poderia tente também a biblioteca Round 10 que fornece uma função de comportamento semelhante com uma implementação muito 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 as 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 das cordas, porque essa representação (como explicado na especificação) já é meio arredondado; não queremos cometer o erro de dizer " 0.014999999...375 arredonda até 0,015, o que perfaz 0,02, portanto 0,0149999...375 balas até 0,02".
Aqui podemos simplesmente usar o embutido.toFixed
método. Note que ao chamar Number()
na sequência devolvida por toFixed
, obtemos um número cuja representação de texto não tem zeros finais (graças à forma como o JavaScript calcula a representação de texto de um número, discutido anteriormente nesta resposta).
/**
* Takes a float and rounds it to at most dp decimal places. For example
*
* roundFloatNumberWithoutTrailingZeroes(1.2345, 3)
*
* returns 1.234
*
* Note that since this treats the value passed to it as a floating point
* number, it will have counterintuitive results in some cases. For instance,
*
* roundFloatNumberWithoutTrailingZeroes(0.015, 2)
*
* gives 0.01 where 0.02 might be expected. For an explanation of why, see
* http://stackoverflow.com/a/38676273/1709587. You may want to consider using the
* roundStringNumberWithoutTrailingZeroes function there instead.
*
* @param {number} num
* @param {number} dp
* @return {number}
*/
function roundFloatNumberWithoutTrailingZeroes (num, dp) {
var numToFixedDp = Number(num).toFixed(dp);
return Number(numToFixedDp);
}
Considerar .toFixed()
e .toPrecision()
:
Math.round(value * 100) / 100
Podes querer ir em frente e fazer uma função separada para o fazer por ti no entanto:
function roundToTwo(value) {
return(Math.round(value * 100) / 100);
}
Então você simplesmente passaria no valor.
Você poderia aumentá-lo para arredondar para qualquer número arbitrário de casas decimais adicionando um segundo parâmetro.
function myRound(value, places) {
var multiplier = Math.pow(10, places);
return (Math.round(value * multiplier) / multiplier);
}
Deve utilizar:
Math.round( num * 100 + Number.EPSILON ) / 100
Ninguém parece estar ciente de Number.EPSILON
.
Também vale a pena notar que isto não é uma estranheza JavaScript como algumas pessoas afirmaram.
É assim que os números de vírgula flutuante funcionam num computador. como 99% das linguagens de programação, o JavaScript não tem números de ponto flutuante feitos em casa; depende do CPU/FPU para isso. Um computador usa binário, e em binário, não há nenhum número 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.333333... com uma infinidade de três.
Number.EPSILON
. Esse número é a diferença entre 1 e o número seguinte existente nos números de vírgula flutuante de precisão dupla. é isso: não há nenhum número entre 1
e 1 + Number.EPSILON
.
Editar:
Como foi perguntado nos comentários, vamos esclarecer uma coisa. coisa: adicionarNumber.EPSILON
só é relevante quando o valor a arredondar é o resultado de uma operação aritmética, uma vez que pode engolir algum delta de erro de ponto flutuante.
Não é útil quando o valor vem de uma fonte directa (por exemplo: literal, entrada do utilizador ou sensor).
+(10).toFixed(2); // = 10
+(10.12345).toFixed(2); // = 10.12
(10).toFixed(2); // = 10.00
(10.12345).toFixed(2); // = 10.12
2017
Basta usar o código nativo.toFixed()
number = 1.2345;
number.toFixed(2) // "1.23"
Se precisar de ser rigoroso e adicionar dígitos, se necessário, pode usar replace
number = 1; // "1"
number.toFixed(5).replace(/\.?0*$/g,'');
Tenta esta soluçãode peso leve :
function round(x, digits){
return parseFloat(x.toFixed(digits))
}
round(1.222, 2) ;
// 1.22
round(1.222, 10) ;
// 1.222
function round(number, precision) {
var pair = (number + 'e').split('e')
var value = Math.round(pair[0] + 'e' + (+pair[1] + precision))
pair = (value + 'e').split('e')
return +(pair[0] + 'e' + (+pair[1] - precision))
}
Utilização:
round(0.015, 2) // 0.02
round(1.005, 2) // 1.01
Se o seu projecto usa o jQuery ou o lodash, também pode encontrar o método round
adequado nas bibliotecas.
Actualizar 1
Removi a variante n.toFixed(2)
, porque não está correcta. Obrigado @avalanche1
Para mim Matemática.o round () não estava a dar a resposta correcta. Descobri que toFixed (2) funciona melhor. Abaixo estão exemplos de ambos:
console.log(Math.round(43000 / 80000) * 100); // wrong answer
console.log(((43000 / 80000) * 100).toFixed(2)); // correct answer
Aqui está a função que uso para resolver os problemas das casas decimais de vírgula flutuante também baseada em MDN . É ainda mais genérico (mas menos conciso) do que a solução de Lavamantis:
function round(value, exp) {
if (typeof exp === 'undefined' || +exp === 0)
return Math.round(value);
value = +value;
exp = +exp;
if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
return NaN;
// Shift
value = value.toString().split('e');
value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));
// Shift back
value = value.toString().split('e');
return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
}
Usa-o com:
round(10.8034, 2); // Returns 10.8
round(1.275, 2); // Returns 1.28
round(1.27499, 2); // Returns 1.27
round(1.2345678e+2, 2); // Returns 123.46
Comparado com a solução de Lavamantis, podemos fazê-lo...
round(1234.5678, -2); // Returns 1200
round("123.45"); // Returns 123
var roundUpto = function(number, upto){
return Number(number.toFixed(upto));
}
roundUpto(0.1464676, 2);
toFixed(2)
Aqui 2 é o número de dígitos até o qual queremos arredondar este número.
_.round(number, precision)
Eg:
_.round(1.7777777, 2) = 1.78
Isto pode ajudá-lo:
var result = (Math.round(input*100)/100);
Para mais informações, pode ver este link
Math.round (num) vs num.tofixed (0) e inconsistências do navegador
A maneira mais fácil:
+num.toFixed(2)
Converte-o para uma cadeia, e depois volta para um inteiro / flutuante.
Aqui está um método protótipo:
Number.prototype.round = function(places){
places = Math.pow(10, places);
return Math.round(this * places)/places;
}
var yournum = 10.55555;
yournum = yournum.round(2);
Pode funcionar para ti,
Math.round(num * 100)/100;
Para saber a diferença entre toFixed e round. Você pode dar uma olhada Math.round (num) vs num.tofixed (0) e inconsistências do navegador.
round(num / p) * p
Utilizando a notação exponencial, o arredondamento dos números +ve é feito correctamente. No entanto, este método não consegue contornar os casos de aresta corretamente.
function round(num, precision = 2) {
var scaled = Math.round(num + "e" + precision);
return Number(scaled + "e" + -precision);
}
// testing some edge cases
console.log( round(1.005, 2) ); // 1.01 correct
console.log( round(2.175, 2) ); // 2.18 correct
console.log( round(5.015, 2) ); // 5.02 correct
console.log( round(-1.005, 2) ); // -1 wrong
console.log( round(-2.175, 2) ); // -2.17 wrong
console.log( round(-5.015, 2) ); // -5.01 wrong
Aqui, também está uma função que escrevi para fazer arredondamentos aritméticos corretamente. Podes testá-lo tu mesmo.
/**
* MidpointRounding away from zero ('arithmetic' rounding)
* Uses a half-epsilon for correction. (This offsets IEEE-754
* half-to-even rounding that was applied at the edge cases).
*/
function RoundCorrect(num, precision = 2) {
// half epsilon to correct edge cases.
var c = 0.5 * Number.EPSILON * num;
// var p = Math.pow(10, precision); //slow
var p = 1; while (precision--> 0) p *= 10;
if (num < 0)
p *= -1;
return Math.round((num + c) * p) / p;
}
// testing some edge cases
console.log(RoundCorrect(1.005, 2)); // 1.01 correct
console.log(RoundCorrect(2.175, 2)); // 2.18 correct
console.log(RoundCorrect(5.015, 2)); // 5.02 correct
console.log(RoundCorrect(-1.005, 2)); // -1.01 correct
console.log(RoundCorrect(-2.175, 2)); // -2.18 correct
console.log(RoundCorrect(-5.015, 2)); // -5.02 correct
parseFloat(parseFloat("1.7777777").toFixed(2))-->1.78
parseFloat(parseFloat("10").toFixed(2))-->10
parseFloat(parseFloat("9.1").toFixed(2))-->9.1
Se por acaso já estiver a usar a biblioteca d3, eles têm uma poderosa biblioteca de formatação de Números: https://github.com/mbostock/d3/wiki/Formatting
O arredondamento específico está aqui: https://github.com/mbostock/d3/wiki/Formatting#d3_round
No seu caso, a resposta é:
> d3.round(1.777777, 2)
1.78
> d3.round(1.7, 2)
1.7
> d3.round(1, 2)
1
Uma maneira de alcançar esse arredondamento só se necessário é utilizar O número.prototipo.toLocaleString():
myNumber.toLocaleString('en', {maximumFractionDigits:2, useGrouping:false})
Isto irá fornecer exactamente a saída que você espera, mas como cadeias de caracteres. Você ainda pode converter esses números de volta para números se esse não é o tipo de dados que você espera.
Uma forma mais simples de ES6 é
const round = (x, n) =>
parseFloat(Math.round(x * Math.pow(10, n)) / Math.pow(10, n)).toFixed(n);
Este padrão também devolve a precisão pedida.
Ex:
round(44.7826456, 4) // yields 44.7826
round(78.12, 4) // yields 78.1200
Uma vez que o ES6 existe uma maneira 'apropriada '(sem a estática superior e a criação de bases de trabalho) de o fazer por usando a toprecisão
var x = 1.49999999999;
console.log(x.toPrecision(4));
console.log(x.toPrecision(3));
console.log(x.toPrecision(2));
var y = Math.PI;
console.log(y.toPrecision(6));
console.log(y.toPrecision(5));
console.log(y.toPrecision(4));
var z = 222.987654
console.log(z.toPrecision(6));
console.log(z.toPrecision(5));
console.log(z.toPrecision(4));
Para não lidar com muitos 0s, use esta variante:
Math.round(num * 1e2) / 1e2