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); }
fuente
1.11.toFixedDown(1) + 22
termina como en1.122
lugar de23.1
. También0.toFixedDown(1)
debería producir0
pero en su lugar produce-0.1
.(-10.2131).toFixedDown(2) // ==> 10.21
. : .(1e-7).toFixedDown(0) // ==> 1e-7
,. Lo hace por1e-(>=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á incorrectamente17.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
fuente
if(isNAN(result) result = 0;
Depende del comportamiento que desee.var a = 5.467; var truncated = Math.floor(a * 100) / 100; // = 5.46
fuente
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 correctaPuede corregir el redondeo restando 0.5 para toFixed, por ejemplo
(f - 0.005).toFixed(2)
fuente
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
Enlace JSFiddle .
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.
fuente
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/25tgrzq1Buena 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
fuente
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; };
fuente
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/9pf0732dTruncar usando operadores bit a bit:
~~0.5 === 0 ~~(-0.5) === 0 ~~14.32794823 === 14 ~~(-439.93) === -439
fuente
La respuesta de @ Dogbert se puede mejorar con
Math.trunc
, que trunca en lugar de redondear.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
fuente
Math.trunc
, sino que9.28 * 100
es en927.9999
lugar de928
. Es posible que desee leer The Perils of Floating PointEscribí 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; }
fuente
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
fuente
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));
fuente
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; };
https://jsfiddle.net/huttn155/7/
fuente
x = 0.0000
la pruebatruncateDecimals (x, 2)
falla. devuelve0
. 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
fuente
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.
fuente
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; }
fuente
El tipo resultante sigue siendo un 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);
fuente
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
esMath.round
oceil
ofloor
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));
Enlace al código fuente
fuente
Aquí mi opinión sobre el tema:
convert.truncate = function(value, decimals) { decimals = (decimals === undefined ? 0 : decimals); return parseFloat((value-(0.5/Math.pow(10, decimals))).toFixed(decimals),10); };
Es solo una versión un poco más elaborada de
(f - 0.005).toFixed(2)
fuente
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); }
fuente
Esto es lo que uso:
var t = 1; for (var i = 0; i < decimalPrecision; i++) t = t * 10; var f = parseFloat(value); return (Math.floor(f * t)) / t;
fuente
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:
fuente
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])
fuente
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
fuente
Number.prototype.truncate = function(places) { var shift = Math.pow(10, places); return Math.trunc(this * shift) / shift; };
fuente
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 } }
fuente
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 ...
fuente