Estoy tratando de truncar números decimales a lugares decimales. Algo como esto:
5.467 -> 5.46
985.943 -> 985.94
toFixed(2)
hace lo correcto pero redondea el valor. No necesito redondear el valor. Espero que esto sea posible en javascript.
Estoy tratando de truncar números decimales a lugares decimales. Algo como esto:
5.467 -> 5.46
985.943 -> 985.94
toFixed(2)
hace lo correcto pero redondea el valor. No necesito redondear el valor. Espero que esto sea posible en javascript.
Respuestas:
upd :
Entonces, después de todo, resultó que los errores de redondeo siempre lo perseguirán, sin importar cuánto intente compensarlos. Por tanto, el problema debe resolverse representando los números exactamente en notación 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]
Solución antigua propensa a errores basada en la compilación de otras:
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);
}
1.11.toFixedDown(1) + 22
termina como en 1.122
lugar de 23.1
. También 0.toFixedDown(1)
debería producir 0
pero en su lugar produce -0.1
.
(-10.2131).toFixedDown(2) // ==> 10.21
. : .
(1e-7).toFixedDown(0) // ==> 1e-7
,. Lo hace por 1e-(>=7)
(ex: 1e-8
, 1e-9
, ...).
La respuesta de Dogbert es buena, pero si su código tiene que lidiar con números negativos, Math.floor
por sí solo puede dar resultados inesperados.
Por ejemplo Math.floor(4.3) = 4
, peroMath.floor(-4.3) = -5
Utilice una función auxiliar como esta para obtener 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
Aquí hay una versión más conveniente de esta función:
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
Si ese no es el comportamiento deseado, inserte una llamada a Math.abs
en la primera línea:
var multiplier = Math.pow(10, Math.abs(digits)),
EDITAR: shendz señala correctamente que el uso de esta solución con a = 17.56
producirá incorrectamente 17.55
. Para obtener más información sobre por qué sucede esto, lea Lo que todo informático debe saber sobre la aritmética de coma flotante . Desafortunadamente, escribir una solución que elimine todas las fuentes de error de punto flotante es bastante complicado con javascript. En otro idioma, usarías enteros o tal vez un tipo decimal, pero con javascript ...
Esta solución debe ser 100% precisa, pero también será más 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 aquellos que necesitan velocidad pero también quieren evitar errores de punto flotante, pruebe algo como BigDecimal.js . Puede encontrar otras bibliotecas Javascript BigDecimal en esta pregunta SO: "¿Existe una buena biblioteca Javascript BigDecimal?" y aquí hay una buena publicación de blog sobre bibliotecas matemáticas para Javascript
if(isNAN(result) result = 0;
Depende del comportamiento que desee.
var a = 5.467;
var truncated = Math.floor(a * 100) / 100; // = 5.46
truncate(-3.14)
y recibo de -4
vuelta, definitivamente lo llamaría indeseable.
var a = 65.1
var truncated = Math.floor(a * 100) / 100; // = 65.09
Por lo tanto, esta no es una solución correcta
Puede corregir el redondeo restando 0.5 para toFixed, por ejemplo
(f - 0.005).toFixed(2)
Considere aprovechando la doble tilde:~~
.
Anote el número. Multiplique por dígitos significativos después del decimal para que pueda truncar a cero con ~~
. Divide ese multiplicador de vuelta. Lucro.
function truncator(numToTruncate, intDecimalPlaces) {
var numPower = Math.pow(10, intDecimalPlaces); // "numPowerConverter" might be better
return ~~(numToTruncate * numPower)/numPower;
}
Estoy tratando de resistirme a envolver la ~~
llamada en parens; El orden de las operaciones debería hacer que funcione correctamente, creo.
alert(truncator(5.1231231, 1)); // is 5.1
alert(truncator(-5.73, 1)); // is -5.7
alert(truncator(-5.73, 0)); // is -5
EDITAR: Mirando hacia atrás, sin querer también he manejado casos para redondear a la izquierda del decimal.
alert(truncator(4343.123, -2)); // gives 4300.
La lógica es un poco loca para ese uso y puede beneficiarse de una refactorización rápida. Pero sigue funcionando. Más suerte que buena.
Math
prototipo con esto y verifica los NaN-s antes de ejecutarlo, sería perfecto.
truncator((10 * 2.9) / 100, 2)
return 0.28 en lugar de 0.29 ... jsfiddle.net/25tgrzq1
Buena solución de una línea:
function truncate (num, places) {
return Math.trunc(num * Math.pow(10, places)) / Math.pow(10, places);
}
Entonces llámalo con:
truncate(3.5636232, 2); // returns 3.56
truncate(5.4332312, 3); // returns 5.433
truncate(25.463214, 4); // returns 25.4632
Pensé en lanzar una respuesta usando |
ya que es simple y funciona bien.
truncate = function(number, places) {
var shift = Math.pow(10, places);
return ((number * shift) | 0) / shift;
};
or
ing con 0 significa "simplemente conservar lo que ya tengo". Hace lo que hace mi ~~
respuesta, pero con una sola operación bit a bit. Aunque también tiene la misma limitación que la escrita: no podemos pasar de 2 ^ 31 .
truncate((10 * 2.9) / 100);
este código devuelve 0.28 en lugar de 0.29 jsfiddle.net/9pf0732d
Truncar usando operadores bit a bit:
~~0.5 === 0
~~(-0.5) === 0
~~14.32794823 === 14
~~(-439.93) === -439
La respuesta de @ Dogbert se puede mejorar con Math.trunc
, que trunca en lugar de redondear.
Existe una diferencia entre redondear y truncar. Truncar es claramente el comportamiento que busca esta pregunta. Si llamo a truncar (-3.14) y recibo -4 de vuelta, definitivamente lo llamaría indeseable. - @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
Math.trunc
, sino que 9.28 * 100
es en 927.9999
lugar de 928
. Es posible que desee leer The Perils of Floating Point
Escribí una respuesta usando un método más corto. Esto es lo que se me ocurrió
function truncate(value, precision) {
var step = Math.pow(10, precision || 0);
var temp = Math.trunc(step * value);
return temp / step;
}
El método se puede utilizar así
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
O, si quieres una sintaxis más corta, aquí tienes
function truncate(v, p) {
var s = Math.pow(10, p || 0);
return Math.trunc(s * v) / s;
}
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
Creo que esta función podría ser una solución simple:
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));
Encontré un problema: considerando la siguiente situación: 2.1 o 1.2 o -6.4
¿Qué pasa si quieres siempre 3 decimales o dos o lo que sea? Entonces, debes completar los ceros iniciales a la derecha
// 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 es la función fija 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;
};
x = 0.0000
la prueba truncateDecimals (x, 2)
falla. devuelve 0
. no como se esperaba0.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
La respuesta de @kirilloid parece ser la respuesta correcta, sin embargo, el código principal debe actualizarse. Su solución no se ocupa de los números negativos (que alguien mencionó en la sección de comentarios pero no se ha actualizado en el código principal).
Actualizando eso a una completa solución final probada:
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 de muestra:
var x = 3.1415629;
Logger.log(x.toFixedDown(2)); //or use whatever you use to log
Violín: Número JS redondeado hacia abajo
PD: No hay suficientes repositorios para comentar sobre esa solución.
Aquí hay una función simple pero funcional para truncar números hasta 2 lugares decimales.
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;
}
Lodash tiene algunos métodos de utilidad matemática que pueden redondear , piso y techo un número a una precisión decimal dada. Esto deja ceros finales.
Adoptan un enfoque interesante, utilizando el exponente de un número. Aparentemente, esto evita problemas de redondeo.
(Nota: func
es Math.round
o ceil
o floor
en el código siguiente)
// 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));
El que está marcado como solución es la mejor solución que he encontrado hasta hoy, pero tiene un problema grave con 0 (por ejemplo, 0.toFixedDown (2) da -0.01). Entonces sugiero usar esto:
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);
}
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 con:
solo para señalar una solución simple que funcionó para mí
convertirlo a cadena y luego regex it ...
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)
Se puede abreviar como
var number_truncated = parseFloat(('' + 123.4568908).match(/\d*\.\d{4}/)[0])
Aquí hay un código ES6 que hace lo que quieres
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
Puedes trabajar con cadenas. Comprueba si '.' existe y luego elimina parte de la cadena.
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
}
}
Estoy un poco confundido acerca de por qué hay tantas respuestas diferentes a una pregunta tan fundamentalmente simple; sólo hay dos enfoques que vi que merecen ser analizados. Hice una evaluación comparativa rápida para ver la diferencia de velocidad usando https://jsbench.me/ .
Esta es la solución que actualmente (26/9/2020) está marcada como la respuesta:
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];
Sin embargo, esto está haciendo cosas de cadenas y expresiones regulares, lo que generalmente no es muy eficiente, y hay una función Math.trunc que hace exactamente lo que el OP quiere sin decimales. Por lo tanto, puede usarlo fácilmente más un poco de aritmética adicional para obtener lo mismo.
Aquí hay otra solución que encontré en este hilo, que es la que usaría:
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];
El primer método es "99,92% más lento" que el segundo, por lo que el segundo es definitivamente el que recomendaría usar.
Bien, volvamos a buscar otras formas de evitar el trabajo ...