c - 泰勒级数计算余弦(余弦(90)的输出为-0.000)

标签 c precision trigonometry taylor-series

我为泰勒级数编写了以下函数来计算余弦。

double cosine(int x) {
    x %= 360; // make it less than 360
    double rad = x * (PI / 180);
    double cos = 0;

    int n;

    for(n = 0; n < TERMS; n++) { 
        cos += pow(-1, n) * pow(rad, 2 * n) / fact(2 * n);
    }
    return cos;
}

我的问题是,当我输入 90 时,我得到的答案是 -0.000000。 (为什么我得到的是 -0.000 而不是 0.000?)

有人可以解释一下为什么以及如何解决这个问题吗?
我认为这是由于 double 的精度造成的。 这是 main() :

int main(void){
int y;
//scanf("%d",&y);
y=90;
printf("sine(%d)= %lf\n",y, sine(y));
printf("cosine(%d)= %lf\n",y, cosine(y));

return 0;
}

最佳答案

完全可以预料,无论您的计算方法有多好,您都无法获得任何浮点的余弦值的精确零输出。这是浮点工作原理的基础。

余弦的数学零点是 pi/2 的奇数倍。因为 pi 是无理数,所以它不能完全表示为 double (或任何浮点形式),并且可表示的最近相邻值之间的差异将至少是 pi/2 乘以 DBL_EPSILON ,大致3e-16 (或其他浮点类型的相应值)。对于 pi/2 的某些奇数倍,您可能会“幸运”并发现它非常接近两个邻居之一,但平均而言,您会发现它约为 1e-16离开。所以你的输入已经是错误的 1e-16左右

现在,余弦在其零点处的斜率为 +1 或 -1,因此输出中的误差将大致与输入中的误差成正比。但要获得精确的零,您需要小于最小可表示非零 double 值的误差,该值约为 2e-308 。这比输入中的误差小了近 300 个数量级。

虽然理论上你可以“幸运”并且拥有一些非常接近最接近的可表示双倍的倍数(如果 pi/2),但仅将其建模为随机的,这种可能性是天文数字般的小。我相信甚至有证据表明没有双重x其中 cos(x) 的正确舍入值是一个精确的零。对于单精度( float ),这可以通过蛮力轻松确定;对于 double这可能也是可行的,但计算量很大。

至于为什么printf正在打印-0.000000 ,只是 %f 的默认值小数点后 6 位,远远不足以看到第一个有效数字。使用%e%g ,可选地使用较大的精度修饰符,将向您显示所获得的结果的近似值,该结果实际上保留了一些意义,并让您了解结果是否良好。

关于c - 泰勒级数计算余弦(余弦(90)的输出为-0.000),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58270529/

相关文章:

c - Protobuf-C 编译问题

将 char 数组转换为一个 int

java - (Java) 如何使用扩展精度算术来处理更大的阶乘?

go - golang中小数平方根的任意精度

cos 和 sin 在 C 语言中给出错误答案

c - 在 C 语言中遇到 Shell 排序问题,无限循环

c - 为什么这是错误的?

c++ - acos(double) 在 x64 和 x32 Visual Studio 上给出不同的结果

java - 基于物理的二维运动 : Changing direction of an object over time

algorithm - 获取角度当前象限的最快方法