javascript - por - Verificación del año bisiesto mediante operadores bitwise(velocidad asombrosa)
javascript validar año bisiesto (2)
Si un número es divisible por 16 y divisible por 25, es divisible por cuatro veces 25 (100), así como 16 veces 25 (400).
Alguien en JSPerf dejó caer una implementación increíblemente rápida para verificar los años bisiestos del calendario ISO (enlace: Odd bit manipulations ):
function isLeapYear(year) {
return !(year & 3 || year & 15 && !(year % 25));
}
Usando Node.js, lo comparé rápidamente con otras dos implementaciones de una línea que conozco.
function isLeapClassic(y) { return (y % 4 == 0) && !(y % 100 == 0) || (y % 400 == 0); }
function isLeapXOR(y) { return (y % 4 == 0) ^ (y % 100 == 0) ^ (y % 400 == 0); }
function isLeapBitwise(y) { return !(y & 3 || y & 15 && !(y % 25)); }
//quick''n''dirty test on a small range!
//works with negative integers too
for (var i = 1900; i <= 2100; i++) {
console.log(
"year = %d,/t%d%d%d",
i,
isLeapClassic(i),
isLeapXOR(i),
isLeapBitwise(i)
);
}
Funciona como se esperaba, pero mi problema es que no puedo entender cómo. Sé que ((a % b) == (a & (b-1))
cuando b es potencia de dos, entonces (year % 4) == (year & 3)
, pero year & 15 && !(year % 25)
es bastante difícil de entender. ¿Puede alguien explicarme cómo funciona? ¿Alguna referencia sobre esta implementación?
year & 3
es el mismo year % 4
. No es tan complicado, solo representa el ciclo habitual de 4 años.
year & 15
es el mismo year % 16
.
Por lo tanto, no es un año bisiesto si el año no se divide uniformemente por 4, o si no se divide equitativamente por 16, pero se divide equitativamente por 25. Esto significa que cada múltiplo de 25 no es un año bisiesto a menos que también un múltiplo de 16. Como 16 y 25 no tienen factores comunes, la única vez que se cumplen ambas condiciones es cuando el año es un múltiplo de 16 * 25, o 400 años. Los múltiplos de 4 * 25 no se considerarán años bisiestos, lo que representa el ciclo de 100 años.
1900 no fue un año bisiesto porque era divisible por 100, 2000 fue un año bisiesto porque era divisible por 400, y 2100 no será un año bisiesto.