Un colega mío se topó con un método para hacer flotar los números del piso usando un bit a bit o:
var a = 13.6 | 0; //a == 13
Estábamos hablando de eso y preguntándonos algunas cosas.
- ¿Como funciona? Nuestra teoría era que el uso de dicho operador convierte el número en un número entero, eliminando así la parte fraccional
- ¿Tiene alguna ventaja sobre hacerlo
Math.floor
? Tal vez es un poco más rápido? (juego de palabras no previsto) - ¿Tiene alguna desventaja? Tal vez no funciona en algunos casos? La claridad es obvia, ya que tuvimos que resolverlo, y bueno, estoy escribiendo esta pregunta.
Gracias.
javascript
floating-point
bit-manipulation
Alex Turpin
fuente
fuente
3000000000.1 | 0
evalúa a -1294967296. Por lo tanto, este método no puede aplicarse para los cálculos de dinero (especialmente en los casos en que multiplica por 100 para evitar números decimales).0.1 + 0.2 == 0.3
en una consola de JavaScript. Si su idioma lo admite, debe usar un tipo decimal. Si no, guarde centavos en su lugar.Respuestas:
Todas las operaciones bit a bit, excepto el desplazamiento a la derecha sin signo
>>>
, funcionan en enteros de 32 bits con signo. Por lo tanto, el uso de operaciones bit a bit convertirá un flotante a un entero.http://jsperf.com/or-vs-floor/2 parece un poco más rápido
Math.floor(NaN) === NaN
mientras que(NaN | 0) === 0
fuente
Math.floor(NaN) === NaN
, mientras(NaN | 0) === 0
. Esa diferencia puede ser importante en algunas aplicaciones.asm.js
(donde aprendí por primera vez). Es más rápido si no por otra razón porque no está llamando a una función en elMath
objeto, una función que en cualquier momento podría reemplazarse como enMath.floor = function(...)
.(value | 0) === value
podría usarse para verificar que un valor es de hecho un número entero y solo un número entero (como en el código fuente de Elm @ dwayne-crooks vinculado). Yfoo = foo | 0
podría usarse para forzar cualquier valor a un entero (donde los números de 32 bits se truncan y todos los no números se convierten en 0).Esto es truncamiento en oposición al piso. La respuesta de Howard es correcta; Pero agregaría que
Math.floor
hace exactamente lo que se supone que debe hacer con respecto a los números negativos. Matemáticamente, eso es un piso.En el caso que describió anteriormente, el programador estaba más interesado en truncar o cortar el decimal por completo. Aunque, la sintaxis que usaron oscurece el hecho de que están convirtiendo el flotante en un int.
fuente
Math.floor(8589934591.1)
produce el resultado esperado,8589934591.1 | 0
NO .En ECMAScript 6, el equivalente de
|0
es Math.trunc , algo así debería decir:fuente
Math.trunc()
funciona con un número mayor o igual a 2 ^ 31 y| 0
no funcionaTu primer punto es correcto. El número se convierte en un entero y, por lo tanto, se eliminan los dígitos decimales. Tenga en cuenta que se
Math.floor
redondea al siguiente número entero hacia menos infinito y, por lo tanto, da un resultado diferente cuando se aplica a números negativos.fuente
Javascript representa
Number
como números flotantes de doble precisión de 64 bits .Math.floor
trabaja con esto en mente.Las operaciones bit a bit funcionan en enteros con signo de 32 bits . Los enteros con signo de 32 bits usan el primer bit como significante negativo y los otros 31 bits son el número. Debido a esto, los números mínimos y máximos permitidos de 32 bits con signo son -2,147,483,648 y 2147483647 (0x7FFFFFFFF), respectivamente.
Entonces, cuando lo estás haciendo
| 0
, esencialmente lo estás haciendo& 0xFFFFFFFF
. Esto significa que cualquier número que se represente como 0x80000000 (2147483648) o mayor regresará como un número negativo.Por ejemplo:
También. Las operaciones bit a bit no se "plantan". Se truncan , lo que es lo mismo que decir, redondean más cerca
0
. Una vez que pasan en torno a los números negativos,Math.floor
rondas abajo , mientras que a nivel de bits comienzan redondeo hacia arriba .Como dije antes,
Math.floor
es más seguro porque funciona con números flotantes de 64 bits. Bitwise es más rápido , sí, pero está limitado al alcance firmado de 32 bits.Para resumir:
0 to 2147483647
.-2147483647 to 0
.-2147483648
y mayores que2147483647
.Si realmente quieres modificar el rendimiento y usar ambos:
Solo para agregar
Math.trunc
trabajos como operaciones bit a bit. Entonces puedes hacer esto:fuente
Las especificaciones dicen que se convierte en un entero:
Rendimiento: esto se ha probado en jsperf antes.
nota: enlace muerto a la especificación eliminada
fuente