sin,cos,tan和舍入误差

Jos*_*ley 5 c math floating-point trigonometry rounding

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

#include <stdio.h>
#include <math.h>

int main(int argc, char *argv[]) {
    printf("%e\n", sin(M_PI));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

该程序提供以下输出:

1.224647e-16
Run Code Online (Sandbox Code Playgroud)

当正确的答案当然是0.

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

Mar*_*ett 14

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

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

  • 也许你的math.h不包括pi的所有数字?你有无数的硬盘吗? (8认同)
  • 我正在使用Math.h中的M_PI逐字.如果编译器没有包含它的所有数字,那么就会出现严重错误.:-) (2认同)
  • 实际上,如果PI仅被定义为浮点数的精度限制,则返回浮点数的任何操作只能具有较差的准确性 - 这是在无聊的关于熵和可计算性理论的讲座中. (2认同)

And*_*oss 13

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

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

  • 请记住,你不是在计算罪(pi),而是罪(M_PI)!常数M_PI不完全是Pi,而是最接近的近似值可表示为double:M_PI =(Pi + delta),其中delta是~10e-16.将其与sin(Pi + x)= -x的扩展相结合,用于| x | << 1,并且罪恶(M_PI)产生这么小的结果并不奇怪. (5认同)
  • 对于阶数为1的角度,可以预期sin和cos(输出范围为[-1,1])的几个*10e-16的精度.使用tan = sin/cos时,输出范围是无界的,精度最佳的位置可能取决于tan函数的写入方式.绝对和分数误差都至少为10e-16. (3认同)

Mar*_*ett 6

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

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

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


chu*_*ica 6

π的正弦是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
Run Code Online (Sandbox Code Playgroud)

注意:使用数学函数sine(x),在x =π时曲线的斜率为-1.0 .π的差异M_PIsin(M_PI)- 正如预期的那样.


我遇到了舍入错误的问题

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


sin(M_PI)如果代码使用不同的FP类型float,long double或者double使用除53位二进制精度之外的其他东西,则会出现此问题,并且会出现不同的非零结果.这不是一个精确的问题,而是一个非理性/理性问题.

正弦(x)接近π