【问题标题】:Can computing tan(x)=sin(x)/cos(x) cause a loss of precision?计算 tan(x)=sin(x)/cos(x) 会导致精度损失吗?
【发布时间】:2016-04-19 14:17:21
【问题描述】:

在从 unix m 数学库调用 sincos(x,&s,&c) 之后,很自然地会得到 s/c 的切线。这是安全的,还是可能存在(生病的)情况,由于精度问题,应该首选(据说)更昂贵的tan(x)

【问题讨论】:

  • 您认为“精度损失”究竟是什么?你能缩小你认为“安全”的范围吗?在您的用例中,sin()/cos(x)tan(x) 相比有多少额外的错误是可以接受的?
  • 根据您获得该余弦的位置,它可能在 pi/2 附近有较大的相对误差,因为它是一个很小的数字,除以它会转化为切线中的较大绝对误差。跨度>
  • @njuffa 我想这取决于具体的应用程序,但由于我更担心灾难而不是极端精度,让我们将阈值固定为 1e-6 的双精度相对偏差。
  • @harold 我编辑了指定余弦原点的问题。
  • 我猜你的意思是libm?有任意数量的libm 实现。假设有问题的libm 实现sincos() 使得在整个输入域中准确计算正弦和余弦(最多有几个ulps 的误差界限),而不是,将tan(x) 计算为@987654332 @ 是安全的,但由于除法的额外舍入误差,最大 ulp 误差通常会略大于 tan(x) 本身。对于float 数据,这很容易通过详尽的测试来显示。

标签: performance floating-point precision trigonometry scientific-computing


【解决方案1】:

如果sin(x)的误差是es,cos(x)的误差是ec,那么t=(sin(x)/cos(x)的误差是

et = abs(t)*sqrt((es/sin(x))^2 + (ec/cos(x))^2)

sin、cos 和 tan 的误差应该正好在数字表示乘以该值的精度附近,可能相差一两个。由于误差会随着数字的精度而变化,所以上式简化为

et = sqrt(es^2 + ec^2)

并且 es 和 ec 应该彼此靠近。因此,使用 sin/cos 而不是重新计算正切的总误差应该比直接计算正切的误差大约 sqrt(2) 倍。

假设 sin、cos 和 tan 中的误差几乎相同,但如今这是一个非常好的假设。在函数的范围内有一个小的误差摆动,但应该在计算过程中使用一些扩展精度位来处理,并且不应该在您看到的值中显着显示。

这是否重要当然取决于具体情况。

请参阅 http://lectureonline.cl.msu.edu/~mmp/labs/error/e2.htm 以获得关于错误传播的简单粗暴的介绍,这是解决此类问题的好方法。

【讨论】:

  • 这个公式如何解释除法造成的误差?
  • 这个答案完全忽略了浮点代数的技巧,这是我担心的根源。
  • 其实这个答案专门关于浮点代数的技巧。任何浮点计算都存在固有错误。在最好的情况下(通常是您看到的良好浮点触发函数),错误是由浮点数的有限精度引起的。这个错误根据很好理解的错误传播规则通过代数传播。我引用的参考资料对该主题进行了非常简短的介绍。它专门处理通过除法运算传播的错误。