C语言 余弦函数中的精度损失问题

2fjabf4q  于 2022-12-11  发布在  其他
关注(0)|答案(4)|浏览(166)

这就是我的任务:
编写一个C函数来计算级数// cos(x)= x-(x2 /2!)+(x4 /4!)-(x6 /6!)+...等等变量realNuber使用弧度而不是度
我失去了精确度,但我不明白在哪里。realNumber = 60的答案一定是0.500,但我有0.501。请帮助。

#include "stdio.h"
#include "inttypes.h"

double power(float N, uint32_t P){
    double buffer = 1;

    for (int i = 0; i < P; ++i) {
        buffer *= N;
    }

    return buffer;
}

float factorial(float number){
    float result = number;

    if (number == 0) {
        return 0;
    }

    for (int i = 0; i < number - 1; ++i) {
        result *= i + 1;
    }

    return result;
}

float cos(float x){
    float result = x * (3.14159265359 / 180.);
    float polar = -1;

    for (int i = 2; i < 10; i += 2) {
        result += power(result, i) / factorial(i) * polar;
        polar *= -1;
    }

    return result;
}

int main(void){
    float realNumber = 0;
    float result = 0;

    scanf("%f", &realNumber);

    result = cos(realNumber);

    printf("%.13f", result);
}

我试着在函数cos()中进行修改;也许问题出在别的地方

dzhpxtsq

dzhpxtsq1#

您最初写道:
编写一个C函数来计算以下级数的值:// cos(x)= x-(x2 /2!)+(x4 /4!)-(x6 /6!)
但这不是cos的泰勒级数。
正确的公式是:

  • (请注意,第一项中的1不是x)*

Source
对泰勒级数进行修正,再做一些修正,我得到:

输出

Success #stdin #stdout 0s 5392KB
0.4999999701977

我的代码:

#include "stdio.h"
#include "inttypes.h"

// No Changes
double power(float N, uint32_t P){
    double buffer = 1;

    for (int i = 0; i < P; ++i) {
        buffer *= N;
    }

    return buffer;
}

// No Changes
float factorial(float number){
    float result = number;

    if (number == 0) {
        return 0;
    }

    for (int i = 0; i < number - 1; ++i) {
        result *= i + 1;
    }

    return result;
}

// Minor changes, explained in comments
float cos(float x){
    x = x * (3.14159265359 / 180.); // Convert Degrees to Radians
    float result = 1;               // Taylor series starts with 1, not with x !!! 
    float polar = -1;

    for (int i = 2; i <= 10; i += 2) {
        result += power(x, i) / factorial(i) * polar;
        polar *= -1;
    }

    return result;
}

// Skipped the scanf in favor of hard-coded value, for simplicity.
int main(void){
    float realNumber = 60;
    float result = 0;

    result = cos(realNumber);

    printf("%.13f", result);
}

当我重写cos函数以消除使用幂和阶乘函数时,我得到了以下结果:

double cos(float x){
    x = x * (3.14159265359 / 180.); // Convert Degrees to Radians
    double num   = 1;  // Numerator of the fraction (x^2, x^4...)
    int    sgn   = +1; // Sign, alternating -1, +1
    uint64_t den = 1;  // Denominator: Factorials, 2!, 4!, 6!...
    float ans    = 1;  // Accumulated answer
    for (int i = 2; i <= 10; i += 2) {
        num *= x*x;
        den *= i*i-i;
        sgn *= -1;
        ans += num / den * sgn;
    }

    return ans;
}
nuypyhwy

nuypyhwy2#

你的cos函数是完全错误的。解释在注解中。

float cos(float x) {
  float anglerad = x * 3.14159265359 / 180; // multiply first, then divide, but 
                                            // it probably doesn't matter much here

  float result = 1;                         // initial result must be 1
  float sign = -1;                          // use proper naming

  for (int i = 2; i < 10; i += 2) {
    // you need power(anglerad,.... not power(result,...)
    result += power(anglerad, i) / factorial(i) * sign;

    sign *= -1;
  }

  return result;
}

余弦的公式为1-(x^2/2!) + (x^4/4!) + ...
您尝试使用错误的x-(x^2/2!) + (x^4/4!) + ...
一些一般性意见:
虽然修正后的cos函数是正确的,但它的效率不是很高。

  • 通过使用前一次迭代的结果,可以避免对阶乘函数的重复调用。记住:你甚至可以使用一个表,其中包含从2到10的硬编码阶乘值(如果你想要更多的迭代,也可以使用其他的上限)。
  • 可以避免对幂函数的重复调用。请记住:x^n = x * x^(n-1) .
  • 您可以使用更多的迭代。
  • 您可以使用double而不是float
  • 可能还有其他一些东西。
noj0wjuj

noj0wjuj3#

cos函数中的小错误。请尝试此操作。

float mycos(float x){
    float result = 1.0;
    float polar = -1;
    float xrad = x * (3.14159265359 / 180.);

    for (int i = 2; i < 10; i += 2) {
        result += power(xrad, i) / (factorial(i) * polar);
        polar *= -1;
    }

    return result;
}
dfuffjeb

dfuffjeb4#

下面是我在Java中实现它的方法。代码应该足够类似于C,以便您轻松翻译。不需要幂或阶乘调用。我希望您会同意它要简单得多。

public class TrigTaylorSeries {

    /**
     * Taylor series for cosine
     * @param x angle in radians
     * @param n terms to include (must be greater than zero)
     * @return cosine(x)
     * @link https://en.wikipedia.org/wiki/Taylor_series
     */
    public static double cos(double x, int n) {
        if (n <= 0) throw new IllegalArgumentException("Number of terms must be positive");
        double result = 0.0;
        double factor = 1.0;
        for (int i = 0; i < n; ++i) {
            result += factor;
            factor *= -x*x/(2*i+1)/(2*i+2);
        }
        return result;
    }
}

下面是一个Junit测试,显示它工作正常:

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class TrigTaylorSeriesTest {

    @Test
    public void testCosine() {
        // setup
        int nterms = 20;
        int npoints = 20;
        double t = 0.0;
        double dt = 2.0*Math.PI/npoints;
        double eps = 1.0e-9;
        // exercise
        // assert
        for (int i = 0; i < npoints+1; ++i) {
            Assertions.assertEquals(Math.cos(t), TrigTaylorSeries.cos(t, nterms), eps, String.format("Incorrect result for %d", i));
            t += dt;
        }
    }
}

使用20个术语精确到9位有效数字。

相关问题