elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado:


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  [C++] Series de Taylor: sen(x)
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: [C++] Series de Taylor: sen(x)  (Leído 11,428 veces)
Zeta255

Desconectado Desconectado

Mensajes: 5


Ver Perfil
[C++] Series de Taylor: sen(x)
« en: 23 Marzo 2021, 19:07 pm »

Hola tengo una duda, me pide hacer una funcion de sen con sumatoria, para eso ingresare un valor x y me dara el valor con sumatoria pero las funciones tiene el mismo criterio de numero impar pero los signos +- son intercarlados como podria hacer para que me salga de igual manera;
Código
  1.  
  2.  
  3. //Solicite al usuario el valor de x y calcule e^x
  4. #include<iostream>
  5. #include<iomanip>
  6. using namespace std;
  7.  
  8. int main()
  9. {
  10. double x, num=1,den=1,f=1,signo;
  11. cout<<"INGRESE el valor de x para sen: ";
  12. cin>>x;
  13. cout<<setprecision(4);
  14. for(int i=1;i<=360;i++)
  15. {
  16. num = num*x;
  17. den = den*i;
  18. f =( f + num/den);
  19.  
  20. }
  21.  
  22. cout<<"EL valor de sen"<<x<<" = "<<f;
  23.  
  24. }


« Última modificación: 24 Marzo 2021, 07:21 am por K-YreX » En línea

K-YreX
Moderador
***
Desconectado Desconectado

Mensajes: 1.008



Ver Perfil
Re: Ayuda con codigo de c++
« Respuesta #1 en: 23 Marzo 2021, 21:32 pm »

La verdad es que la explicación es un poco complicada para el que no sepa de qué le están hablando.
Intuyo que la historia empieza por las series de Taylor y su forma de aproximar funciones como el sen(x) mediante una sumatoria.
Para ver la fórmula de la serie de Taylor para sen(x): https://es.wikipedia.org/wiki/Serie_de_Taylor#Funciones_trigonom%C3%A9tricas
La fórmula dice algo así como:
Código:
sen(x) = SUM(n=0->inf) ((-1)^n / (2n+1)! * x^(2n+1)) =
       = x^1/1! - x^3/3! + x^5/5! - x^7/7! + x^9/9! - ...
Ahora igual ya sí podemos empezar a hacer algo...

Si te das cuenta tú estás calculando:
Código:
sen(x) = 1+x^1/1 + x^2/2 + x^3/4 + x^4/16 + ... 
Por lo que parece que ahí fallan más cosas.

De todas formas, cambiar el signo es muy sencillo. Aunque no nos demos cuenta, cuando cambiamos el signo de algo lo estamos multiplicando por -1. Entonces:
Código
  1. int numero = 5;
  2. for(int i = 0; i < 10; ++i)
  3.  cout << numero << " ";
  4.  numero *= -1; // numero = numero * -1
  5. }
Salida:
Código:
5 -5 5 -5 5 -5 5 -5 5 -5


En línea

Código
  1. cout << "Todos tenemos un defecto, un error en nuestro código" << endl;
Zeta255

Desconectado Desconectado

Mensajes: 5


Ver Perfil
Re: Ayuda con codigo de c++
« Respuesta #2 en: 23 Marzo 2021, 23:14 pm »

segun lo que entendi va asi, pero no me compila no se que estare haciendo mal, me tira nan.

Código
  1. #include<iostream>
  2. #include <math.h>
  3. #include<iomanip>
  4.  
  5. using namespace std;
  6. int main(){
  7. int x, numerador=1, denominador=1, sen,f=0;
  8.  
  9. cout<<"ingrese el valor de x para sen: "; cin>>x;
  10. cout<<setprecision(4);
  11. for (int i=1; i<=10;i++)
  12. {
  13. numerador=numerador*(-1^x);
  14. denominador=denominador*(2*i+1);
  15. sen=(numerador/denominador)*(x^(2*x+1));
  16. f=f+sen;
  17. }
  18. cout<<"el valor de sen"<<x<<"= "<<f;
  19. }
« Última modificación: 24 Marzo 2021, 05:40 am por Zeta255 » En línea

K-YreX
Moderador
***
Desconectado Desconectado

Mensajes: 1.008



Ver Perfil
Re: [C++] Series de Taylor: sen(x)
« Respuesta #3 en: 24 Marzo 2021, 07:29 am »

Lo primero: avisarte de que he borrado el otro tema que has abierto para el mismo problema.
Lo segundo: es mejor si los títulos de los temas son algo más descriptivos así que he cambiado el título de este tema.

En C++ el operador ^ es un XOR (OR exclusivo) que funciona bit a bit. Para usar potencias hay que utilizar la función pow(). Podrías hacerlo así limitándote a usar la fórmula con potencias y factoriales pero la cantidad de cálculos que va a tener que hacer tu programa va a ser muy grande.

Lo mejor es aprovechar que tu programa es iterativo para ahorrarte operaciones que ya tienes.
Piensa que si en una iteración tienes 1! y lo multiplicas por 2, ya tienes 2!. Si 2! lo multiplicas por 3, ya tienes 3!; y así sucesivamente sin tener que hacer todas las operaciones en cada iteración.
Lo mismo pasa con una potencia: si tienes x y lo multiplicas por x, ya tienes x^2. Si x^2 lo multiplicas por x, ya tienes x^3 y así sucesivamente también.

Ahora tienes que ver cómo ir almacenando estos resultados parciales en cada iteración.
No puedo ser más concreto ahora mismo porque no tengo tiempo.
En línea

Código
  1. cout << "Todos tenemos un defecto, un error en nuestro código" << endl;
BloodSharp


Desconectado Desconectado

Mensajes: 813


¡ Hiperfoco !


Ver Perfil WWW
Re: [C++] Series de Taylor: sen(x)
« Respuesta #4 en: 24 Marzo 2021, 15:20 pm »

Esta es la implementación de la función seno multiplataforma de ReactOS, espero que te sirva:

Código
  1. /*
  2.   * COPYRIGHT:        See COPYING in the top level directory
  3.   * PROJECT:          ReactOS CRT
  4.   * FILE:             lib/sdk/crt/math/sin.c
  5.   * PURPOSE:          Generic C Implementation of sin
  6.   * PROGRAMMER:       Timo Kreuzer (timo.kreuzer@reactos.org)
  7.   */
  8.  
  9. #ifdef _MSC_VER
  10. #pragma warning(suppress:4164) /* intrinsic not declared */
  11. #pragma function(sin)
  12. #endif /* _MSC_VER */
  13.  
  14. #define PRECISION 9
  15. #define M_PI 3.141592653589793238462643
  16.  
  17. static double sin_off_tbl[] = {0.0, -M_PI/2., 0, -M_PI/2.};
  18. static double sin_sign_tbl[] = {1,-1,-1,1};
  19.  
  20. double
  21. sin(double x)
  22. {
  23.     int quadrant;
  24.     double x2, result;
  25.  
  26.     /* Calculate the quadrant */
  27.     quadrant = (int)(x * (2./M_PI));
  28.  
  29.     /* Get offset inside quadrant */
  30.     x = x - quadrant * (M_PI/2.);
  31.  
  32.     /* Normalize quadrant to [0..3] */
  33.     quadrant = (quadrant - 1) & 0x3;
  34.  
  35.     /* Fixup value for the generic function */
  36.     x += sin_off_tbl[quadrant];
  37.  
  38.     /* Calculate the negative of the square of x */
  39.     x2 = - (x * x);
  40.  
  41.     /* This is an unrolled taylor series using <PRECISION> iterations
  42.       * Example with 4 iterations:
  43.       * result = 1 - x^2/2! + x^4/4! - x^6/6! + x^8/8!
  44.       * To save multiplications and to keep the precision high, it's performed
  45.       * like this:
  46.       * result = 1 - x^2 * (1/2! - x^2 * (1/4! - x^2 * (1/6! - x^2 * (1/8!))))
  47.       */
  48.  
  49.     /* Start with 0, compiler will optimize this away */
  50.     result = 0;
  51.  
  52. #if (PRECISION >= 10)
  53.     result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20);
  54.     result *= x2;
  55. #endif
  56. #if (PRECISION >= 9)
  57.     result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18);
  58.     result *= x2;
  59. #endif
  60. #if (PRECISION >= 8)
  61.     result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16);
  62.     result *= x2;
  63. #endif
  64. #if (PRECISION >= 7)
  65.     result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12*13*14);
  66.     result *= x2;
  67. #endif
  68. #if (PRECISION >= 6)
  69.     result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12);
  70.     result *= x2;
  71. #endif
  72. #if (PRECISION >= 5)
  73.     result += 1./(1.*2*3*4*5*6*7*8*9*10);
  74.     result *= x2;
  75. #endif
  76.     result += 1./(1.*2*3*4*5*6*7*8);
  77.     result *= x2;
  78.  
  79.     result += 1./(1.*2*3*4*5*6);
  80.     result *= x2;
  81.  
  82.     result += 1./(1.*2*3*4);
  83.     result *= x2;
  84.  
  85.     result += 1./(1.*2);
  86.     result *= x2;
  87.  
  88.     result += 1;
  89.  
  90.     /* Apply correct sign */
  91.     result *= sin_sign_tbl[quadrant];
  92.  
  93.     return result;
  94. }


B#
En línea



Zeta255

Desconectado Desconectado

Mensajes: 5


Ver Perfil
Re: [C++] Series de Taylor: sen(x)
« Respuesta #5 en: 24 Marzo 2021, 22:17 pm »

lo he modificado con respecto a lo que me has dicho sinceramente no se que hacer ya, lo hago asi segun la formular pero me sigue dando nan no se porque no me calcula nada.



Código
  1. // Utilizar sumatoria taylor para calcular el valor de SEN con respecto a "X"
  2.  
  3. #include<iostream>
  4. #include <math.h>
  5. #include<iomanip>
  6.  
  7. using namespace std;
  8. int main(){
  9. double x, sen,numero, numerador=1, denominador=1,f=0;
  10.  
  11. cout<<"ingrese el valor de x para sen: "; cin>>x;
  12. for (int i=1; i<=360;i++)
  13. {
  14. sen=x*((i*i)+1);
  15. numero=(-1*i);
  16. numerador= numerador+(sen*numero);
  17. denominador=denominador+((i*i)+(1));
  18. f=f+(numerador/denominador);
  19. }
  20. cout<<"el valor de sen"<<x<<"= "<<f;
  21. }
En línea

K-YreX
Moderador
***
Desconectado Desconectado

Mensajes: 1.008



Ver Perfil
Re: [C++] Series de Taylor: sen(x)
« Respuesta #6 en: 26 Marzo 2021, 22:36 pm »

El problema de que te muestre nan como resultado es porque estás calculando números demasiado grandes. Realizar una serie de Taylor para el sen(x) con una precisión de 360 (como estás calculando tú) es una locura.
Llamando precisión al número de elementos de la serie que se calculan, tenemos lo siguiente:
Código:
Elemento 1: denominador = 1! = (1 * 2 - 1)!
Elemento 2: denominador = 3! = (2 * 2 - 1)!
Elemento 3: denominador = 5! = (3 * 2 - 1)!
Elemento 4: denominador = 7! = (4 * 2 - 1)!
...
Elemento 360: denominador = (360 * 2 - 1)! = 719!
Puedes intentar calcular 719! a ver qué pasa...

Una precisión de 10 es más que suficiente para una aproximación decente.
Dicho esto volvamos con el código en sí. La cosa es calcular cada uno de los elementos de la serie correctamente. Empezamos.
La estructura general del programa es la siguiente:
Código
  1. #include <iostream>
  2. #include <cmath>
  3.  
  4. using namespace std;
  5.  
  6. const int PRECISION = 10;
  7.  
  8. int main() {
  9.  double x = 2; // Un valor cualquiera para calcular sen(x)
  10.  
  11.  double resultado = 0;
  12.  for(int i = 0; i < PRECISION; ++i) {
  13.    resultado += signo * numerador / denominador;
  14.  }
  15.  
  16.  cout << "El resultado aproximado de sen(" << x << ") es: " << resultado << endl;
  17.  cout << "El resultado real de sen(" << x << ") es: " << sin(x) << endl;
  18. }
Ahora falta calcular cada una de las variables (signo, numerador, denominador).

Para calcular el signo, como ya te dije, basta con ir multiplicando por -1 en cada iteración.
Código
  1. //...
  2. int signo = 1; // Empezamos con 1 porque el primer elemento es positivo
  3. for(int i = 0; i < PRECISION; ++i) {
  4.  resultado += signo * numerador / denominador;
  5.  signo *= -1; // Cambiamos el signo a -1 para la siguiente iteracion
  6. }
  7. //...

Ahora para calcular el numerador, como ya dije también, hay que darse cuenta de que en cada iteración está elevado a un exponente 2 veces mayor.
Código:
Elemento 1: numerador = x^1 = x ^ (1 * 2 - 1)
Elemento 2: numerador = x^3 = x ^ (2 * 2 - 1)
Elemento 3: numerador = x^5 = x ^ (3 * 2 - 1)
...
La primera opción es calcular:
Código
  1. for(int i = 0; i < PRECISION; ++i) {
  2.  numerador = pow(x, i * 2 - 1);
  3.  //...
  4. }
Pero esto requiere demasiados cálculos innecesarios. Como ya dije:
Citar
Lo mismo pasa con una potencia: si tienes x y lo multiplicas por x, ya tienes x^2. Si x^2 lo multiplicas por x, ya tienes x^3 y así sucesivamente también.
Entonces la mejor opción es:
Código
  1. //...
  2. double numerador = x; // El primer numerador es x^1 entonces lo dejamos ya almacenado
  3. for(int i = 0; i < PRECISION; ++i) {
  4.  resultado += signo * numerador / denominador;
  5.  signo *= -1; // Cambiamos el signo a -1 para la siguiente iteracion
  6.  numerador *= (x * x); // Si tenemos x^1 y lo multiplicamos por x^2 (x*x), obtenemos x^3
  7. }
  8. //...

Y ya sólo quedaría el denominador. Vuelvo a mencionar lo que dije en el mensaje anterior:
Citar
Piensa que si en una iteración tienes 1! y lo multiplicas por 2, ya tienes 2!. Si 2! lo multiplicas por 3, ya tienes 3!; y así sucesivamente sin tener que hacer todas las operaciones en cada iteración.
Aquí también podríamos calcular el factorial de (2^n-1) pero volverían a ser un montón de cálculos innecesarios. Vamos a ver cómo funcionan los factoriales otra vez:
Código:
Elemento 1: denominador = 1! = (1 * 2 - 1)!
Elemento 2: denominador = 3! = (2 * 2 - 1)! = 1! * 2 * 3
Elemento 3: denominador = 5! = (3 * 2 - 1)! = 3! * 4 * 5
Elemento 4: denominador = 7! = (4 * 2 - 1)! = 5! * 6 * 7
...
Como ves, si en la primera iteración tenemos 1!, luego hay que multiplicar por 2 y por 3 para conseguir 3!. Para conseguir el 5! como ya tenemos 3! sólo hay que multiplicar por 4 y por 5 y así sucesivamente.
Código
  1. //...
  2. double denominador = 1; // El primer denominador es 1! (1) entonces lo dejamos ya almacenado
  3. for(int i = 0; i < PRECISION; ++i) {
  4.  resultado += signo * numerador / denominador;
  5.  signo *= -1; // Cambiamos el signo a -1 para la siguiente iteracion
  6.  numerador *= (x * x); // Si tenemos x^1 y lo multiplicamos por x^2 (x*x), obtenemos x^3
  7.  denominador *= ((i+2) * 2 - 2) * ((i+2) * 2 - 1);
  8. }
  9. //...
Tenemos que sumar 2 a i porque al empezar en 0, obtendríamos números negativos en las primeras iteraciones. Este valor que se suma a i dependerá del número (i) con el que se empiecen a contar las iteraciones.
En línea

Código
  1. cout << "Todos tenemos un defecto, un error en nuestro código" << endl;
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines