Estou tentando truncar números decimais em casas decimais. Algo assim:
5.467 -> 5.46
985.943 -> 985.94
toFixed(2)
faz exatamente a coisa certa, mas arredonda o valor. Eu não preciso do valor arredondado. Espero que isso seja possível em javascript.
Respostas:
upd :
Então, afinal de contas, os bugs circulares sempre irão persegui-lo, não importa o quanto você tente compensá-los. Portanto, o problema deve ser atacado representando os 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]
Antiga solução sujeita a erros baseada na compilação de outros:
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); }
fonte
1.11.toFixedDown(1) + 22
termina como em1.122
vez de23.1
. Também0.toFixedDown(1)
deve produzir,0
mas em vez disso, produz-0.1
.(-10.2131).toFixedDown(2) // ==> 10.21
.(1e-7).toFixedDown(0) // ==> 1e-7
. Faz isso para1e-(>=7)
(ex:1e-8
,1e-9
, ...).A resposta de Dogbert é boa, mas se seu código tiver que lidar com números negativos,
Math.floor
por si só pode fornecer resultados inesperados.Por exemplo
Math.floor(4.3) = 4
, masMath.floor(-4.3) = -5
Use uma função 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
Esta é uma versão mais conveniente desta função:
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 esse não for o comportamento desejado, insira uma chamada para
Math.abs
na primeira linha:var multiplier = Math.pow(10, Math.abs(digits)),
EDIT: shendz corretamente aponta que usar esta solução com
a = 17.56
produzirá incorretamente17.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 elimina todas as fontes de erro de ponto flutuante é muito complicado com javascript. Em outro idioma você usaria inteiros ou talvez um tipo decimal, mas com javascript ...Esta 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 quem precisa de velocidade, mas também deseja evitar erros de ponto flutuante, tente algo como BigDecimal.js . Você pode encontrar outras bibliotecas javascript BigDecimal nesta pergunta do SO: "Existe uma boa biblioteca Javascript BigDecimal?" e aqui está uma boa postagem no blog sobre bibliotecas matemáticas para Javascript
fonte
if(isNAN(result) result = 0;
Depende do comportamento que você deseja.var a = 5.467; var truncated = Math.floor(a * 100) / 100; // = 5.46
fonte
truncate(-3.14)
e receber de-4
volta, definitivamente considerarei isso indesejável.var a = 65.1
var truncated = Math.floor(a * 100) / 100; // = 65.09
Portanto, esta não é uma solução corretaVocê pode corrigir o arredondamento subtraindo 0,5 de toFixed, por exemplo
(f - 0.005).toFixed(2)
fonte
Considere aproveitando a dupla til:
~~
.Pegue o número. Multiplique por dígitos significativos após o decimal para que você possa truncar para zero casas 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 a
~~
chamada entre parênteses; a ordem das operações deve fazer com que funcione 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 também lidei sem querer com casos para arredondar à esquerda do decimal.
alert(truncator(4343.123, -2)); // gives 4300.
A lógica é um pouco maluca procurando por esse uso e pode se beneficiar de uma refatoração rápida. Mas ainda funciona. Melhor sorte do que bem.
fonte
Math
protótipo com isso e verificar se há NaN-s antes de executá-lo, será perfeito.truncator((10 * 2.9) / 100, 2)
retorna 0,28 em vez de 0,29 ... jsfiddle.net/25tgrzq1100012345678
é significativamente maior que2147483647
. Se você realmente tiver números maiores do que 32 bits (em vez disso, se precisar de tantos dígitos significativos), este não é o andróide que você está procurando. Esta é uma resposta rápida e suja (e rápida) para, digamos, 4-5 dígitos de sigilo. Para perfeição potencialmente exagerada, tente a resposta aceita . ; ^ DBoa solução de uma linha:
function truncate (num, places) { return Math.trunc(num * Math.pow(10, places)) / Math.pow(10, places); }
Em seguida, chame-o com:
truncate(3.5636232, 2); // returns 3.56 truncate(5.4332312, 3); // returns 5.433 truncate(25.463214, 4); // returns 25.4632
fonte
Pensei em adicionar uma resposta usando,
|
pois é simples e funciona bem.truncate = function(number, places) { var shift = Math.pow(10, places); return ((number * shift) | 0) / shift; };
fonte
or
ing com 0 significa "apenas manter o que já tenho". Faz o que minha~~
resposta faz, mas com uma única operação bit a bit. Embora também tenha a mesma limitação escrita: Não podemos ultrapassar 2 ^ 31 .truncate((10 * 2.9) / 100);
este código retorna 0,28 em vez de 0,29 jsfiddle.net/9pf0732dTruncar usando operadores bit a bit:
~~0.5 === 0 ~~(-0.5) === 0 ~~14.32794823 === 14 ~~(-439.93) === -439
fonte
A resposta de @Dogbert pode ser melhorada com
Math.trunc
, que trunca em vez de arredondar.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
fonte
Math.trunc
, mas em vez de9.28 * 100
é927.9999
melhor que928
. Você pode querer ler The Perils of Floating PointEscrevi uma resposta usando um método mais curto. Aqui está o que eu inventei
function truncate(value, precision) { var step = Math.pow(10, precision || 0); var temp = Math.trunc(step * value); return temp / step; }
O método pode ser usado assim
truncate(132456.25456789, 5)); // Output: 132456.25456 truncate(132456.25456789, 3)); // Output: 132456.254 truncate(132456.25456789, 1)); // Output: 132456.2 truncate(132456.25456789)); // Output: 132456
Ou, se você quiser uma sintaxe mais curta, aqui está
function truncate(v, p) { var s = Math.pow(10, p || 0); return Math.trunc(s * v) / s; }
fonte
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
fonte
Acho que essa função 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.2,0)); console.log(trunc(241));
fonte
Encontrei um problema: considerando a próxima situação: 2.1 ou 1.2 ou -6.4
E se você quiser sempre 3 casas decimais ou duas ou qualquer outra coisa, 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 função 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/
fonte
x = 0.0000
o testetruncateDecimals (x, 2)
falha. retorna0
. não como esperado0.00
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
fonte
A resposta de @kirilloid parece ser a resposta correta, no entanto, o código principal precisa ser atualizado. Sua solução não trata de números negativos (que alguém mencionou na seção de comentários, mas não foram atualizados no código principal).
Atualizando para uma solução testada final 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(); };
Amostra de uso:
var x = 3.1415629; Logger.log(x.toFixedDown(2)); //or use whatever you use to log
Violino: número JS arredondado para baixo
PS: Repo insuficiente para comentar essa solução.
fonte
Aqui está uma função simples, mas funcional para 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; }
fonte
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);
fonte
Lodash tem alguns métodos de utilitário de matemática que pode rodada , chão , e ceil um número para uma determinada precisão decimal. Isso deixa os zeros à direita.
Eles têm uma abordagem interessante, usando o expoente de um número. Aparentemente, isso evita problemas de arredondamento.
(Nota:
func
éMath.round
ouceil
oufloor
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
fonte
Aqui está 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 de
(f - 0.005).toFixed(2)
fonte
Aquela que está marcada como solução é a melhor solução que encontrei até hoje, mas está com um problema sério com 0 (por exemplo, 0.toFixedDown (2) dá -0,01). Então, 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); }
fonte
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;
fonte
const TO_FIXED_MAX = 100; function truncate(number, decimalsPrecison) { // make it a string with precision 1e-100 number = number.toFixed(TO_FIXED_MAX); // chop off uneccessary digits const dotIndex = number.indexOf('.'); number = number.substring(0, dotIndex + decimalsPrecison + 1); // back to a number data type (app specific) return Number.parseFloat(number); } // example truncate(0.00000001999, 8); 0.00000001
funciona com:
fonte
apenas para apontar uma solução simples que funcionou para mim
convertê-lo em string e 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])
fonte
Aqui está um código ES6 que faz o que você deseja
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
fonte
Number.prototype.truncate = function(places) { var shift = Math.pow(10, places); return Math.trunc(this * shift) / shift; };
fonte
Você pode trabalhar com cordas. Ele verifica se '.' existe e, em seguida, remove parte da string.
truncar (7,88, 1) -> 7,8
truncar (7,889, 2) -> 7,89
truncar (-7,88, 1) -> -7,88
function truncate(number, decimals) { const tmp = number + ''; if (tmp.indexOf('.') > -1) { return +tmp.substr(0 , tmp.indexOf('.') + decimals+1 ); } else { return +number } }
fonte
Estou um pouco confuso sobre por que existem tantas respostas diferentes para uma pergunta tão fundamentalmente simples; eu vi apenas duas abordagens que pareciam valer a pena olhar. Fiz um benchmark rápido para ver a diferença de velocidade usando https://jsbench.me/ .
Esta é a solução que está atualmente (26/09/2020) sinalizada como a resposta:
function truncate(n, digits) { var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"), m = n.toString().match(re); return m ? parseFloat(m[1]) : n.valueOf(); }; [ truncate(5.467,2), truncate(985.943,2), truncate(17.56,2), truncate(0, 1), truncate(1.11, 1) + 22];
No entanto, isso está fazendo coisas de string e regex, o que geralmente não é muito eficiente, e há uma função Math.trunc que faz exatamente o que o OP deseja, mas sem decimais. Portanto, você pode facilmente usar isso mais um pouco de aritmética extra para obter a mesma coisa.
Aqui está outra solução que encontrei neste tópico, que eu usaria:
function truncate(n, digits) { var step = Math.pow(10, digits || 0); var temp = Math.trunc(step * n); return temp / step; } [ truncate(5.467,2), truncate(985.943,2), truncate(17.56,2), truncate(0, 1), truncate(1.11, 1) + 22];
O primeiro método é "99,92% mais lento" do que o segundo, então o segundo é definitivamente aquele que eu recomendaria usar.
Ok, voltando a encontrar outras maneiras de evitar o trabalho ...
fonte