tab - Javascript a fijo no redondeado
title html (14)
Estoy usando javascript para enlazar a algunas casillas de verificación, y toFixed(2)
no está redondeando. ¿Alguna idea de por qué no está redondeando? Por ejemplo, si el número es 859.385
, solo muestra 859.38
lugar de 859.39
.
También he leído que toFixed
puede redondear de forma diferente según el navegador que esté utilizando, ¿alguien sabe cómo evitar esto para que mis cálculos de JavaScript coincidan con mis cálculos de php?
var standardprice = parseFloat($(''#hsprice_''+this.id.split(''_'')[1]).val());
var price = parseFloat($(''#hprice_''+this.id.split(''_'')[1]).val());
var discount = parseFloat($(''#hdiscount_''+this.id.split(''_'')[1]).val());
var deposit = parseFloat($(''#hdeposit_''+this.id.split(''_'')[1]).val());
var currSprice = parseFloat($(''#hTotalSprice'').val());
var currPrice = parseFloat($(''#hTotalPrice'').val());
var currDiscount = parseFloat($(''#hTotalDiscount'').val());
var currDeposit = parseFloat($(''#hTotalDeposit'').val());
currSprice += standardprice;
currPrice += price;
currDiscount += discount;
currDeposit += deposit;
$(''#lblTotalSprice'').text(''$''+addCommas(currSprice.toFixed(2)));
$(''#lblTotalPrice'').text(''$''+addCommas(currPrice.toFixed(2)));
$(''#lblTotalDiscount'').text(''$''+addCommas(currDiscount.toFixed(2)));
$(''#lblTotalDeposit'').text(''$''+addCommas(currDeposit.toFixed(2)));
$(''#hTotalSprice'').val(currSprice.toFixed(2));
$(''#hTotalPrice'').val(currPrice.toFixed(2));
$(''#hTotalDiscount'').val(currDiscount.toFixed(2));
$(''#hTotalDeposit'').val(currDeposit.toFixed(2));
Todavía tengo que encontrar un número que toFixed10 haga mal. ¿Alguien más?
Gracias a blg
y su respuesta que me indicó el método Mozilla''s toFixed10() .
Usando eso, se me ocurrió este trazador de líneas corto, que de hecho cubre todos los casos mencionados aquí ...
function toFixed( num, precision ) {
return (+(Math.round(+(num + ''e'' + precision)) + ''e'' + -precision)).toFixed(precision);
}
Dado que en javascripts ''a función fija, el punto flotante número 5
no pertenece a la mitad superior de un entero, el número dado se redondea hacia abajo si tiene números como estos:
859.385.toFixed(2) // results in 859.38
de hecho, puede agregar números de coma flotante (excepto cero) como aquí:
859.3851.toFixed(2) // results in 859.39
Por lo tanto, los desarrolladores tienden a agregar números como 0.00000000001
para redondearlos de manera apropiada y para no cambiar accidentalmente el valor del número.
Así que se me ocurrió una función que agrega ese número dependiendo de cuántos dígitos quieres que se fije tu número flotante:
// both parameters can be string or number
function toFixed(number, decimals) {
var x = Math.pow(10, Number(decimals) + 1);
return (Number(number) + (1 / x)).toFixed(decimals)
}
toFixed(859.385, 2) //results in 859.39
En las rondas de Chrome, toFixed()
:
859.385 ==> 859.38
859.386 ==> 859.39
Cuando miro la especificación ECMAScript de quinta edición para .toFixed()
(sección 15.7.4.5), no veo que describa explícitamente el redondeo aunque describe algo bastante obtuso que puede ser lo que Chrome ha implementado.
Me parece que si desea controlarlo con un redondeo explícito, entonces probablemente debería usar la solución sugerida frecuentemente de:
var roundedNum = (Math.round( num * 100 ) / 100).toFixed(2);
Esto te garantizará un redondeo predecible como el que estás acostumbrado.
Demostración de trabajo aquí: http://jsfiddle.net/jfriend00/kvpgE/
Esto sucede debido a la representación de punto flotante de JavaScript.
Prueba esto:
Number.prototype.round = function(digits) {
digits = Math.floor(digits);
if (isNaN(digits) || digits === 0) {
return Math.round(this);
}
if (digits < 0 || digits > 16) {
throw ''RangeError: Number.round() digits argument must be between 0 and 16'';
}
var multiplicator = Math.pow(10, digits);
return Math.round(this * multiplicator) / multiplicator;
}
Number.prototype.fixed = function(digits) {
digits = Math.floor(digits);
if (isNaN(digits) || digits === 0) {
return Math.round(this).toString();
}
var parts = this.round(digits).toString().split(''.'');
var fraction = parts.length === 1 ? '''' : parts[1];
if (digits > fraction.length) {
fraction += new Array(digits - fraction.length + 1).join(''0'');
}
return parts[0] + ''.'' + fraction;
}
Uso:
var n = 859.385;
console.log(n.round(2)); // 859.39
console.log(n.fixed(2)); // 859.39
console.log(n.round(4)); // 859.385
console.log(n.fixed(4)); // 859.3850
Hice esto para usar en todos los datos financieros como una mejor función de redondeo. Puedes probarlo en todos los números problemáticos. Javascript permite algún tipo de precisión, así que lo usé para hacer que casi todos los números se redondearan como se esperaba.
function roundTo(n, digits) {
if (digits === undefined) {
digits = 0;
}
var multiplicator = Math.pow(10, digits);
n = parseFloat((n * multiplicator).toFixed(11));
return Math.round(n) / multiplicator;
}
La respuesta de Joy Twindle aquí debería ser la mejor respuesta en lugar de la cantidad de hack arounds.
x = 1859.385;
x = x.toFixed(2);
alert(x);
da un redondeo incorrecto, es decir 1859.38 en vez de 1859.39
x = 1859.385;
x = x.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
alert(x);
da un redondeo correcto de 1.859.39
El único problema es que el resultado devuelto es una cadena con un separador de coma de mil y, por lo tanto, no se puede usar para los cálculos. Usando una expresión regular que obtuve del desbordamiento de la pila para eliminar la coma, el resultado final es
x = 1859.385;
x = x.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
x=x.replace(//,/g,'''');
alert(x);
que ahora devuelve 1859.39 y se puede usar para los cálculos. El valor antes de la expresión regular, es decir, 1,859.39, se puede usar para la visualización html, mientras que el valor sin formato 1859,39 se puede usar para los cálculos.
MDM tiene una https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round . Es más exacto que la mayoría si no todas las respuestas aquí.
Me encontré con este mismo problema hoy, e incluso al intentar sugerencias en otras respuestas encontré que todavía no recibí el resultado que esperaba. Finalmente, como estoy usando AngularJS para mi proyecto actual al encontrarme con esto, pensé que verificaría si AngularJS ya había resuelto el mismo tipo de problema antes y de hecho lo habían hecho. Aquí está la solución que usan y funciona perfectamente para mí:
function toFixed(number, fractionSize) {
return +(Math.round(+(number.toString() + ''e'' + fractionSize)).toString() + ''e'' + -fractionSize);
}
Encontrado aquí: AngularJS filters.js fuente
Me encontré con esto preguntándome por qué Number.toFixed
se comportaba de manera extraña. Veo que la función nativa no es confiable, lo cual es desafortunado. Al analizar las respuestas por curiosidad, veo que la mayoría de ellas * no se comportan correctamente con el número 35.855
ya que TJ Crowder gentilmente comentó sobre cada una de ellas.
Quizás esto responderá a tu pregunta.
function toFixed(n,precision) {
var match=RegExp("(//d+//.//d{1,"+precision+"})(//d)?").exec(n);
if(match===null||match[2]===undefined) {
return n.toFixed(precision);
}
if(match[2]>=5) {
return (Number(match[1])+Math.pow(10,-precision)).toFixed(precision);
}
return match[1];
}
La expresión regular divide su número en una matriz de cadenas como toFixed(35.855,2)
: ["35.855", "35.85", "5"]
. Si el último número (después del corte de precisión) es >=5
, agregue Math.pow(10, -precision)
al número recortado. Esto agregará .01
si está cortando a 2 decimales, .002
a 3, y así sucesivamente.
No sé si esto es infalible, ya que todavía realiza operaciones matemáticas decimales en flotadores que pueden ser impredecibles. Puedo decir que redondea 35.855
hasta 35.86
.
Otro buen número para probar junto con 35.855 es 1.005
No creo que la solución de Robert Messerle maneje 1.005
El ejemplo decimal de redondeo aquí https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round $ revision / 1383484 # Decimal_rounding convierte los números en notación exponencial y parece obtener mejores resultados.
Creé un violín aquí http://jsfiddle.net/cCX5y/2/ que muestra el ejemplo original de Robert Messerle (llamado a toFixedB
) y el de documentos de Mozilla (llamado a toFixed10
).
Todavía tengo que encontrar un número que toFixed10 haga mal. ¿Alguien más?
Puede usar Math.round()
para redondear el número. Si desea redondear a un punto decimal específico, puede emplear un poco de matemática:
var result=Math.round(original*100)/100
Si está buscando obtener un número como salida , entonces considere la técnica Math.round()
en otras respuestas.
Pero si desea obtener una cadena como salida, para presentarla a un ser humano , entonces muchas veces n.toLocaleString()
es más útil que n.toFixed()
.
¿Por qué? Porque también agregará comas o puntos al encabezado de números grandes, que los humanos usan para leer. Por ejemplo:
var n = 1859.385
n.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})
// Produces 1,859.39 in USA (locale en-US)
// Produces 1 859,39 in France (locale fr-FR)
// Produces 1.859,39 in Germany (locale de-DE)
La especificación dice que al pasar undefined
como primer argumento, se usará la configuración regional propia del usuario (según lo especificado por el sistema operativo). Desafortunadamente, como muestra la documentación vinculada, Mozilla usa la configuración regional en-EE en esta situación, pero puede cumplir con la especificación en el futuro.
esto podría ayudar
tofix2Decimals=function(float){
if(parseInt(float)==float)return float.toFixed(2);
$decimals=//.(/d+)/.exec(float)[1].length;
$decimals=$decimals>=2?$decimals+1:3;
float+=Math.pow(10,-$decimals);
return float.toFixed(2);
}
function roundup(num,dec){
dec= dec || 0;
var s=String(num);
if(num%1)s= s.replace(/5$/, ''6'');
return Number((+s).toFixed(dec));
}
var n= 35.855
roundup(n,2)
/ * valor devuelto: (Número) 35.86 * /