2010-03-26 11 views
25

Por lo general, no soy partidario de microbenchmarks. Pero este tiene un resultado muy interesante.
http://ernestdelgado.com/archive/benchmark-on-the-floor/¿Por qué Math.floor de Javascript es la forma más lenta de calcular piso en Javascript?

Sugiere que Math.floor es la manera más lenta para calcular piso en Javascript. ~~n, n|n, n&n todo siendo más rápido.
Esto parece bastante impactante, ya que supongo que las personas que implementan Javascript en los navegadores modernos de hoy serían algunas personas bastante inteligentes.

¿El piso hace algo importante que otros métodos no hacen? ¿Hay alguna razón para usarlo?

+3

'~~ n',' n | n' y 'n & n' no produce el mismo resultado que' Math.floor'. Los primeros tres solo pueden devolver enteros de 32 bits. Pruebe 'n = 50000000000.4'. – kennytm

+0

En mi navegador (FF 3.6.a algo) todos tenían la misma velocidad en los resultados (alrededor de "3", lo que sea que eso signifique). Pruébelo en diferentes navegadores (la pequeña prueba se proporciona en la parte inferior) en lugar de simplemente tomar los resultados por su valor nominal. Realmente no hay ninguna razón por la cual debería ser notablemente más lento. –

+3

En realidad, ejecutar su punto de referencia en FF 3.6 muestra que 'Math.floor' es el más rápido –

Respuesta

26

No tiene nada que ver con los navegadores modernos. Tiene que ver con la implementación del estándar ECMA. No se puede simplemente cambiar el rendimiento de una determinada función, incluso si hay una forma más rápida. Podría romper el código existente.

El Math.Floor tiene que tener en cuenta una gran cantidad de escenarios diferentes para manejar diferentes tipos. ¿Podrían haber hecho diferentes escenarios más rápidos tomando atajos como describió? Tal vez podrían, pero eso podría haber roto otros escenarios. Solo porque algo en la superficie parezca pequeño, no significa que no haya un iceberg debajo.

+7

+1 Lento o no, es probable que sea la única cosa que lo hace * correctamente * –

+1

Buen punto. 'Math.floor (" foo ")' devuelve 'NaN'. Pero si ese es el único beneficio, estoy tentado de usar otro método. Al menos hasta que Javascript sea compatible con la división de enteros. – z5h

+0

No digo que siempre deba usar Math.Floor, es lento. Es solo que cuando diseñan una función tienen que dar cuenta de muchos escenarios diferentes que la gente podría hacer. Una cosa sobre JS es que debe ser fácil de programar, lo que significa que tuvieron que tomar precauciones adicionales al construirlo y en algunos casos les hizo tomar el camino más largo. – kemiller2002

31

La razón principal por la que Math.floor es más lento (lo que realmente es, en algunas pruebas que he hecho es más rápido) es que implica una llamada de función. Las implementaciones más antiguas de JavaScript no podían hacer llamadas a funciones en línea. Los motores más nuevos pueden alinear la llamada, o al menos hacer que la búsqueda de la propiedad sea más rápida, pero aún necesitan una condición de protección en caso de que usted (o alguna otra secuencia de comandos) sobrescriba la función Math.floor. Sin embargo, la sobrecarga es mínima, por lo que no hay mucha diferencia en la velocidad.

Más importante aún, como se mencionó en varios comentarios, los otros métodos no son equivalentes. Todos trabajan haciendo operaciones bit a bit. Los operadores bit a bit convierten automáticamente sus operandos a enteros de 32 bits truncando el número. Eso está bien si el número cabe en 32 bits, pero los números de JavaScript son flotantes de 64 bits, que podrían ser mucho más grandes que 2147483647.

También dan un resultado diferente para números negativos, ya que la conversión a enteros trunca y Math.floor siempre redondea abajo. Por ejemplo, Math.floor(-2.1) === -3, pero (-2.1) | (-2.1) === -2.

Si sabe sólo se trata de un número positivo menor que 2147483648, y que necesita para exprimir cada gota de rendimiento de su código en los navegadores antiguos (Asegúrese de que en realidad es el cuello de botella en primer lugar. Es probable que no es .), Usaría un método aún más simple: x|0. No evalúa la variable dos veces, y funciona incluso si x es una expresión (simplemente asegúrese de ponerlo entre paréntesis para que no se encuentre con problemas de precedencia).

+0

"JavaScript no puede alinear funciones porque es dinámico y puede reemplazar Math.floor con una función diferente". Eso es un non sequitur. Los compiladores de JIT pueden y hacen llamadas de función dinámicas en línea. Los JIT de rastreo son especialmente buenos en esto. El dinamismo se maneja mediante controles de guardia o añadiendo activadores de invalidación. Una implementación específica podría o no podría estar en línea. Entonces, como con todas las microoptimizaciones, si realmente importa, mídelas en las plataformas de destino. –

+0

@Ants: Buen punto. A eso me refería con los valores de la función en caché, pero lo redacté incorrectamente. –

+6

Sé que esta respuesta tiene un par de años, pero las llamadas de función V8 incorporan ahora, y esto da como resultado ['Math.floor', así como también bitwise hacks] (http://jsperf.com/js-floors). – josh3736

Cuestiones relacionadas