tan calculate arcoseno c++ math trigonometry sin cmath cos

calculate - sin y cos c++



Sin y Cos dan resultados inesperados para ángulos bien conocidos (3)

Estoy seguro de que esta es una pregunta realmente estúpida, pero cuando paso un ángulo de 180 grados en las funciones cos () y sin () de c / c ++, parece que recibo un valor incorrecto. Sé que debería ser: pecado de 0.0547 y cos de 0.99 pero obtengo pecado de 3.5897934739308216e-009 y cos de -1.00000

Mi código es:

double radians = DegreesToRadians( angle ); double cosValue = cos( radians ); double sinValue = sin( radians );

DegreesToRadians () es:

double DegreesToRadians( double degrees ) { return degrees * PI / 180; }

Gracias :)


C / C ++ proporciona funciones sin(a) , cos(a) , tan(a) , etc. que requieren un parámetro con unidades de radianes en lugar de grados . double DegreesToRadians(d) realiza una conversión cercana pero aproximada a medida que se redondean los resultados de la conversión. También la máquina M_PI está cerca, pero no tiene el mismo valor que la matemática irracional π .

El código de OP con 180 pasado a DegreesToRadians(d) y luego a sin()/cos() da resultados que difieren de lo esperado debido al redondeo, la precisión finita de double() y un posible valor débil para PI .

Una mejora es realizar la reducción de argumentos en grados antes de llamar a la función trigonométrica. Lo siguiente reduce el ángulo primero a un rango de -45 ° a 45 ° y luego llama a sin() . Esto asegurará que grandes valores de N en sind(90.0*N) --> -1.0, 0.0, 1.0 . . Nota: sind(360.0*N +/- 30.0) puede no ser exactamente igual a +/-0.5 . Algunas consideraciones adicionales necesarias.

#include <math.h> #include <stdio.h> static double d2r(double d) { return (d / 180.0) * ((double) M_PI); } double sind(double x) { if (!isfinite(x)) { return sin(x); } if (x < 0.0) { return -sind(-x); } int quo; double x90 = remquo(fabs(x), 90.0, &quo); switch (quo % 4) { case 0: // Use * 1.0 to avoid -0.0 return sin(d2r(x90)* 1.0); case 1: return cos(d2r(x90)); case 2: return sin(d2r(-x90) * 1.0); case 3: return -cos(d2r(x90)); } return 0.0; } int main(void) { int i; for (i = -360; i <= 360; i += 15) { printf("sin() of %.1f degrees is % .*e/n", 1.0 * i, DBL_DECIMAL_DIG - 1, sin(d2r(i))); printf("sind() of %.1f degrees is % .*e/n", 1.0 * i, DBL_DECIMAL_DIG - 1, sind(i)); } return 0; }

Salida

sin() of -360.0 degrees is 2.4492935982947064e-16 sind() of -360.0 degrees is -0.0000000000000000e+00 // Exact sin() of -345.0 degrees is 2.5881904510252068e-01 // 76-68 = 8 away // 2.5881904510252076e-01 sind() of -345.0 degrees is 2.5881904510252074e-01 // 76-74 = 2 away sin() of -330.0 degrees is 5.0000000000000044e-01 // 44 away // 0.5 5.0000000000000000e-01 sind() of -330.0 degrees is 4.9999999999999994e-01 // 6 away sin() of -315.0 degrees is 7.0710678118654768e-01 // 68-52 = 16 away // square root 0.5 --> 7.0710678118654752e-01 sind() of -315.0 degrees is 7.0710678118654746e-01 // 52-46 = 6 away sin() of -300.0 degrees is 8.6602540378443860e-01 sind() of -300.0 degrees is 8.6602540378443871e-01 sin() of -285.0 degrees is 9.6592582628906842e-01 sind() of -285.0 degrees is 9.6592582628906831e-01 sin() of -270.0 degrees is 1.0000000000000000e+00 // Exact sind() of -270.0 degrees is 1.0000000000000000e+00 // Exact ...


En primer lugar, un coseno de 180 grados debería ser igual a -1 , por lo que el resultado que obtuvo es correcto.

En segundo lugar, a veces no puede obtener valores exactos cuando utiliza las funciones sin/cos/tan etc., ya que siempre obtiene resultados que son los más cercanos a los correctos . En su caso, el valor que obtuvo del sin es el más cercano a cero.

El valor de sin(PI) que obtuvo difiere de cero solo en el noveno dígito (!) Después del punto flotante. 3.5897934739308216e-009 es casi igual a 0.000000004 y es casi igual a cero.


Tengo el mismo problema que el OP al convertir la aplicación a 64 bits.
Mi solución es usar las nuevas funciones math.h __cospi () y __sinpi ().
El rendimiento es similar (incluso 1% más rápido) que cos () y sin ().

// cos(M_PI * -90.0 / 180.0) returns 0.00000000000000006123233995736766 //__cospi( -90.0 / 180.0) returns 0.0, as it should // #define degree2rad 3.14159265359/180 // #define degree2rad M_PI/ 180.0 // double rot = -degree2rad * ang; // double sn = sin(rot); // double cs = cos(rot); double rot = -ang / 180.0; double sn = __sinpi(rot); double cs = __cospi(rot);

De mates.h:

/* __sinpi(x) returns the sine of pi times x; __cospi(x) and __tanpi(x) return the cosine and tangent, respectively. These functions can produce a more accurate answer than expressions of the form sin(M_PI * x) because they avoid any loss of precision that results from rounding the result of the multiplication M_PI * x. They may also be significantly more efficient in some cases because the argument reduction for these functions is easier to compute. Consult the man pages for edge case details. */