用 C 中的泰勒级数逼近 Sine(x) 并遇到很多问题
Approximating Sine(x) with a Taylor series in C and having a lot of problems
我正在尝试使用泰勒级数和阶乘的斯特林逼近来逼近 C 中的 sine(x),但对于 n<5 和 -0 对于任何 n=>5,我得到了非常奇怪的答案。我昨天才开始学习,所以如果一些更有经验的程序员可以看看它并告诉我哪里出了问题,我将不胜感激
泰勒正弦级数
阶乘的斯特林近似
#include <stdio.h>
#include <math.h>
int main(){
float x,n,s,i,e,p,f,r;
f=M_PI;
e=2.7182818;
s=0;
printf("What value of sine do you want to apporximate?");
scanf("%f", &x);
printf("With what level of precision do you want to calculate it?");
scanf("%f", &n);
for(i=0;i<=n; ++i);{
r=((2*i)+1);
p=(sqrt(2*r*f)*(pow((r/e),r)));
s=s+(((pow((-1),i))*(pow(x,((2*i)+1))))/p);
}
printf("the value of sine at %f is %f",x,s);
}
这一行
for(i = 0; i <= n; ++i);{
多了一个分号。您正在执行一个空循环。
根据您的公式,这是正确的代码,但它生成错误的输出,因此您需要再次检查您的公式:
#include <stdio.h>
#include <math.h>
int main(){
double x,n,s,i,e,p,f;
f=M_PI;
e=2.7182818;
s=0;
int sign=0;// Adding this type to toggle the sign
printf("What value of sine do you want to apporximate?");
scanf("%lf", &x);// conversion specifier must be %lf for floating number
printf("With what level of precision do you want to calculate it?");
scanf("%lf", &n);
for(i=1;i<=n; i=i+2){ // Correcting the for loop
p=sqrt(2*i*f)*pow((i/e),i);
s=s+(pow(-1,sign++)*pow(x,i))/p;
}
printf("the value of sine at %f is %f",x,s);
}
由于 sin()
是一个周期函数,我永远不会超过一个周期来计算它。这简化了太多的数学,因为你永远不需要计算大的阶乘数。事实上,您甚至不需要为系列中的每一项计算阶乘,因为系数可以从最后一项导出,只需将前一个系数除以 (n-1)
和 n
。如果您的输入限于一个周期(好吧,您不需要使用 M_PI
的固定周期,您可以假设最大值为 3.5
并减少您的答案以获得更大的值只需减去 M_PI
.
的除法模数
一旦说到这里,我们就可以绑定你的最大误差,至于3.5
的最大输入,我们将3.5^n/n!
作为我们近似的最后一项,对于一些n
小于固定我们需要计算的项数的最大误差。
我将尝试通过推导算法和显示实际值(例如,最大输入值 3.2
)
这些是 3.2
和
位置 n
项的输入值
n | term at position n for input `3.2`
======+=================
8 | 0.27269634
12 | 0.00240693
16 | 0.00000578
18 | 0.00000019
20 | 0.00000001
21 | 7.9E-10
因此我们可以停止只计算该系列的 20 项。 exp()
函数是这样,它添加了所有项并且是一个简单的函数。对于 sin()
或 cos()
,如果您认为两者具有与 exp()
函数相同的项,您可以猜到更好的误差估计(好吧,第一个只有奇数项,第二个只有偶数项)
(x^n)/(n!) - (x^(n+2))/((n+2)!) = (n!*x^n*(1 - x^2/((n+1)*(n+2))))/n!
对于 n > 3.2
意味着每个术语是
< x^n/n!
所以我们可以应用与指数相同的标准。
这就是说我们可以在某个时候停止...如果我们继续我们的 table 我们会看到,例如 n > 30
总累积项小于 5.3E-18
所以我们可以到此为止(至少对于 double
个数字)。
#include <stdio.h>
#include <math.h> /* for the system sin() function */
double MySin(double x) /* x must be in the range [0..3.2] */
{
int i;
const int n = 30;
double t = x, acum = x; /* first term, x/1! */
x *= x; /* square the argument so we get x^2 in variable x */
for (i = 3; i < n; i += 2) {
t = -t * x / i / (i-1); /* mutiply by -1, x^2 and divide by i and (i-1) */
acum += t; /* and add it to the accum */
}
return acum;
}
int main()
{
double arg;
for(;;) {
if (scanf("%lg", &arg) != 1)
break;
printf("MySin(%lg) = %lg; sin(%lg) = %lg\n",
arg, MySin(arg), arg, sin(arg));
}
}
如果你利用 sin 函数的对称性,你可以将你的定义域减少到 M_PI/4
小于一,你甚至可以在 18 次幂处停止以获得大约 17 有效数字(对于 double
)这会让你的罪更快。
最后,我们可以通过以下方式获得对所有真实域有效的 sin2()
函数:
double sin2(double x)
{
bool neg = false;
int ip = x / 2.0 / M_PI;
x -= 2.0 * M_PI * ip; /* reduce to first period [-2PI..2PI] */
if (x < 0.0) x += 2.0*M_PI; /* reduce to first period [0..2PI] */
if (x > M_PI) { x -= M_PI; neg = true; } /* ... first period negative [ 0..PI ] */
if (x > M_PI/2.0) x = M_PI - x; /* reflection [0..PI/2] */
return neg ? MySin(-x) : MySin(x);
}
这更容易兄弟
#include <iostream>
#include <cmath>
using namespace std;
double factorial(int X)
{
double factorial = 1;
for(int i=1; i<=X; i++)
{
factorial = factorial *i;
}
return factorial;
}
double Mysin(double x,double result)
{
for(int i = 0;i<20;i++)
{
result+=pow((-1),i)*pow(x,((2*i)+1))/factorial((2*i)+1);
}
return result;
}
double Mycos(double x,double result)
{
for(int i = 0;i<20;i++)
{
result+=pow(-1,i)*pow(x,2*i)/factorial(2*i);
}
return result;
}
double Mytan(double sine,double cosine)
{
return sine/cosine;
}
double deg_to_rad(double x)
{
double const pi = 3.14159265359;
return x*pi/180;
}
int main()
{
double x,result=0;
cin>>x;
cout<<"My sin: "<<Mysin(deg_to_rad(x),result)<<endl;
cout<<"My cosin: "<<Mycos(deg_to_rad(x),result)<<endl;
cout<<"My tan: "<<Mytan(Mysin(deg_to_rad(x),result),Mycos(deg_to_rad(x),result))<<endl;
return 0;
}
我正在尝试使用泰勒级数和阶乘的斯特林逼近来逼近 C 中的 sine(x),但对于 n<5 和 -0 对于任何 n=>5,我得到了非常奇怪的答案。我昨天才开始学习,所以如果一些更有经验的程序员可以看看它并告诉我哪里出了问题,我将不胜感激
泰勒正弦级数
阶乘的斯特林近似
#include <stdio.h>
#include <math.h>
int main(){
float x,n,s,i,e,p,f,r;
f=M_PI;
e=2.7182818;
s=0;
printf("What value of sine do you want to apporximate?");
scanf("%f", &x);
printf("With what level of precision do you want to calculate it?");
scanf("%f", &n);
for(i=0;i<=n; ++i);{
r=((2*i)+1);
p=(sqrt(2*r*f)*(pow((r/e),r)));
s=s+(((pow((-1),i))*(pow(x,((2*i)+1))))/p);
}
printf("the value of sine at %f is %f",x,s);
}
这一行
for(i = 0; i <= n; ++i);{
多了一个分号。您正在执行一个空循环。
根据您的公式,这是正确的代码,但它生成错误的输出,因此您需要再次检查您的公式:
#include <stdio.h>
#include <math.h>
int main(){
double x,n,s,i,e,p,f;
f=M_PI;
e=2.7182818;
s=0;
int sign=0;// Adding this type to toggle the sign
printf("What value of sine do you want to apporximate?");
scanf("%lf", &x);// conversion specifier must be %lf for floating number
printf("With what level of precision do you want to calculate it?");
scanf("%lf", &n);
for(i=1;i<=n; i=i+2){ // Correcting the for loop
p=sqrt(2*i*f)*pow((i/e),i);
s=s+(pow(-1,sign++)*pow(x,i))/p;
}
printf("the value of sine at %f is %f",x,s);
}
由于 sin()
是一个周期函数,我永远不会超过一个周期来计算它。这简化了太多的数学,因为你永远不需要计算大的阶乘数。事实上,您甚至不需要为系列中的每一项计算阶乘,因为系数可以从最后一项导出,只需将前一个系数除以 (n-1)
和 n
。如果您的输入限于一个周期(好吧,您不需要使用 M_PI
的固定周期,您可以假设最大值为 3.5
并减少您的答案以获得更大的值只需减去 M_PI
.
一旦说到这里,我们就可以绑定你的最大误差,至于3.5
的最大输入,我们将3.5^n/n!
作为我们近似的最后一项,对于一些n
小于固定我们需要计算的项数的最大误差。
我将尝试通过推导算法和显示实际值(例如,最大输入值 3.2
)
这些是 3.2
和
n
项的输入值
n | term at position n for input `3.2`
======+=================
8 | 0.27269634
12 | 0.00240693
16 | 0.00000578
18 | 0.00000019
20 | 0.00000001
21 | 7.9E-10
因此我们可以停止只计算该系列的 20 项。 exp()
函数是这样,它添加了所有项并且是一个简单的函数。对于 sin()
或 cos()
,如果您认为两者具有与 exp()
函数相同的项,您可以猜到更好的误差估计(好吧,第一个只有奇数项,第二个只有偶数项)
(x^n)/(n!) - (x^(n+2))/((n+2)!) = (n!*x^n*(1 - x^2/((n+1)*(n+2))))/n!
对于 n > 3.2
意味着每个术语是
< x^n/n!
所以我们可以应用与指数相同的标准。
这就是说我们可以在某个时候停止...如果我们继续我们的 table 我们会看到,例如 n > 30
总累积项小于 5.3E-18
所以我们可以到此为止(至少对于 double
个数字)。
#include <stdio.h>
#include <math.h> /* for the system sin() function */
double MySin(double x) /* x must be in the range [0..3.2] */
{
int i;
const int n = 30;
double t = x, acum = x; /* first term, x/1! */
x *= x; /* square the argument so we get x^2 in variable x */
for (i = 3; i < n; i += 2) {
t = -t * x / i / (i-1); /* mutiply by -1, x^2 and divide by i and (i-1) */
acum += t; /* and add it to the accum */
}
return acum;
}
int main()
{
double arg;
for(;;) {
if (scanf("%lg", &arg) != 1)
break;
printf("MySin(%lg) = %lg; sin(%lg) = %lg\n",
arg, MySin(arg), arg, sin(arg));
}
}
如果你利用 sin 函数的对称性,你可以将你的定义域减少到 M_PI/4
小于一,你甚至可以在 18 次幂处停止以获得大约 17 有效数字(对于 double
)这会让你的罪更快。
最后,我们可以通过以下方式获得对所有真实域有效的 sin2()
函数:
double sin2(double x)
{
bool neg = false;
int ip = x / 2.0 / M_PI;
x -= 2.0 * M_PI * ip; /* reduce to first period [-2PI..2PI] */
if (x < 0.0) x += 2.0*M_PI; /* reduce to first period [0..2PI] */
if (x > M_PI) { x -= M_PI; neg = true; } /* ... first period negative [ 0..PI ] */
if (x > M_PI/2.0) x = M_PI - x; /* reflection [0..PI/2] */
return neg ? MySin(-x) : MySin(x);
}
这更容易兄弟
#include <iostream>
#include <cmath>
using namespace std;
double factorial(int X)
{
double factorial = 1;
for(int i=1; i<=X; i++)
{
factorial = factorial *i;
}
return factorial;
}
double Mysin(double x,double result)
{
for(int i = 0;i<20;i++)
{
result+=pow((-1),i)*pow(x,((2*i)+1))/factorial((2*i)+1);
}
return result;
}
double Mycos(double x,double result)
{
for(int i = 0;i<20;i++)
{
result+=pow(-1,i)*pow(x,2*i)/factorial(2*i);
}
return result;
}
double Mytan(double sine,double cosine)
{
return sine/cosine;
}
double deg_to_rad(double x)
{
double const pi = 3.14159265359;
return x*pi/180;
}
int main()
{
double x,result=0;
cin>>x;
cout<<"My sin: "<<Mysin(deg_to_rad(x),result)<<endl;
cout<<"My cosin: "<<Mycos(deg_to_rad(x),result)<<endl;
cout<<"My tan: "<<Mytan(Mysin(deg_to_rad(x),result),Mycos(deg_to_rad(x),result))<<endl;
return 0;
}