Truncar (não arredondar) números decimais em javascript

Eu estou tentando truncar números decimais para casas decimais. Algo assim:

5.467 -> 5.46 985.943 -> 985.94 

toFixed(2) faz quase a coisa certa, mas arredonda o valor. Eu não preciso do valor arredondado. Espero que isso seja possível em javascript.

upd :

Então, afinal descobriu-se que os insetos que o cercam sempre vão assombrá-lo, não importa o quanto você tente compensá-los. Portanto, o problema deve ser atacado representando números exatamente em notação decimal.

 Number.prototype.toFixedDown = function(digits) { var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"), m = this.toString().match(re); return m ? parseFloat(m[1]) : this.valueOf(); }; [ 5.467.toFixedDown(2), 985.943.toFixedDown(2), 17.56.toFixedDown(2), (0).toFixedDown(1), 1.11.toFixedDown(1) + 22]; // [5.46, 985.94, 17.56, 0, 23.1] 

Solução antiga propensa a erros baseada na compilation de outras:

 Number.prototype.toFixedDown = function(digits) { var n = this - Math.pow(10, -digits)/2; n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56" return n.toFixed(digits); } 

A resposta de Dogbert é boa, mas se o seu código pode ter que lidar com números negativos, o Math.floor por si só pode dar resultados inesperados.

Por exemplo, Math.floor(4.3) = 4 , mas Math.floor(-4.3) = -5

Use uma function auxiliar como esta para obter resultados consistentes:

 truncateDecimals = function (number) { return Math[number < 0 ? 'ceil' : 'floor'](number); }; // Applied to Dogbert's answer: var a = 5.467; var truncated = truncateDecimals(a * 100) / 100; // = 5.46 

Aqui está uma versão mais conveniente desta function:

 truncateDecimals = function (number, digits) { var multiplier = Math.pow(10, digits), adjustedNum = number * multiplier, truncatedNum = Math[adjustedNum < 0 ? 'ceil' : 'floor'](adjustedNum); return truncatedNum / multiplier; }; // Usage: var a = 5.467; var truncated = truncateDecimals(a, 2); // = 5.46 // Negative digits: var b = 4235.24; var truncated = truncateDecimals(b, -2); // = 4200 

Se isso não for um comportamento desejado, insira uma chamada para Math.abs na primeira linha:

 var multiplier = Math.pow(10, Math.abs(digits)), 

EDIT: shendz corretamente aponta que usando esta solução com a = 17.56 incorretamente produzirá 17.55 . Para saber mais sobre por que isso acontece, leia O que todo cientista da computação deve saber sobre aritmética de ponto flutuante . Infelizmente, escrever uma solução que elimine todas as fonts de erro de ponto flutuante é bastante complicado com o javascript. Em outro idioma você usaria números inteiros ou talvez um tipo Decimal, mas com javascript ...

Essa solução deve ser 100% precisa, mas também será mais lenta:

 function truncateDecimals (num, digits) { var numS = num.toString(), decPos = numS.indexOf('.'), substrLength = decPos == -1 ? numS.length : 1 + decPos + digits, trimmedResult = numS.substr(0, substrLength), finalResult = isNaN(trimmedResult) ? 0 : trimmedResult; return parseFloat(finalResult); } 

Para aqueles que precisam de velocidade, mas também querem evitar erros de ponto flutuante, tente algo como BigDecimal.js . Você pode encontrar outras bibliotecas BigDecimal de javascript nesta pergunta SO: "Existe uma boa biblioteca BigDecimal de Javascript?" e aqui está um bom post sobre bibliotecas matemáticas para Javascript

 var a = 5.467; var truncated = Math.floor(a * 100) / 100; // = 5.46 

Você pode corrigir o arredondamento subtraindo 0,5 para toFixed, por exemplo

 (f - 0.005).toFixed(2) 

Considere tirar proveito do duplo til: ~~ .

Pegue o número. Multiplique por dígitos significativos após o decimal para que você possa truncar para zero lugares com ~~ . Divida esse multiplicador de volta. Lucro.

 function truncator(numToTruncate, intDecimalPlaces) { var numPower = Math.pow(10, intDecimalPlaces); // "numPowerConverter" might be better return ~~(numToTruncate * numPower)/numPower; } 

Estou tentando resistir a envolver o ~~ call em parentes; ordem de operações deve fazer esse trabalho corretamente, eu acredito.

alert(truncator(5.1231231, 1)); // is 5.1

alert(truncator(-5.73, 1)); // is -5.7

alert(truncator(-5.73, 0)); // is -5

Link JSFiddle .

EDIT: Olhando para trás, eu involuntariamente também lidou com casos para arredondar à esquerda do decimal também.

alert(truncator(4343.123, -2)); // gives 4300.

A lógica é um pouco maluca procurando por esse uso, e pode se beneficiar de um refatorador rápido. Mas ainda funciona. Melhor sorte que bem.

Eu pensei em lançar uma resposta usando | desde que é simples e funciona bem.

 truncate = function(number, places) { var shift = Math.pow(10, places); return ((number * shift) | 0) / shift; }; 

Solução agradável de uma linha:

 function truncate (num, places) { return Math.trunc(num * Math.pow(10, places)) / Math.pow(10, places); } 

Então ligue com:

 truncate(3.5636232, 2); // returns 3.56 truncate(5.4332312, 3); // returns 5.433 truncate(25.463214, 4); // returns 25.4632 

Truncar usando operadores bit a bit:

 ~~0.5 === 0 ~~(-0.5) === 0 ~~14.32794823 === 14 ~~(-439.93) === -439 

@ A resposta de Dogbert pode ser melhorada com Math.trunc , que trunca em vez de arredondar.

Há uma diferença entre arredondamento e truncamento. Truncando é claramente o comportamento que esta questão está buscando. Se eu chamar truncate (-3.14) e receber -4 de volta, eu definitivamente chamaria isso indesejável. – @NickKnowlson

 var a = 5.467; var truncated = Math.trunc(a * 100) / 100; // = 5.46 
 var a = -5.467; var truncated = Math.trunc(a * 100) / 100; // = -5.46 

O que é marca como a solução é a melhor solução que encontrei até hoje, mas tem um problema sério com 0 (por exemplo, 0.toFixedDown (2) fornece -0.01). Então eu sugiro usar isso:

 Number.prototype.toFixedDown = function(digits) { if(this == 0) { return 0; } var n = this - Math.pow(10, -digits)/2; n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56" return n.toFixed(digits); } 

Aqui está a function simples, mas funcional, de truncar o número até 2 casas decimais.

  function truncateNumber(num) { var num1 = ""; var num2 = ""; var num1 = num.split('.')[0]; num2 = num.split('.')[1]; var decimalNum = num2.substring(0, 2); var strNum = num1 +"."+ decimalNum; var finalNum = parseFloat(strNum); return finalNum; } 
 Number.prototype.trim = function(decimals) { var s = this.toString(); var d = s.split("."); d[1] = d[1].substring(0, decimals); return parseFloat(d.join(".")); } console.log((5.676).trim(2)); //logs 5.67 

Eu encontrei um problema: considerando a próxima situação: 2.1 ou 1.2 ou -6.4

E se você quiser sempre 3 decimais ou dois ou wharever, então, você tem que completar os zeros à direita

 // 3 decimals numbers 0.5 => 0.500 // 6 decimals 0.1 => 0.10000 // 4 decimales -2.1 => -2.1000 // truncate to 3 decimals 3.11568 => 3.115 

Esta é a function fixa de Nick Knowlson

 function truncateDecimals (num, digits) { var numS = num.toString(); var decPos = numS.indexOf('.'); var substrLength = decPos == -1 ? numS.length : 1 + decPos + digits; var trimmedResult = numS.substr(0, substrLength); var finalResult = isNaN(trimmedResult) ? 0 : trimmedResult; // adds leading zeros to the right if (decPos != -1){ var s = trimmedResult+""; decPos = s.indexOf('.'); var decLength = s.length - decPos; while (decLength <= digits){ s = s + "0"; decPos = s.indexOf('.'); decLength = s.length - decPos; substrLength = decPos == -1 ? s.length : 1 + decPos + digits; }; finalResult = s; } return finalResult; }; 

https://jsfiddle.net/huttn155/7/

O tipo resultante permanece um número …

 /* Return the truncation of n wrt base */ var trunc = function(n, base) { n = (n / base) | 0; return base * n; }; var t = trunc(5.467, 0.01); 

Eu acho que essa function pode ser uma solução simples:

 function trunc(decimal,n=2){ let x = decimal + ''; // string return x.lastIndexOf('.')>=0?parseFloat(x.substr(0,x.lastIndexOf('.')+(n+1))):decimal; // You can use indexOf() instead of lastIndexOf() } console.log(trunc(-241.31234,2)); console.log(trunc(241.312,5)); console.log(trunc(-241.233)); console.log(trunc(241)); 

Aqui minha opinião sobre o assunto:

 convert.truncate = function(value, decimals) { decimals = (decimals === undefined ? 0 : decimals); return parseFloat((value-(0.5/Math.pow(10, decimals))).toFixed(decimals),10); }; 

É apenas uma versão um pouco mais elaborada

 (f - 0.005).toFixed(2) 

só para apontar uma solução simples que funcionou para mim

convertê-lo em string e, em seguida, regex-lo …

 var number = 123.45678; var number_s = '' + number; var number_truncated_s = number_s.match(/\d*\.\d{4}/)[0] var number_truncated = parseFloat(number_truncated_s) 

Pode ser abreviado para

 var number_truncated = parseFloat(('' + 123.4568908).match(/\d*\.\d{4}/)[0]) 

Aqui está o que eu uso:

 var t = 1; for (var i = 0; i < decimalPrecision; i++) t = t * 10; var f = parseFloat(value); return (Math.floor(f * t)) / t; 

Aqui está um código ES6 que faz o que você quer

 const truncateTo = (unRouned, nrOfDecimals = 2) => { const parts = String(unRouned).split("."); if (parts.length !== 2) { // without any decimal part return unRouned; } const newDecimals = parts[1].slice(0, nrOfDecimals), newString = `${parts[0]}.${newDecimals}`; return Number(newString); }; // your examples console.log(truncateTo(5.467)); // ---> 5.46 console.log(truncateTo(985.943)); // ---> 985.94 // other examples console.log(truncateTo(5)); // ---> 5 console.log(truncateTo(-5)); // ---> -5 console.log(truncateTo(-985.943)); // ---> -985.94 
 Number.prototype.truncate = function(places) { var shift = Math.pow(10, places); return Math.trunc(this * shift) / shift; }; 

A resposta de @kirilloid parece ser a resposta correta, no entanto, o código principal precisa ser atualizado. Sua solução não cuida de números negativos (o que alguém mencionou na seção de comentários, mas não foi atualizado no código principal).

Atualizando isso para uma solução final testada completa:

 Number.prototype.toFixedDown = function(digits) { var re = new RegExp("([-]*\\d+\\.\\d{" + digits + "})(\\d)"), m = this.toString().match(re); return m ? parseFloat(m[1]) : this.valueOf(); }; 

Uso da amostra:

 var x = 3.1415629; Logger.log(x.toFixedDown(2)); //or use whatever you use to log 

Fiddle: JS Number Arredondar para baixo

PS: Não há repo suficiente para comentar sobre essa solução.

 function toFixed(number, digits) { var reg_ex = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)") var array = number.toString().match(reg_ex); return array ? parseFloat(array[1]) : number.valueOf() } var test = 10.123456789 var __fixed = toFixed(test, 6) console.log(__fixed) // => 10.123456 

Lodash tem alguns methods utilitários de matemática que podem arredondar , pavimentar e ceilizar um número para uma precisão decimal. Isso deixa de lado zeros.

Eles adotam uma abordagem interessante, usando o expoente de um número. Aparentemente, isso evita problemas de arredondamento.

(Nota: func é Math.round ou ceil ou floor no código abaixo)

 // Shift with exponential notation to avoid floating-point issues. var pair = (toString(number) + 'e').split('e'), value = func(pair[0] + 'e' + (+pair[1] + precision)); pair = (toString(value) + 'e').split('e'); return +(pair[0] + 'e' + (+pair[1] - precision)); 

Link para o código-fonte

    Intereting Posts