在C中实现正弦和余弦的泰勒级数

时间:2016-11-25 16:04:34

标签: c trigonometry taylor-series

我一直在关注我教授给我们的指南,但我找不到我错的地方。我也经历了一些关于在C中实现泰勒系列的其他问题。

enter image description here

假设RaiseTo(将数字提升到x的幂)就在那里。

double factorial (int n)
{
    int fact = 1,
    flag;

   for (flag = 1; flag <= n; flag++)
   {
        fact *= flag;
   }

   return flag;
}

double sine (double rad)
{

int flag_2,
    plusOrMinus2 = 0; //1 for plus, 0 for minus 
double sin, 
    val2 = rad,
    radRaisedToX2,
    terms;

terms = NUMBER_OF_TERMS; //10 terms

    for (flag_2 = 1; flag_2 <= 2 * terms; flag_2 += 2)
    {
        radRaisedToX2 = RaiseTo(rad, flag_2);   

        if (plusOrMinus2 == 0)
        {
            val2 -=  radRaisedToX2/factorial(flag_2);
            plusOrMinus2++; //Add the next number
        }

        else
        {
            val2 += radRaisedToX2/factorial(flag_2);
            plusOrMinus2--; //Subtract the next number
        }
    }

    sin = val2;
    return sin;
 }

int main()
{
    int degree;
    scanf("%d", &degree);
    double rad, cosx, sinx;
    rad = degree * PI / 180.00;
    //cosx = cosine (rad);
    sinx = sine (rad);
    printf("%lf \n%lf", rad, sinx);
}

所以在循环期间,我得到了rad ^ x,将其除以从1开始的奇数系列的阶乘,然后根据需要添加或减去它,但是当我运行程序时,我得到输出方式高于一,我们都知道sin(x)的极限是1和-1,我真的想知道我哪里出错所以我可以改进,抱歉,如果这是一个非常糟糕的问题。

3 个答案:

答案 0 :(得分:3)

12!以上的任何内容都超过32位int,因此这些值会溢出,因此无法返回您所期望的内容。

不是每次计算全因子,而是查看序列中相对于前一个项的每个项。对于任何给定的术语,下一个术语是前一个术语的-((x*x)/(flag_2*(flag_2-1))倍。所以从术语x开始,然后乘以每个连续术语的因子。

在不知道你需要多少个术语的情况下,计算double精度的结果也是一个技巧。我将此作为练习留给读者。

答案 1 :(得分:1)

在函数factorial中,您在分配到函数的int返回值之前进行double乘法运算。因子可以轻易地打破int范围,例如20! = 2432902008176640000

你还返回了错误的变量 - 循环计数器!

请将本地变量更改为double,如

double factorial (int n)
{
    double fact = 1;
    int flag;

    for (flag = 1; flag <= n; flag++)
    {
        fact *= flag;
    }
    return fact;    // it was the wrong variable, and wrong type
}

此外,甚至不需要进行因子计算。请注意,系列中的每个术语都将前一个术语乘以rad并除以术语编号 - 并更改符号。

答案 2 :(得分:0)

另一种相当天真的5分钟方法涉及计算一个包含前20个左右阶乘的查找表,即1! .. 20!这需要非常少的记忆,并且可以提高速度,而不是每次都能提高速度。计算方法。在预先计算阶乘的函数中可以很容易地实现进一步的优化,利用每个阶乘的关系。

在两个trig函数的循环中有效消除分支(如果X执行Y,否则执行Z)的方法将再次提供更高的速度。

C代码

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

const int nMaxTerms=20;
double factorials[nMaxTerms];

double factorial(int n)
{
    if (n==1)
        return 1;
    else
        return (double)n * factorial(n - 1.0);
}

void precalcFactorials()
{
    for (int i=1; i<nMaxTerms+1; i++)
    {
        factorials[i-1] = factorial(i);
    }
}

/*
    sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! .......
*/
double taylorSine(double rads)
{
    double result = rads;

    for (int curTerm=1; curTerm<=(nMaxTerms/2)-1; curTerm++)
    {
        double curTermValue = pow(rads, (curTerm*2)+1);
        curTermValue /= factorials[ curTerm*2 ];
        if (curTerm & 0x01)
            result -= curTermValue;
        else
            result += curTermValue;
    }
    return result;
}

/*
    cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! .......
*/
double taylorCos(double rads)
{
    double result = 1.0;
    for (int curTerm=1; curTerm<=(nMaxTerms/2)-1; curTerm++)
    {
        double curTermValue = pow(rads, (curTerm*2) );
        curTermValue /= factorials[ (curTerm*2) - 1 ];
        if (curTerm & 0x01)
            result -= curTermValue;
        else
            result += curTermValue;
    }
    return result;
}

int main()
{
    precalcFactorials();
    printf("Math sin(0.5) = %f\n", sin(0.5));
    printf("taylorSin(0.5) = %f\n", taylorSine(0.5));

    printf("Math cos(0.5) = %f\n", cos(0.5));
    printf("taylorCos(0.5) = %f\n", taylorCos(0.5));

    return 0;
}

输出

Math sin(0.5) = 0.479426
taylorSin(0.5) = 0.479426
Math cos(0.5) = 0.877583 
taylorCos(0.5) = 0.877583

的Javascript

在javascript中实现,当在sin / cos函数中仅对7个项求和时,代码产生看似相同的结果(我没有经常测试)到内置的Math库。

&#13;
&#13;
window.addEventListener('load', onDocLoaded, false);

function onDocLoaded(evt)
{
	console.log('starting');
	for (var i=1; i<21; i++)
		factorials[i-1] = factorial(i);
	console.log('calculated');
	
	console.log(" Math.cos(0.5) = " + Math.cos(0.5));
	console.log("taylorCos(0.5) = " + taylorCos(0.5));
	console.log('-');
	console.log("  Math.sin(0.5) = " + Math.sin(0.5));
	console.log("taylorSine(0.5) = " + taylorSine(0.5));
}

var factorials = [];

function factorial(n)
{
	if (n==1)
		return 1;
	else
		return n * factorial(n-1);
}

/*
	sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! .......
*/
function taylorSine(x)
{
	var result = x;
	for (var curTerm=1; curTerm<=7; curTerm++)
	{
		var curTermValue = Math.pow(x, (curTerm*2)+1);
		curTermValue /= factorials[ curTerm*2 ];
		if (curTerm & 0x01)
			result -= curTermValue;
		else
			result += curTermValue;
	}
	return result;
}

/*
	cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! .......
*/
function taylorCos(x)
{
	var result = 1.0;
	for (var curTerm=1; curTerm<=7; curTerm++)
	{
		var curTermValue = Math.pow(x, (curTerm*2));
		curTermValue /= factorials[ (curTerm*2)-1 ];
		if (curTerm & 0x01)
			result -= curTermValue;
		else
			result += curTermValue;
	}
	return result;
}
&#13;
&#13;
&#13;