【问题标题】:Implementing Taylor Series for sine and cosine in C在 C 中实现正弦和余弦的泰勒级数
【发布时间】:2017-04-10 01:55:08
【问题描述】:

我一直在按照我的教授给我们的指南进行操作,但我就是找不到哪里出错了。我还遇到了其他一些关于在 C 中实现泰勒级数的问题。

只要假设 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,我真的很想知道我哪里出错了,所以我可以改进,对不起,如果这是一个非常糟糕的问题。

【问题讨论】:

  • 请显示factorial函数。如果您正在获得2*terms 的阶乘,那么您是否知道20! = 2432902008176640000
  • @Weather 好的,已编辑,是的,我知道,我们的教授告诉我们用 10 个术语来解决它,而它只能达到 19 个!对于罪过,但是是的,我看到这是一个巨大的数字,但是当度数为 180 时,我最终得到了像 157318262.9 这样的数字,因为分母如此之大,它不应该更小吗?上帝,我讨厌我现在无法正常思考
  • 您甚至没有使用错误的阶乘 - 您使用 return flag; 返回了错误的变量,请参阅我的回答。所以你除以一个太小的数字,这个词就太大了。

标签: c trigonometry taylor-series


【解决方案1】:

12! 上的任何值都大于 32 位 int 的容量,因此这些值会溢出,因此不会返回您期望的值。

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

还有一个技巧可以在不知道需要多少项的情况下将结果计算到double 的精度。我将把它作为练习留给读者。

【讨论】:

  • 所以像这样的东西作为我的 for 循环而不是我现在拥有的东西? val2 = val2 * (-1.00) * (rad * rad) / (flag_2 * (flag_2 + 1.00)); sin += val2;
  • 实际上是的,改变我的方程式以遵循您的方程式使估计值更接近。谢谢:)
【解决方案2】:

在函数factorial 中,在分配给函数的double 返回值之前,您正在执行int 乘法。阶乘可以轻松打破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 并除以术语编号 - 符号发生变化。

【讨论】:

  • 天哪,非常感谢您指出这一点,我感到非常沮丧,因为与上次运行时相比,输出没有任何变化。
【解决方案3】:

另一种相当幼稚的 5 分钟方法涉及计算一个查找表,其中包含前 20 个左右的阶乘,即 1! .. 20!这需要很少的内存,并且可以提高“每次”计算方法的速度。在预先计算阶乘的函数中可以很容易地实现进一步的优化,利用每个阶乘与前一个阶乘之间的关系。

在两个三角函数的循环中有效消除分支(如果 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 个项求和时,代码会产生与内置数学库看似相同的结果(我没有进行太多测试)。

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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-02
    • 1970-01-01
    • 2020-02-04
    • 2017-06-06
    • 2021-02-19
    • 1970-01-01
    • 2015-06-20
    • 1970-01-01
    相关资源
    最近更新 更多