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. */