[英]Taylor Series in C (problem with sin(240) and sin(300))
#include <stdio.h>
#include <math.h>
const int TERMS = 7;
const float PI = 3.14159265358979;
int fact(int n) {
return n<= 0 ? 1 : n * fact(n-1);
}
double sine(int x) {
double rad = x * (PI / 180);
double sin = 0;
int n;
for(n = 0; n < TERMS; n++) { // That's Taylor series!!
sin += pow(-1, n) * pow(rad, (2 * n) + 1)/ fact((2 * n) + 1);
}
return sin;
}
double cosine(int x) {
double rad = x * (PI / 180);
double cos = 0;
int n;
for(n = 0; n < TERMS; n++) { // That's also Taylor series!
cos += pow(-1, n) * pow(rad, 2 * n) / fact(2 * n);
}
return cos;
}
int main(void){
int y;
scanf("%d",&y);
printf("sine(%d)= %lf\n",y, sine(y));
printf("cosine(%d)= %lf\n",y, cosine(y));
return 0;
}
The code above was implemented to compute sine and cosine using Taylor series.上面的代码是使用泰勒级数计算正弦和余弦的。 I tried testing the code and it works fine for sine(120).
我尝试测试代码,它适用于正弦(120)。 I am getting wrong answers for sine(240) and sine(300).
我得到了正弦(240)和正弦(300)的错误答案。
Can anyone help me find out why those errors occur?谁能帮我找出为什么会发生这些错误?
You should calculate the functions in the first quadrant only [0, pi/2).您应该只计算第一象限中的函数 [0, pi/2)。 Exploit the properties of the functions to get the values for other angles.
利用函数的属性来获取其他角度的值。 For instance, for values of x between [pi/2, pi), sin(x) can be calculated by sin(pi - x).
例如,对于 [pi/2, pi) 之间的 x 值,sin(x) 可以通过 sin(pi - x) 计算。
The sine of 120 degrees, which is 40 past 90 degrees, is the same as 50 degrees: 40 degrees before 90. Sine starts at 0, then rises toward 1 at 90 degrees, and then falls again in a mirror image to zero at 180. 120 度的正弦,即 90 度后的 40 度,与 50 度相同:90 之前的 40 度。正弦从 0 开始,然后在 90 度处向 1 上升,然后在镜像中再次下降到 180 度处的零.
The negative sine values from pi to 2pi are just -sin(x - pi).从 pi 到 2pi 的负正弦值只是 -sin(x - pi)。 I'd handle everything by this recursive definition:
我会通过这个递归定义来处理所有事情:
sin(x):
cases x of:
[0, pi/2) -> calculate (Taylor or whatever)
[pi/2, pi) -> sin(pi - x)
[pi/2, 2pi) -> -sin(x - pi)
< 0 -> sin(-x)
>= 2pi -> sin(fmod(x, 2pi)) // floating-point remainder
A similar approach for cos
, using identity cases appropriate for it. cos
的类似方法,使用适合它的身份案例。
The key point is:关键点是:
TERMS
is too small to have proper precision. TERMS
太小而无法获得适当的精度。 And if you increase TERMS
, you have to change fact
implementation as it will likely overflow when working with int
.如果增加
TERMS
,则必须更改fact
实现,因为在使用int
时它可能会溢出。
I would use a sign to toggle the -1 power instead of pow(-1,n)
overkill.我会使用一个符号来切换 -1 功率而不是
pow(-1,n)
过度杀伤。
Then use double
for the value of PI to avoid losing too many decimals然后对 PI 的值使用
double
以避免丢失太多小数
Then for high values, you should increase the number of terms (this is the main issue).然后对于高值,您应该增加术语的数量(这是主要问题)。 using
long long
for your factorial method or you get overflow.对阶乘方法使用
long long
,否则会溢出。 I set 10 and get proper results:我设置了 10 并得到了正确的结果:
#include <stdio.h>
#include <math.h>
const int TERMS = 10;
const double PI = 3.14159265358979;
long long fact(int n) {
return n<= 0 ? 1 : n * fact(n-1);
}
double powd(double x,int n) {
return n<= 0 ? 1 : x * powd(x,n-1);
}
double sine(int x) {
double rad = x * (PI / 180);
double sin = 0;
int n;
int sign = 1;
for(n = 0; n < TERMS; n++) { // That's Taylor series!!
sin += sign * powd(rad, (2 * n) + 1)/ fact((2 * n) + 1);
sign = -sign;
}
return sin;
}
double cosine(int x) {
double rad = x * (PI / 180);
double cos = 0;
int n;
int sign = 1;
for(n = 0; n < TERMS; n++) { // That's also Taylor series!
cos += sign * powd(rad, 2 * n) / fact(2 * n);
sign = -sign;
}
return cos;
}
int main(void){
int y;
scanf("%d",&y);
printf("sine(%d)= %lf\n",y, sine(y));
printf("cosine(%d)= %lf\n",y, cosine(y));
return 0;
}
result:结果:
240
sine(240)= -0.866026
cosine(240)= -0.500001
Notes:笔记:
pow
using successive multiplications is probably not needed, since we're dealing with floating point.pow
的递归实现,因为我们正在处理浮点数。 It introduces accumulation error if n is big.fact
could be using floating point to allow bigger numbers and better precision. fact
可以使用浮点来允许更大的数字和更好的精度。 Actually I suggested long long
but it would be better not to assume that the size will be enough.long long
但最好不要假设大小就足够了。 Better use standard type like int64_t
for that.int64_t
这样的标准类型。fact
and pow
results could be pre-computed/hardcoded as well. fact
和pow
结果也可以预先计算/硬编码。 This would save computation time.const double TERMS = 14;
const double PI = 3.14159265358979;
double fact(double n) {return n <= 0.0 ? 1 : n * fact(n - 1);}
double sine(double x)
{
double rad = x * (PI / 180);
rad = fmod(rad, 2 * PI);
double sin = 0;
for (double n = 0; n < TERMS; n++)
sin += pow(-1, n) * pow(rad, (2 * n) + 1) / fact((2 * n) + 1);
return sin;
}
double cosine(double x)
{
double rad = x * (PI / 180);
rad = fmod(rad,2*PI);
double cos = 0;
for (double n = 0; n < TERMS; n++)
cos += pow(-1, n) * pow(rad, 2 * n) / fact(2 * n);
return cos;
}
int main()
{
printf("sine(240)= %lf\n", sine(240));
printf("cosine(300)= %lf\n",cosine(300));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.