我为泰勒级数编写了以下函数来计算余弦。
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/