javascript - que - qué es js
Redondeo gaussiano/bancario en JavaScript (6)
He estado usando Math.Round(myNumber, MidpointRounding.ToEven)
en C # para hacer mi redondeo del lado del servidor, sin embargo, el usuario necesita saber ''en vivo'' cuál será el resultado de la operación del lado del servidor que significa (evitar un Solicitud Ajax ) creando un método JavaScript para replicar el método MidpointRounding.ToEven
utilizado por C #.
MidpointRounding.ToEven es un redondeo gaussiano / bancario , un método de redondeo muy común para sistemas contables descrito here .
¿Alguien tiene alguna experiencia con esto? He encontrado ejemplos en línea, pero no se redondean a un número dado de lugares decimales ...
Esa es una gran solución de @soegaard. Aquí hay un pequeño cambio que lo hace funcionar para puntos decimales:
bankers_round(n:number, d:number=0) {
var x = n * Math.pow(10, d);
var r = Math.round(x);
var br = (((((x>0)?x:(-x))%1)===0.5)?(((0===(r%2)))?r:(r-1)):r);
return br / Math.pow(10, d);
}
Y mientras tanto, aquí hay algunas pruebas:
console.log(" 1.5 -> 2 : ", bankers_round(1.5) );
console.log(" 2.5 -> 2 : ", bankers_round(2.5) );
console.log(" 1.535 -> 1.54 : ", bankers_round(1.535, 2) );
console.log(" 1.525 -> 1.52 : ", bankers_round(1.525, 2) );
console.log(" 0.5 -> 0 : ", bankers_round(0.5) );
console.log(" 1.5 -> 2 : ", bankers_round(1.5) );
console.log(" 0.4 -> 0 : ", bankers_round(0.4) );
console.log(" 0.6 -> 1 : ", bankers_round(0.6) );
console.log(" 1.4 -> 1 : ", bankers_round(1.4) );
console.log(" 1.6 -> 2 : ", bankers_round(1.6) );
console.log(" 23.5 -> 24 : ", bankers_round(23.5) );
console.log(" 24.5 -> 24 : ", bankers_round(24.5) );
console.log(" -23.5 -> -24 : ", bankers_round(-23.5) );
console.log(" -24.5 -> -24 : ", bankers_round(-24.5) );
Este es el flujo de pila inusual donde las respuestas inferiores son mejores que las aceptadas. Simplemente limpié la solución de @xims y la hice un poco más legible:
function bankersRound(n, d=2) {
var x = n * Math.pow(10, d);
var r = Math.round(x);
var br = Math.abs(x) % 1 === 0.5 ? (r % 2 === 0 ? r : r-1) : r;
return br / Math.pow(10, d);
}
Estrictamente hablando, todas estas implementaciones deben manejar el caso de un número negativo de dígitos para redondear.
Es un caso de ventaja, pero aún así sería prudente no permitirlo (o ser muy claro acerca de lo que eso significa, por ejemplo, -2 se redondea a la cantidad más cercana de cientos).
La respuesta aceptada se redondea a un número dado de lugares. En el proceso, llama a Fixed, que convierte el número en una cadena. Como esto es caro, ofrezco la solución a continuación. Redondea un número que termina en 0.5 al número par más cercano. No maneja el redondeo a un número arbitrario de lugares.
function even_p(n){
return (0===(n%2));
};
function bankers_round(x){
var r = Math.round(x);
return (((((x>0)?x:(-x))%1)===0.5)?((even_p(r))?r:(r-1)):r);
};
const isEven = (value: number) => value % 2 === 0;
const isHalf = (value: number) => {
const epsilon = 1e-8;
const remainder = Math.abs(value) % 1;
return remainder > .5 - epsilon && remainder < .5 + epsilon;
};
const roundHalfToEvenShifted = (value: number, factor: number) => {
const shifted = value * factor;
const rounded = Math.round(shifted);
const modifier = value < 0 ? -1 : 1;
return !isEven(rounded) && isHalf(shifted) ? rounded - modifier : rounded;
};
const roundHalfToEven = (digits: number, unshift: boolean) => {
const factor = 10 ** digits;
return unshift
? (value: number) => roundHalfToEvenShifted(value, factor) / factor
: (value: number) => roundHalfToEvenShifted(value, factor);
};
const roundDollarsToCents = roundHalfToEven(2, false);
const roundCurrency = roundHalfToEven(2, true);
- Si no te gusta la sobrecarga de llamar a Fijo ()
- Queremos poder suministrar una escala arbitraria.
- No quiero introducir errores de punto flotante.
- Quiere tener un código legible, reutilizable
roundHalfToEven es una función que genera una función de redondeo de escala fija. Realizo mis operaciones de divisas en centavos, en lugar de dólares, para evitar introducir FPE. El parámetro Unshift existe para evitar la sobrecarga de un Shifting y Shifting nuevamente para esas operaciones.
function evenRound(num, decimalPlaces) {
var d = decimalPlaces || 0;
var m = Math.pow(10, d);
var n = +(d ? num * m : num).toFixed(8); // Avoid rounding errors
var i = Math.floor(n), f = n - i;
var e = 1e-8; // Allow for rounding errors in f
var r = (f > 0.5 - e && f < 0.5 + e) ?
((i % 2 == 0) ? i : i + 1) : Math.round(n);
return d ? r / m : r;
}
console.log( evenRound(1.5) ); // 2
console.log( evenRound(2.5) ); // 2
console.log( evenRound(1.535, 2) ); // 1.54
console.log( evenRound(1.525, 2) ); // 1.52
Demostración en vivo: http://jsfiddle.net/NbvBp/
Para lo que parece ser un tratamiento más riguroso de esto (nunca lo he usado), puedes probar esta implementación de BigNumber .