Extendiendo un poco el tema de aproximar funciones matemáticas complejas que comencé en éste post. Agrego ahora un modo de aproximar las funciones seno y coseno que encontré en Internet.
Antes de empezar, quiero aclarar que la información la tomé de éste post de la página Polygonal Labs, que a su vez encontró la información en éste post.
Luego de aclarado eso, vamos a lo verdaderamente interesante.
Quizá lo primero que se nos ocurre para aproximar una función cualquiera (trigonométricas incluidas) es usar una serie de Taylor (recuerdo haberlo intentado).
El problema es que la fórmula es algo complicada y sólo aproxima correctamente cerca del origen (ya que centramos Taylor en 0, por practicidad)
En el ejemplo, se puede ver el seno en verde y el polinomio de Taylor de grado 4 en rojo.
Si hacemos un Zoom, vemos como se comporta fantásticamente hasta π/2 para luego desviarse.
Por supuesto, podríamos tomar Taylor de un mayor órden, pero la idea es hacer las cuentas lo más cortas posibles.
Entonces, es cuando la genialidad surge. Por si no lo habían notado, la función seno en un período se parece a una parábola. Donde:
a = 0 b = 4/π c = -4/π^2
Pero no es una gran aproximación, incluso, es obvio que es aún peor que usar Taylor.
En éste punto vale aclarar que cuando necesitamos valores negativos, podemos invertir la parábola
Bien, continuando con lo anterior, vamos a buscar una solución al problema de la falta de calidad. Para solucionarlo, observamos que el error es siempre por exceso (es decir, que los valores son mayores o iguales a los verdaderos). Entonces, buscamos una función cuyo error sea por defecto (es decir, valores menores), teniendo cuidado en que sea correcto el valor en 0, π/2 y π
Podemos observar que el módulo del error es mayor al de la aproximación anterior.
Bueno, promediamos ambos valores y obtenemos una aproximación aún mejor. Es más, la aproximación es casi perfecta.
Sólo falta aclarar que las ecuaciones para el coseno son bastante parecidas (apenas un poco más complejas) a las del seno.
Pero basta de teoría. El código sería el siguiente (para la primer aproximación, 14 veces más rápida):
Código :
// Mantenemos el ángulo entre -π y π if (x < -3.14159265) { x += 6.28318531; } else if (x > 3.14159265) { x -= 6.28318531; } // Obtenemos el seno if (x < 0) { sin = 1.27323954 * x + .405284735 * x * x; } else { sin = 1.27323954 * x - 0.405284735 * x * x; } // Obtenemos el coseno x += 1.57079632; if (x > 3.14159265) { x -= 6.28318531; } if (x < 0) { cos = 1.27323954 * x + 0.405284735 * x * x } else { cos = 1.27323954 * x - 0.405284735 * x * x; } }
Para la segunda aproximación (más precisa, pero 8 veces más rápida):
Código :
// Mantenemos el ángulo entre -π y π if (x < -3.14159265) { x += 6.28318531; } else if (x > 3.14159265) { x -= 6.28318531; } // Obtenemos el seno if (x < 0) { sin = 1.27323954 * x + .405284735 * x * x; if (sin < 0) { sin = .225 * (sin *-sin - sin) + sin; } else { sin = .225 * (sin * sin - sin) + sin; } } else { sin = 1.27323954 * x - 0.405284735 * x * x; if (sin < 0) { sin = .225 * (sin *-sin - sin) + sin; } else { sin = .225 * (sin * sin - sin) + sin; } } // Obtenemos el coseno x += 1.57079632; if (x > 3.14159265) { x -= 6.28318531; } if (x < 0) { cos = 1.27323954 * x + 0.405284735 * x * x if (cos < 0) { cos = .225 * (cos *-cos - cos) + cos; } else { cos = .225 * (cos * cos - cos) + cos; } } else { cos = 1.27323954 * x - 0.405284735 * x * x; if (cos < 0) cos = .225 * (cos *-cos - cos) + cos; else cos = .225 * (cos * cos - cos) + cos; }
Aclaro que no ubicamos el código en una función ya que consume importantes recursos.
Justo lo que estaba buscando, probando!! Por:bicho_O
Asi de masticadito todo es mas facil, gracias por este post, me ha sido de gran ayuda... Por:jose bernal_blog
Si al final de todo, mantienes el ángulo entre -PI y PI ... Taylor te lo hubiera resuelto con un error mínimo y controlado. Siempre puedes aproximar Taylor desde otro punto (cualquiera) pero en general desde un múltiplo de PI (para que sea cero igualmente).
Desde el punto de vista matemático esto es ... bueno, no tiene ningún rigor Por:_CONEJO_blog
Si al final de todo, mantienes el ángulo entre -PI y PI ... Taylor te lo hubiera resuelto con un error mínimo y controlado. Siempre puedes aproximar Taylor desde otro punto (cualquiera) pero en general desde un múltiplo de PI (para que sea cero igualmente).
Desde el punto de vista matemático esto es ... bueno, no tiene ningún rigor
No, es más un truco matemático que otra cosa, pero las cuentas son más cortas que Taylor de órden 5 (el órden necesario para aproximar con un error menor o igual. Por:HernanRivas
Esto... o me pierdo en algún sitio, o la función de flash es 3 veces más rápida que la segunda función. Las funciones nativas de Math, por estar escritas directamente en el player suelen ser mucho rápidas que las que el usuario define con ActionScript. O eso o hay algún error aquí:
Código :
x = 1.337; var t = getTimer(); for (a = 0; a < 10000; a++) { // Mantenemos el ángulo entre -π y π if (x < -3.14159265) { x += 6.28318531; } else if (x > 3.14159265) { x -= 6.28318531; } // Obtenemos el seno if (x < 0) { sin = 1.27323954 * x + .405284735 * x * x; if (sin < 0) { sin = .225 * (sin * -sin - sin) + sin; } else { sin = .225 * (sin * sin - sin) + sin; } } else { sin = 1.27323954 * x - 0.405284735 * x * x; if (sin < 0) { sin = .225 * (sin * -sin - sin) + sin; } else { sin = .225 * (sin * sin - sin) + sin; } } } t -= getTimer(); trace(-t); j = getTimer(); for (b = 0; b < 10000; b++) { y = Math.sin(x); } j -= getTimer(); trace(-j);
Ahora lo checkeo, la verdad, me fié en lo que decía la página y no hice más que corroborar que los valores fueran correctos (es decir, la calidad de la aproximación y no la velocidad).
hola: esta informacion fue muy util muchas gracias, tambien quisiera si nos ayudarias con las series de potencia para el seno, coseno, tangente, logaritmo natural, e elevado a la "x" Por:hans_blog
necesito los procedimientos de las identidades trigonometricas es urgente Por:andres_blog
Y se mejora si hacemos una asignación de la función nativa en nuestro código:
Código :
x = 1.337;
j = getTimer(); for (b = 0; b < 10000; b++) { y = Math.sin(x); } j -= getTimer(); trace(-j);
r=Math.sin; // esta es la aceleración. q=getTimer(); for (b = 0; b < 10000; b++) { y = r(x); } q -= getTimer(); trace(-q);
En mi equipo de 39ms. a 31ms. para el seno, otras Math mejoran todavía mucho más. Por:Teseo
agan algo mas efiente estos problemas son muy sencillos Por:panter_blog
chupmela pinches ñoños vale pito, yo estudio y trabajo y si puedo jajajaaj Por:daniel_blog
quiero ejemplos Por:janeth ramirez_blog
esta de peloz y mas ejemplos Por:jhesica _rock_blog
nesecitamos ejemplos de problemas para a si poder guiarnos mejor Por:lelsie raquel marin sarav