Como formatar um flutuador em javascript?

427

Em JavaScript, ao converter de um float para uma string, como posso obter apenas 2 dígitos após o ponto decimal? Por exemplo, 0,34 em vez de 0,3445434.

jww
fonte
16
Apenas alguns exemplos: você deseja "cortar" todos os dois primeiros dígitos, ou deseja arredondar para dois dígitos?
xtofl 19/03/09

Respostas:

232
var result = Math.round(original*100)/100;

Os detalhes , caso o código não seja auto-explicativo.

edit: ... ou apenas use toFixed, como proposto por Tim Büthe . Esqueci esse, obrigado (e um voto positivo) pelo lembrete :)

kkyy
fonte
1
Eu estava usando isso na biblioteca "Highchart" onde ele não aceita valores de cadeia, portanto, toFixed não trabalharam para mim, Math.round resolvido meu problema, graças
Swapnil Chincholkar
4
toFixed()vai imitar o que algo como printf()faz em C. No entanto, toFixed()e Math.round()irá lidar com arredondamento diferente. Nesse caso, toFixed()terá o mesmo tipo de efeito Math.floor()que teria (desde que você multiplique o original por 10 ^ n antes e ligue toFixed()com n dígitos). A "correção" da resposta depende muito do que o OP deseja aqui, e ambas são "corretas" à sua maneira.
DDPWNAGE
838

Existem funções para arredondar números. Por exemplo:

var x = 5.0364342423;
print(x.toFixed(2));

imprimirá 5.04.

EDIT: Fiddle

Tim Büthe
fonte
7
Eu recomendaria contra o uso de print () em um navegador embora
cobbal
70
Ter cuidado com isso, toFixed () retorna um string: var x = 5.036432346; var y = x.toFixed(2) + 100; yserá igual"5.03100"
Vlad
5
Esteja ciente de que (1e100) .toFixed (2) === "1e + 100"
qbolec 15/02/14
7
Além disso, cuidado com os arredondamentos inconsistentes: (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2)
Skippy le Grand Gourou
3
Se você procurar um equivalente de toFixed, mas com arredondamento consistente, use toLocaleString: (0.345) .toLocaleString ('en-EN', {minimumFractionDigits: 2, maximumFractionDigits: 2})
fred727
185

Tenha cuidado ao usar toFixed():

Primeiro, o arredondamento do número é feito usando a representação binária do número, o que pode levar a um comportamento inesperado. Por exemplo

(0.595).toFixed(2) === '0.59'

em vez de '0.6'.

Segundo, há um bug do IE toFixed(). No IE (pelo menos até a versão 7, não verificou o IE8), o seguinte é verdadeiro:

(0.9).toFixed(0) === '0'

Pode ser uma boa ideia seguir a sugestão de kkyy ou usar uma toFixed()função personalizada , por exemplo

function toFixed(value, precision) {
    var power = Math.pow(10, precision || 0);
    return String(Math.round(value * power) / power);
}
Christoph
fonte
Sim, isso pode ser muito importante ao criar código para prever preços. Obrigado! +1
Fabio Milheiro 07/10
10
Eu sugeriria adicionar o .toFixed()método nativo no valor de retorno, que adicionará a quantidade necessária de precisão, por exemplo:: return (Math.round(value * power) / power).toFixed(precision);e também retornará o valor como uma string. Caso contrário, precisão de 20 é ignorado para decimais menores
William Joss Crowcroft
3
Uma observação sobre toFixed: observe que aumentar a precisão pode gerar resultados inesperados:, (1.2).toFixed(16) === "1.2000000000000000"enquanto (1.2).toFixed(17) === "1.19999999999999996"(no Firefox / Chrome; no IE8, o último não é válido devido à menor precisão que o IE8 pode oferecer internamente).
Jakub.g
2
Por favor, note que mesmo (0.598).toFixed(2)não produz 0.6. Produz 0.60:)
qbolec
1
Além disso, cuidado com arredondamento inconstistent: (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2).
Skippy le Grand Gourou
36

Outro problema a ter em atenção é que toFixed()pode produzir zeros desnecessários no final do número. Por exemplo:

var x=(23-7.37)
x
15.629999999999999
x.toFixed(6)
"15.630000"

A idéia é limpar a saída usando um RegExp:

function humanize(x){
  return x.toFixed(6).replace(/\.?0*$/,'');
}

O RegExpcoincide com os zeros à direita (e, opcionalmente, o ponto decimal) para ter certeza que parece ser bom para inteiros também.

humanize(23-7.37)
"15.63"
humanize(1200)
"1200"
humanize(1200.03)
"1200.03"
humanize(3/4)
"0.75"
humanize(4/3)
"1.333333"
qbolec
fonte
Number.prototype.minFixed = function (decimais) {retorna this.toFixed (decimais). Substitua (/ \.? 0 * $ /, ""); }
Luc Bloom
Isso deve ser aceito, zeros à direita são irritantes, eu estava procurando exatamente por essa solução, gj.
exoslav 6/06/18
1
Zeros à direita podem ser irritante, mas isso é exatamente o que o nome do método "toFixed" promete fazer;)
ksadowski
11
var x = 0.3445434
x = Math.round (x*100) / 100 // this will make nice rounding
Ilya Birman
fonte
Math.round (1.015 * 100) / 100 fornece 1,01 enquanto esperamos que seja 1,02?
gaurav5430
6

Há um problema com todas essas soluções flutuando usando multiplicadores. Infelizmente, as soluções de kkyy e Christoph estão erradas.

Teste o seu código para o número 551.175 com 2 casas decimais - ele será arredondado para 551,17 enquanto deve ser 551,18 ! Mas se você testar para ex. 451.175, tudo bem - 451.18. Portanto, é difícil identificar esse erro à primeira vista.

O problema está na multiplicação: tente 551.175 * 100 = 55117.49999999999 (ups!)

Então, minha ideia é tratá-lo com toFixed () antes de usar Math.round ();

function roundFix(number, precision)
{
    var multi = Math.pow(10, precision);
    return Math.round( (number * multi).toFixed(precision + 1) ) / multi;
}
ArteQ
fonte
1
Esse é o problema da aritmética em js: (551.175 * 10 * 10)! == (551.175 * 100). Você precisa usar incrementos decimais para mover a vírgula para resultados decimais não reais.
precisa
+1 por perceber isso, no entanto, também toFixedé afetado - (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2)... Qualquer que seja o método usado, adicione um épsilon antes do arredondamento.
Skippy le Grand Gourou
5

A chave aqui eu acho que é arredondar corretamente primeiro, então você pode convertê-lo em String.

function roundOf(n, p) {
    const n1 = n * Math.pow(10, p + 1);
    const n2 = Math.floor(n1 / 10);
    if (n1 >= (n2 * 10 + 5)) {
        return (n2 + 1) / Math.pow(10, p);
    }
    return n2 / Math.pow(10, p);
}

// All edge cases listed in this thread
roundOf(95.345, 2); // 95.35
roundOf(95.344, 2); // 95.34
roundOf(5.0364342423, 2); // 5.04
roundOf(0.595, 2); // 0.60
roundOf(0.335, 2); // 0.34
roundOf(0.345, 2); // 0.35
roundOf(551.175, 2); // 551.18
roundOf(0.3445434, 2); // 0.34

Agora você pode formatar esse valor com segurança com toFixed (p). Então, com o seu caso específico:

roundOf(0.3445434, 2).toFixed(2); // 0.34
Steven
fonte
3

Se você quiser a string sem arredondar, poderá usar este RegEx (talvez não seja a maneira mais eficiente ... mas é realmente fácil)

(2.34567778).toString().match(/\d+\.\d{2}/)[0]
// '2.34'
Pablo Andres Diaz Mazzaro
fonte
1
function trimNumber(num, len) {
  const modulu_one = 1;
  const start_numbers_float=2;
  var int_part = Math.trunc(num);
  var float_part = String(num % modulu_one);
      float_part = float_part.slice(start_numbers_float, start_numbers_float+len);
  return int_part+'.'+float_part;
}
ofir_aghai
fonte
ótima resposta, exceto que você está com ponto e vírgula ausente (não, no es6 o ponto e vírgula não é obsoleto e ainda precisamos usá-lo em alguns casos). Eu tive que também editar última linha para: return float_part ? int_part+'.'+float_part : int_part;caso contrário, se você passou Integer, ele retornou número com um ponto no final (exemplo de entrada: 2100, saída: 2100.)
Kuba Simonovsky
0

Talvez você também queira separador decimal? Aqui está uma função que acabei de criar:

function formatFloat(num,casasDec,sepDecimal,sepMilhar) {
    if (num < 0)
    {
        num = -num;
        sinal = -1;
    } else
        sinal = 1;
    var resposta = "";
    var part = "";
    if (num != Math.floor(num)) // decimal values present
    {
        part = Math.round((num-Math.floor(num))*Math.pow(10,casasDec)).toString(); // transforms decimal part into integer (rounded)
        while (part.length < casasDec)
            part = '0'+part;
        if (casasDec > 0)
        {
            resposta = sepDecimal+part;
            num = Math.floor(num);
        } else
            num = Math.round(num);
    } // end of decimal part
    while (num > 0) // integer part
    {
        part = (num - Math.floor(num/1000)*1000).toString(); // part = three less significant digits
        num = Math.floor(num/1000);
        if (num > 0)
            while (part.length < 3) // 123.023.123  if sepMilhar = '.'
                part = '0'+part; // 023
        resposta = part+resposta;
        if (num > 0)
            resposta = sepMilhar+resposta;
    }
    if (sinal < 0)
        resposta = '-'+resposta;
    return resposta;
}
Rodrigo
fonte
0

Não há como evitar arredondamentos inconsistentes para preços com x.xx5 como valor real usando multiplicação ou divisão. Se você precisar calcular preços corretos no lado do cliente, mantenha todos os valores em centavos. Isso se deve à natureza da representação interna dos valores numéricos em JavaScript. Observe que o Excel sofre dos mesmos problemas para que a maioria das pessoas não notasse os pequenos erros causados ​​por esse fenômeno. No entanto, os erros podem se acumular sempre que você acrescenta muitos valores calculados. Existe uma teoria completa envolvendo a ordem dos cálculos e outros métodos para minimizar o erro no resultado final. Para enfatizar os problemas com valores decimais, observe que 0,1 + 0,2 não é exatamente igual a 0,3 no JavaScript, enquanto 1 + 2 é igual a 3.

Dony
fonte
a solução seria separar parte inteira e parte decimal e representá-los como números inteiros na base 10, em vez de usar flutuadores, aqui funciona sem problemas para prettyPrint, mas em geral você precisa escolher entre uma base e outra, uma representação para números reais e outro, cada um com seus problemas
repete 06/11/2015
"O Excel sofre dos mesmos problemas". fonte ?
gaurav5430
0
/** don't spend 5 minutes, use my code **/
function prettyFloat(x,nbDec) { 
    if (!nbDec) nbDec = 100;
    var a = Math.abs(x);
    var e = Math.floor(a);
    var d = Math.round((a-e)*nbDec); if (d == nbDec) { d=0; e++; }
    var signStr = (x<0) ? "-" : " ";
    var decStr = d.toString(); var tmp = 10; while(tmp<nbDec && d*tmp < nbDec) {decStr = "0"+decStr; tmp*=10;}
    var eStr = e.toString();
    return signStr+eStr+"."+decStr;
}

prettyFloat(0);      //  "0.00"
prettyFloat(-1);     // "-1.00"
prettyFloat(-0.999); // "-1.00"
prettyFloat(0.5);    //  "0.50"
reuns
fonte
0

Eu uso esse código para formatar carros alegóricos. É baseado, toPrecision()mas remove zeros desnecessários. Gostaria de receber sugestões de como simplificar a regex.

function round(x, n) {
    var exp = Math.pow(10, n);
    return Math.floor(x*exp + 0.5)/exp;
}

Exemplo de uso:

function test(x, n, d) {
    var rounded = rnd(x, d);
    var result = rounded.toPrecision(n);
    result = result.replace(/\.?0*$/, '');
    result = result.replace(/\.?0*e/, 'e');
    result = result.replace('e+', 'e');
    return result;  
}

document.write(test(1.2000e45, 3, 2) + '=' + '1.2e45' + '<br>');
document.write(test(1.2000e+45, 3, 2) + '=' + '1.2e45' + '<br>');
document.write(test(1.2340e45, 3, 2) + '=' + '1.23e45' + '<br>');
document.write(test(1.2350e45, 3, 2) + '=' + '1.24e45' + '<br>');
document.write(test(1.0000, 3, 2) + '=' + '1' + '<br>');
document.write(test(1.0100, 3, 2) + '=' + '1.01' + '<br>');
document.write(test(1.2340, 4, 2) + '=' + '1.23' + '<br>');
document.write(test(1.2350, 4, 2) + '=' + '1.24' + '<br>');
Marca
fonte