sin,cos,tan和舍入误差

我正在用C / C ++进行一些三角计算,并且遇到了舍入错误的问题。 例如,在我的Linux系统上:

#include  #include  int main(int argc, char *argv[]) { printf("%e\n", sin(M_PI)); return 0; } 

该程序提供以下输出:

 1.224647e-16 

当正确的答案当然是0。

使用trig函数时,我可以期待多少舍入误差? 我怎样才能最好地处理这个错误? 我熟悉用于比较浮点数的最后位置单位技术,来自Bruce Dawson的比较浮点数 ,但这似乎在这里不起作用,因为0和1.22e-16相当于几个ULP。

IEEE双重存储52位尾数,“隐含前导”形成53位数。 因此,结果的最低位中的错误占数字比例的约1/2 ^ 53。 您的输出与1.0的顺序相同,因此几乎只有10 ^ 16中的一个部分(因为53 * log(2)/ log(10)== 15.9)。

是的。 这大约是您可以预期的精度限制。 我不确定您使用的ULP技术是什么,但我怀疑您的应用是错误的。

对于罪(pi),答案只有0 – 你是否包括Pi的所有数字?

– 有没有人注意到这里明显缺乏,讽刺/幽默感?

@Josh Kelley – 好的回答。
通常,您不应该将涉及浮点数或双精度数的任何操作的结果相互比较。

唯一的例外是分配。
浮动a = 10.0;
float b = 10.0;
那么a == b

否则你总是要编写一些函数,比如bool IsClose(float a,float b,float error),以便检查两个数字是否在彼此的“错误”范围内。
记得还要检查标志/使用晶圆厂 – 你可能有-1.224647e-16

π的正弦是0.0。
M_PI正弦值约为1.224647e-16。

M_PI不是π。

程序给出… 1.224647e-16当正确的答案当然是0。

Code给出了7个地方的正确答案。


以下不打印π的正弦。 它打印一个接近π的数字的正弦值。 见下图。

 π // 3.1415926535897932384626433832795... printf("%.21\n", M_PI); // 3.141592653589793115998 printf("%.21f\n", sin(M_PI));// 0.000000000000000122465 

注意:使用数学函数sine(x) ,在x =π时曲线的斜率为-1.0。 π和M_PI的差异大约是sin(M_PI)如预期的那样


我遇到了舍入错误的问题

当使用M_PI来呈现π时发生舍入问题。 M_PI是最接近π的double ,但由于π是无理的,并且所有有限double都是有理的,它们必须不同 – 即使是少量。 所以不是sin(), cos(), tan()的直接舍入问题。 sin(M_PI)简单暴露了使用不精确的π开始的问题。


如果代码使用不同的FP类型(如floatlong doubledouble以及除了53位二进制精度之外的其他内容,则会出现此问题,其中sin(M_PI)结果不同。 这不是一个精确的问题,而是一个非理性/理性问题。

正弦(x)接近π

有两个错误来源。 sin()函数和M_PI的近似值。 即使sin()函数是“完美的”,它也不会返回零,除非M_PI的值也是完美的 – 它不是。

我认为这将取决于系统。 我不认为标准对先验函数的准确性有任何说法。 不幸的是,我不记得有任何关于函数精度的讨论,所以你可能不得不自己弄明白。

我在我的系统上得到了完全相同的结果 – 我说它足够接近了

我会通过将格式字符串更改为“%f \ n”来解决问题:)

但是,这会给你一个“更好”的结果,或者至少在我的系统上它会给出-3.661369e-245

 #include  #include  int main(int argc, char *argv[]) { printf("%e\n", (long double)sin(M_PI)); return 0; } 

除非您的程序需要有效数字到小数点后16位或更多,否则您可以手动进行舍入。 根据我编程游戏的经验,我们总是将小数点数舍入为可容忍的有效数字。 例如:

 #include  #include  #include  #define HALF 0.5 #define GREATER_EQUAL_HALF(X) (X) >= HALF double const M_PI = 2 * acos(0.0); double round(double val, unsigned places = 1) { val = val * pow(10.0f, (float)places); long longval = (long)val; if ( GREATER_EQUAL_HALF(val - longval) ) { return ceil(val) / pow(10.0f, (float)places); } else { return floor(val) / pow(10.0f, (float)places); } } int main() { printf("\nValue %lf", round(sin(M_PI), 10)); return 0; } 

可能实施的准确性太低

 M_PI = 3.14159265358979323846 (20 digits) 

http://fresh2refresh.com/c/c-function/c-math-h-library-functions/