Usando bitwise O 0 para floor un número


Un colega mío se topó con un método para floor float numbers usando un bitwise or:

var a = 13.6 | 0; //a == 13

Estábamos hablando de ello y preguntándonos algunas cosas.

  • ¿Cómo funciona? Nuestra teoría era que el uso de tal operador arroja el número a un entero, eliminando así la parte fraccionaria
  • ¿Tiene alguna ventaja sobre hacer Math.floor? Tal vez es un poco más rápido? (juego de palabras no intencionado)
  • ¿Tiene alguna desventaja? Tal vez no funciona en algunos casos? Claridad es obvio, ya que tuvimos que resolverlo, y bueno, estoy escribiendo esta pregunta.

Gracias.

Author: Alex Turpin, 2011-09-20

6 answers

¿Cómo funciona? Nuestra teoría era que el uso de un operador de este tipo arroja la número a un entero, eliminando así la parte fraccionaria

Todas las operaciones bit a bit excepto el desplazamiento derecho sin signo, >>>, funcionan con enteros de 32 bits con signo. Así que usando operaciones bitwise convertirá un flotador a un entero.

Tiene alguna ventaja sobre hacer Matemáticas.piso? Tal vez es un poco más rápido? (juego de palabras no intencionado)

Http://jsperf.com/or-vs-floor/2 parece un poco más rápido

¿Tiene algún inconveniente? Tal vez no funciona en algunos casos? La claridad es obvia, ya que teníamos que averiguarlo, y bueno, Estoy escribiendo esta pregunta.

  • No pasará JSLint.
  • solo enteros con signo de 32 bits
  • Comportamiento comparativo impar: Math.floor(NaN) === NaN, mientras que (NaN | 0) === 0
 115
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-02 03:32:07

Esto es truncamiento en contraposición al piso. La respuesta de Howard es algo así como correcta; pero yo añadiría que Math.floor hace exactamente lo que se supone que hace con respecto a los números negativos. Matemáticamente, eso es lo que es un piso.

En el caso descrito anteriormente, el programador estaba más interesado en truncamiento o cortar el decimal completamente. Aunque, la sintaxis que usaron oscurece el hecho de que están convirtiendo el float a un int.

 24
Author: Chad La Guardia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-20 15:54:29

En ECMAScript 6, el equivalente de |0 es Matemáticas.trunc , más o menos debería decir:

Devuelve la parte integral de un número eliminando cualquier dígito fraccionario. Simplemente trunca el punto y los dígitos detrás de él, no importa si el argumento es un número positivo o un número negativo.

Math.trunc(13.37)   // 13
Math.trunc(42.84)   // 42
Math.trunc(0.123)   //  0
Math.trunc(-0.123)  // -0
Math.trunc("-1.123")// -1
Math.trunc(NaN)     // NaN
Math.trunc("foo")   // NaN
Math.trunc()        // NaN
 13
Author: zangw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-10 13:44:55

Su 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 Math.floor redondea al siguiente entero hacia menos infinito y por lo tanto da un resultado diferente cuando se aplica a números negativos.

 10
Author: Howard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-20 15:51:51
  • Las especificaciones dicen que se convierte en un entero:

    Sea lnum ToInt32(lval).

  • Rendimiento: esto ha sido probado en jsperf antes.

 5
Author: pimvdb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-20 16:54:52

Javascript representa Number como Números flotantes de 64 bits de doble precisión.

Math.floor funciona con esto en mente.

Las operaciones a nivel de bits funcionan en enteros de 32 bits firmados. los enteros firmados de 32 bits usan el primer bit como significante negativo y los otros 31 bits son el número. Debido a esto, el número mínimo y máximo permitido números firmados de 32 bits son -2,147,483,648 y 2147483647 (0x7FFFFFFFF), respectivamente.

Así que cuando estás haciendo | 0, estás esencialmente haciendo es & 0xFFFFFFFF. Esto significa que cualquier número que se represente como 0x80000000 (2147483648) o mayor volverá como un número negativo.

Por ejemplo:

 // Safe
 (2147483647.5918 & 0xFFFFFFFF) ===  2147483647
 (2147483647      & 0xFFFFFFFF) ===  2147483647
 (200.59082098    & 0xFFFFFFFF) ===  200
 (0X7FFFFFFF      & 0xFFFFFFFF) ===  0X7FFFFFFF

 // Unsafe
 (2147483648      & 0xFFFFFFFF) === -2147483648
 (-2147483649     & 0xFFFFFFFF) ===  2147483647
 (0x80000000      & 0xFFFFFFFF) === -2147483648
 (3000000000.5    & 0xFFFFFFFF) === -1294967296

También. Las operaciones bitwise no "floor". Ellos truncan, que es lo mismo que decir, redondean más cerca de 0. Una vez que vas alrededor de números negativos, Math.floor redondea hacia abajo mientras que comienza a redondear 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 limitado al alcance firmado de 32 bits.

Para resumir:

  • Funciona de la misma manera si se trabaja desde 0 to 2147483647.
  • Bitwise es 1 número apagado si se trabaja desde -2147483647 to 0.
  • Bitwise es completamente diferente para números menores que -2147483648 y mayores que 2147483647.

Si realmente quieres ajustar el rendimiento y usar ambos:

function floor(n) {
    if (n >= 0 && n < 0x80000000) {
      return n & 0xFFFFFFFF;
    }
    if (n > -0x80000000 && n < 0) {
      return (n - 1) & 0xFFFFFFFF;
    }
    return Math.floor(n);
}

Solo para agregar Math.trunc funciona como operaciones bitwise. Así que puedes hacer esto:

function floor(n) {
    if (n > -0x80000000 && n < 0x80000000) {
      return n & 0xFFFFFFFF;
    }
    return Math.trunc(n);
}
 0
Author: ShortFuse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-04 15:39:03