【问题标题】:Taylor Series Expansion of cos x and sin x in C Programming without using math.h and only inside int main()C 编程中 cos x 和 sin x 的泰勒级数展开,不使用 math.h 且仅在 int main() 内部
【发布时间】:2016-02-01 08:18:02
【问题描述】:

我正在为我们学校做一个项目,我们需要创建一个程序来计算 sin xcos x 的泰勒展开级数的近似值,只使用 <stdio.h>不使用 除int main() 之外的用户定义函数,从-180180 的所有角度,增量为+5。以下是我的代码:

#include <stdio.h>
#define PI   3.141592653589
#define NUMBER_OF_TERMS    10

int
main()
{
    int cosctr, sinctr;
    double ctr, radi;
    double cosaccu, costerm, sinaccu, sinterm;

    for (ctr = -180; ctr < 185; ctr = ctr + 5) {
        radi = ctr * PI/180.0;
        cosctr = 1;
        cosaccu = 1;
        costerm = 1;
        sinctr = 2;
        sinaccu = radi;
        sinterm = radi;
        while (cosctr <= 2*NUMBER_OF_TERMS) {
            costerm = costerm*(-1)*(radi*radi)/(cosctr*(cosctr + 1));
            cosaccu = cosaccu + costerm;
            cosctr+=2;
        } do {
            sinterm = sinterm*(-1)*(radi*radi)/(sinctr*(sinctr + 1));
            sinaccu = sinaccu + sinterm;
            sinctr+=2;
        } while (sinctr <= 2*NUMBER_OF_TERMS);
        printf("%.2lf      %.12lf      %.12lf      %.12lf\n", ctr, radi, cosaccu, sinaccu);
    } return 0;
}

上面的代码对于 15 项展开近似是准确的。但是,如果我将 NUMBER_OF_TERMS 更改为例如 5 或 10,则近似值有缺陷。
有什么建议吗?

让我澄清一下:我需要获得 5 项、10 项和 15 项的近似值。除了&lt;stdio.h&gt;,我不能使用任何其他库。我不能使用int main() 之外的任何其他功能(对于我之前的解释含糊不清,我深表歉意)。
请使用随附的更正代码回答。

【问题讨论】:

  • 你能做的只有这么多,你的任务需要的迭代次数多吗?您需要多少位数的准确度?
  • 在那个程序中,main() 肯定是一个用户定义的函数。换句话说,您的要求很奇怪并且......具有误导性。
  • “近似值有缺陷”是什么意思?近似值越准确,包含的项越多。这就是它的工作原理。近似值是否比您预期的更不准确?你期望什么输出,它给出了什么?
  • "请使用包含的更正代码回答。"嗯,没有。您编写代码,我们将帮助您。
  • 其实需要的是0-45(0,5,10,15,20,25,30,35,40,45degrees)的计算。

标签: c taylor-series


【解决方案1】:

sind(degrees)cosd(degrees) 的高进动但简单计算的关键是首先将度数的范围减少到 0 到 90(甚至 0 到 45),使用通常的三角调整与 degree 先安排。

减少:
angle = fmod(angle, 360) // 减少 (-360..360) 或使用 a = a - (int)(a/360)
sin(x) = -sin(-x) // 减少到 [0..360 )
cos(x) = cos(-x) // 减少到 [0..360)
sin(x) = -sin(x-180) // 减少到 [0..180)
cos(x) = -cos(x-180) // 减少到 [0..180)sin(x) = cos(90-x) // 减少到 [0..90)
进一步减少:
对于 [45-90) 使用 sin(x) = cos(90-x) // 减少到 [0..45)

然后转换为弧度并使用泰勒级数展开。

Example

注意:由于代码处理的是double,通常为 17 位精度,无需使用课程 PI 近似值。

// #define PI   3.141592653589
#define PI   3.1415926535897932384626433832795

【讨论】:

    【解决方案2】:

    我试过你的代码;它对我来说很好,因为它看起来像它设计的那样。这是您的代码在 5 项和 10 项处的余弦输出与 Mathematica 计算的相同近似值之间的比较。他们同意&lt;10^-12,即您输出的精度。:

    我在您的代码中看到的唯一问题是,按照您设计循环的方式,如果您计算展开式中的第一项(即余弦的常数项),您实际上是在考虑 NUMBER_OF_TERMS + 1 项,正弦的线性项。)您从第一项开始,然后您的循环添加另一个 NUMMBER_OF_TERMS 项。如果这不是设计使然,那么您实际上是在以您期望的更高精度逼近函数。

    【讨论】:

    • 能否请您扩展您的答案?我似乎找不到 NUMBER_OF_TERMS + 1 个
    • 您的循环计算了NUMBER_OF_TERMS 术语,但您在循环开始之前已经计算了一个额外的术语。
    • 哪个循环?您的回答非常含糊,尽管我非常感谢您的回答。我知道这很痛苦,但我是新手,我的教授对项目的规范非常严格
    • 它有什么模糊之处?您的代码中有两个 while 循环。这些用于连续计算近似值中的高阶项。循环内的代码运行了一定次数,即NUMBER_OF_TERMS。假设 NUMBER_OF_TERMS 是 10。您从 while 循环中得到 10 个近似值。但是,您已经在循环开始之前计算了一项。因此,您总共可以获得 11 个术语。
    • @gabriel_741 你不接受答案有什么原因吗?
    【解决方案3】:

    根据其定义,泰勒级数是无限系列项的总和。

    因此,泰勒有限展开只是真实结果的近似值:随着项数的增加,该近似值的准确性会提高。

    如果有足够的项,则在某个点的近似误差变得不明显。但是,如果您尝试减少项数,则近似误差会增加并且可以检测到。

    在您的情况下,近似误差低于NUMBER_OF_TERMS= 15 的检测阈值,但在NUMBER_OF_TERMS= 10 或更少时变得明显。

    【讨论】:

    • 谢谢,但您的回答没有回答我的问题。您解释了为什么会出现错误,但您没有回答如何更正代码。
    • 常见的技巧是将术语向后求和。想象一下,你向前求和 1/2 + 1/4 + 1/8 等等。在某些时候,由于精度有限,这些项对总和变得可以忽略不计,并且总和不再改变(谐波级数 1/1 + 1/2 + 1/3 ... 是一个经典示例,并且似乎收敛) .一个简单的解决方案是计算项并将其存储在一个数组中,然后从最小值开始向后求和。
    【解决方案4】:

    随着 x 的增加,sin(x) 和 cos(x) 的泰勒展开需要更长的时间来收敛。但由于这些是周期函数,因此您实际上不需要为 0-90° 范围之外的值扩展系列。

    对于超出此范围的 x 值,请使用以下标识:

    sin(x) = -sin(x+180°) = -sin(-x) = sin(180°-x)
    cos(x) = -cos(x+180°) = cos(-x) = -cos(180°-x)
    

    例如sin(175°) = sin(5°), cos(-120°) = -cos(60°)

    【讨论】:

    • 您能澄清一下吗?最好我希望看到您的建议以语义上可接受的方式插入到我的代码中。感谢您的合作。
    【解决方案5】:

    我在另一个用户的帮助下想通了。 原来我正在计算术语 + 1,使答案比预期的更准确。 15 项后的变化超过了小数点后第 12 位,因此没有显示在结果中。

    #include <stdio.h>
    #define PI   3.141592653589
    #define NUMBER_OF_TERMS 10 // 5 and 15 work as well
    
    int
    main()
    {
        int cosctr, sinctr;
        double ctr, radi;
        double cosaccu, costerm, sinaccu, sinterm; // accu will be final answer, term will be added to accu
    
        for (ctr = -180; ctr < 185; ctr+=5) { // for loop; ctr initialized at -185 and added to in increments of 5 to produce degrees
            radi = ctr * PI/180.0; // calculation for radians (assigned to radi)
            cosctr = 1; // initialization for cos counter; must be included in loop to allow correct calculations of cos
            cosaccu = 1; // first term is 1
            costerm = 1; // base term, to be multiplied with termcalc formula
            sinctr = 2; // initialization for sin counter; must be included in loop to allow correct calculations of sin
            sinaccu = radi; // first term is x, or degrees in radians (radi)
            sinterm = radi; // base term for sin
         // cos calculation
         while (cosctr < 2*NUMBER_OF_TERMS-1) { // accuracy check, 2* since increments of 2; NOTE: actual values are (1, 3, 5,...)
            costerm = costerm*(-1)*(radi*radi)/(cosctr*(cosctr + 1)); // TERMCALC FORMULA; multiplying previous term with formula creates next term
            cosaccu = cosaccu + costerm; // addition of new term to previous sum; dependent on accuracy (NUMBER_OF_TERMS)
            cosctr+=2;
         } do { // sin calculation; identical to cos, albeit with substituted vars
            sinterm = sinterm*(-1)*(radi*radi)/(sinctr*(sinctr + 1));
            sinaccu = sinaccu + sinterm;
            sinctr+=2;
         } while (sinctr < 2*NUMBER_OF_TERMS-1); // accuracy check, 2* since increments of 2; NOTE: actual values are (2, 4, 6,...)
         printf("%.2lf\t%.12lf\t%.12lf\t%.12lf\n", ctr, radi, cosaccu, sinaccu); // final display; /t used for convenience
     } return 0; // finally!!!
    }
    

    【讨论】:

      猜你喜欢
      • 2022-06-10
      • 2015-01-07
      • 2021-03-19
      • 2015-04-30
      • 2018-06-23
      • 2020-03-01
      • 1970-01-01
      • 2020-04-01
      相关资源
      最近更新 更多