Saltar al contenido

Rápida implementación de funciones trigonométricas para c++

Te recomendamos que pruebes esta solución en un entorno controlado antes de pasarlo a producción, saludos.

Solución:

Aquí hay algunas buenas diapositivas sobre cómo hacer aproximaciones de series de potencias (aunque NO series de Taylor) de funciones trigonométricas: Funciones matemáticas más rápidas.

Está dirigido a los programadores de juegos, lo que significa que la precisión se sacrifica por el rendimiento, pero debería poder agregar otro término o dos a las aproximaciones para recuperar parte de la precisión.

Lo bueno de esto es que también debería poder extenderlo a SIMD fácilmente, de modo que pueda calcular el seno o el coseno de 4 valores a la vez (2 si está usando doble precisión).

Espero que ayude…

Esto debería ser bastante rápido si puede optimizarlo aún más, por favor hágalo y publique el código en pastie.org o algo así.

Especificaciones de la computadora -> 512 MB de RAM, Visual Studio 2010, Windows XP Professional SP3 versión 2002, Intel (R) Pentium (R) 4 CPU 2.8GHZ.

Esto es increíblemente preciso y en realidad proporcionará resultados ligeramente mejores en algunas situaciones. Por ejemplo, 90, 180, 270 grados en C++ devuelve un decimal distinto de 0.

TABLA COMPLETA DE 0 a 359 grados: https://pastee.org/dhwbj

FORMATO -> GRADO # -> MINE_X(#) , CosX(#) , MINE_Z(#) , SinZ(#).

A continuación se muestra el código utilizado para construir la tabla que se muestra arriba. Probablemente pueda hacerlo aún más preciso si usa un tipo de datos más grande. Utilicé un corto sin firmar e hice N/64000. Entonces, cualquiera que sea el cos (##) y el pecado (##) donde más cerca esté, redondeé a ese índice. También traté de usar la menor cantidad posible de datos adicionales para que esta no fuera una tabla desordenada con 720 valores flotantes para cos y sen. Lo que probablemente daría mejores resultados, pero sería una completa pérdida de memoria. La siguiente tabla es tan pequeña como pude hacerlo. Me gustaría ver si es posible hacer una ecuación que pueda redondear a todos estos valores cortos y usar eso en su lugar. No estoy seguro de si sería más rápido, pero eliminaría la mesa por completo y probablemente no reduciría la velocidad en nada o mucho.

Por lo tanto, la precisión en comparación con las operaciones cos/sin de C++ es del 99,99998 % al 100 %.

A continuación se muestra la tabla utilizada para calcular los valores cos/sin.

static const unsigned __int16 DEGREE_LOOKUP_TABLE[91] =

    64000, 63990, 63961, 63912, 63844, 63756,
    63649, 63523, 63377, 63212, 63028, 62824,
    62601, 62360, 62099, 61819, 61521, 61204,
    60868, 60513, 60140, 59749, 59340, 58912,
    58467, 58004, 57523, 57024, 56509, 55976,
    55426, 54859, 54275, 53675, 53058, 52426,
    51777, 51113, 50433, 49737, 49027, 48301,
    47561, 46807, 46038, 45255, 44458, 43648,
    42824, 41988, 41138, 40277, 39402, 38516,
    37618, 36709, 35788, 34857, 33915, 32962,
    32000, 31028, 30046, 29055, 28056, 27048,
    26031, 25007, 23975, 22936, 21889, 20836,
    19777, 18712, 17641, 16564, 15483, 14397,
    13306, 12212, 11113, 10012,  8907,  7800,
     6690,  5578,  4464,  3350,  2234,  1117,
        0,
;

A continuación se muestra el código real que realiza los cálculos cos/sin.

    int deg1 = (int)degrees;
    int deg2 = 90 - deg1;
    float module = degrees - deg1;
    double vX = DEGREE_LOOKUP_TABLE[deg1] * 0.000015625;
    double vZ = DEGREE_LOOKUP_TABLE[deg2] * 0.000015625;
    double mX = DEGREE_LOOKUP_TABLE[deg1 + 1] * 0.000015625;
    double mZ = DEGREE_LOOKUP_TABLE[deg2 - 1] * 0.000015625;
    float vectorX = vX + (mX - vX) * module;
    float vectorZ = vZ + (mZ - vZ) * module;
    if (quadrant & 1)
    
        float tmp = vectorX;
        if (quadrant == 1)
        
            vectorX = -vectorZ;
            vectorZ = tmp;
         else 
            vectorX = vectorZ;
            vectorZ = -tmp;
        
     else if (quadrant == 2) 
        vectorX = -vectorX;
        vectorZ = -vectorZ;
    

VELOCIDADES POR DEBAJO usando las especificaciones de computadora mencionadas originalmente. Lo estaba ejecutando en modo de depuración antes de que este sea el modo de depuración, pero se ejecutó a través del ejecutable que creo que es depuración sin depuración.

MI MÉTODO

1,000 Iterations -> 0.004641 MS or 4641 NanoSeconds.
100,000 Iterations -> 4.4328 MS.
100,000,000 Iterations -> 454.079 MS.
1,000,000,000 Iterations -> 4065.19 MS.

MÉTODO COS/SIN

1,000 Iterations -> 0.581016 MS or 581016 NanoSeconds.
100,000 Iterations -> 25.0049 MS.
100,000,000 Iterations -> 24,731.6 MS.
1,000,000,000 Iterations -> 246,096 MS.

Entonces, para resumir lo anterior, realizar tanto cos (###) como sin (###) con mi estrategia permite aproximadamente 220,000,000 ejecuciones por segundo. Utilizando las especificaciones de la computadora que se muestran originalmente. Esto es bastante rápido y utiliza muy poca memoria, por lo que es un excelente sustituto de las funciones matemáticas cos/sin que normalmente se encuentran en C++. Si desea ver la precisión, abra el enlace que se muestra arriba y hay una impresión de los grados 0 a 359. También admite 0 a 89 y cuadrantes 0 a 3. Por lo tanto, debe usar eso o realizar ( GRADOS % 90).

Si desea utilizar una implementación personalizada, consulte aquí, aquí y aquí

También aquí (desplácese hasta Universal SIMD-Mathlibrary) si necesita calcular sen/cos para arreglos grandes

También puede intentar usar los intrínsecos de C++ SSE. Mira aquí

Tenga en cuenta que la mayoría de los compiladores modernos admiten optimizaciones SSE y SSE2. Para Visual Studio 2010, por ejemplo, deberá habilitarlo manualmente. Una vez que haga esto, se usará una implementación diferente para la mayoría de las funciones matemáticas estándar.

Una opción más es usar DirectX HLSL. Mira aquí. Tenga en cuenta que hay unas buenas funciones sincos que devuelven tanto el seno como el coseno.

Por lo general, uso IPP (que no es gratuito). Para más detalles, mira aquí

Aquí puedes ver las comentarios y valoraciones de los usuarios

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *