2012-04-13 31 views
12

he visto una serie de preguntas acerca de las simulaciones y animaciones en JavaScript, que a menudo implica el cálculo de la hipotenusa:hipotenusa más rápida en javascript?

hypot = Math.sqrt(x*x + y*y); 

Desde coordenadas cartesianas son el arma de elección en la mayoría de estos motores, estos cálculos son necesarios para encuentre la distancia entre pares de puntos, etc. Por lo tanto, cualquier aceleración en el cálculo de la hipotenusa podría ser de gran ayuda para muchos proyectos.

Para ese fin, ¿puede ver un método más rápido que la simple implementación anterior? Encontré una aproximación que fue marginalmente más rápida en Chrome, pero resultó ser mucho más lenta en Firefox, basada en this approximation function in SuperCollider.

Editar 2015-08-15: Cambié la respuesta aceptada a Math.hypot; Sospecho que el enfoque pragmático en este momento sería usar Math.hypot o una función hipotética sintetizada si no está disponible, y compararla con el cuadrado (por respuesta de sch) si eso es suficiente y Math.hypot no está disponible.

+3

usted podría utilizar siempre [algo de magia 0x5f3759df] (http://en.wikipedia.org/wiki/Fast_inverse_square_root) – violet313

+1

Es noble de su parte desea acelerar cada guión que utiliza la fórmula de Pitágoras. Sin embargo, no creo que exista una solución general para hacer que la fórmula sea más rápida (de lo contrario, no estaríamos usando la versión de 2.500 años). En lugar de tratar de hacer que la fórmula sea más rápida, intente refactorizar su código para que use menos la fórmula, y solo después de que haya demostrado que la fórmula es el cuello de botella en el rendimiento de su código. – Kevin

+0

@Kevin: en C o en algún otro idioma con gastos generales más bajos, de hecho hay aproximaciones que aceleran las cosas. Si una aproximación es útil depende de la precisión que necesita un modelo, pero para la física del juego generalmente valdría la pena si hace que el juego sea más fluido. –

Respuesta

1

En ECMAScript ES6 puede utilizar Math.hypot:

// ES5 support 
 

 
Math.hypot = Math.hypot || function(x, y){ return Math.sqrt(x*x + y*y) } 
 

 
var x = 3, y = 4; 
 

 
document.write(Math.hypot(x, y))

Editar: Puede ejecutar esta prueba en una pestaña en blanco, son 2 millones de operaciones con tanto métodos, los resultados son muy buenos, es un 24% más rápido.

var i, tmp, x = 55, y = 66, end, ini = performance.now(); 

// Math.sqrt operation 
i = 0; 
ini = performance.now(); 
tmp = 0; 
while(i++ < 2000000){ 
    tmp += Math.sqrt(x*x + y*y) 
} 
end = performance.now(); 
console.log(tmp, "Math.sqrt operation: " + (end - ini) + " ms"); 

// Math.hypot 

i = 0; 
ini = performance.now(); 
tmp = 0; 
while(i++ < 2000000){ 
    tmp += Math.hypot(x, y) 
} 
end = performance.now(); 

console.log(tmp, "Math.hypot: " + (end - ini) + " ms"); 

Nota: En esta prueba, se utiliza de ES6 Math.hypot.

enter image description here

+0

Ooh, ¿alguna idea sobre el rendimiento de eso? –

+0

@PhilH Edit, probé la operación con Math.sqrt y Math.hypot, puedes verla. En esta prueba se usa la función original de Math.hypot –

+0

'hypotot 'aparece constantemente más lento en Chrome 62. Intenté ponerlo en una función estricta para minimizar la interferencia externa (https://gist.github.com/anonymous/159187ac9a8d3caf97737cd9cf551c1a), pero sqrt sigue siendo la operación más rápida. Quizás agregaron alguna protección contra el desbordamiento/subdesbordamiento en algún momento? – Arthur2e5

13

A menudo, no es necesario calcular la raíz cuadrada y hypot^2 = x*x + y*y es suficiente. Este es el caso, por ejemplo, si quiere comparar las distancias y no necesita los valores reales.

0

Puede ver la igualdad de x y y. Si son iguales, puede calcular hipotenusa como (x + y)/sqrt(2), donde sqrt(2) es una constante.

Por lo que este método se puede utilizar para el caso donde x = y. Para otros casos, puede usarse con una imprecisión máxima de ~ 41%. Este es un gran error. Pero cuando especifica los límites de error permitidos, puede usar este método. Por ejemplo, si define el error permitido al 5%, puede obtener que b debe estar entre 0.515*a y 1.942*a.

Si no necesita una imprecisión perfecta de sus cálculos, puede mejorar el rendimiento de los cálculos con un rango de valores.

Por analogía puede mirar a la igualdad de x o y a zero. Y con cierta precisión calcula hipotenusa más rápido para estos casos.

P.S. He leído sobre esto en el russian article.

6

Un punto importante que muchos no saben:

hypot = Math.sqrt(x*x + y*y);

que funciona en teoría, pero en la práctica puede fallar. Si x es tan grande que x * x se desborda, el código producirá un resultado infinito.

Aquí se explica cómo calcular sqrt (x x + y y) sin riesgo de desbordamiento.

max = maximum(|x|, |y|) 
min = minimum(|x|, |y|) 
r = min/max 
return max*sqrt(1 + r*r) 

de referencia y el texto completo: John D.Cocine - http://www.johndcook.com/blog/2010/06/02/whats-so-hard-about-finding-a-hypotenuse/

+0

(más uno) es bueno mencionar problemas de implementación como cálculos desbordados, etc. –

+0

más un detalle, asegúrese de que al menos uno de 'x' y' y' no es cero, de lo contrario el resultado será 'infinito' –

Cuestiones relacionadas