1

我正在处理一些需要使用三角函数的编程问题。不幸的是,math.h库中的函数似乎不准确。这是一个例子:

#include <stdio.h>
#include <math.h>    
int main() {
  double a, b, c, d;
  a = sin(0.0);
  b = sin(90.0);
  c = cos(0.0);
  d = cos(90.0);
  printf("A = %lf\nB = %lf\nC = %lf\nD = %lf\n", a, b, c, d);
  return (0);
}

输出:

A = 0.000000
B = 0.893997
C = 1.000000
D = -0.448074

那么有没有办法让这些函数准确呢?还是我必须使用系列制作自己的功能?

我用谷歌搜索,到目前为止找不到任何方法来使功能准确,但使用系列。

4

2 回答 2

12

函数sin()cos()期望弧度。它们通常是“忠实的”,也就是说,它们在数学结果的 1 ULP范围内产生结果,至少对于多达几千个参数。

#include <stdio.h>
#include <math.h>    
int main() {
  double a, b, c, d;
  a = sin(0.0);
  b = sin(0.5 * 3.1415926535897932);
  c = cos(0.0);
  d = cos(0.5 * 3.1415926535897932);
  printf("A = %lf\nB = %lf\nC = %lf\nD = %lf\n", a, b, c, d);
  return (0);
}

A = 0.000000
B = 1.000000
C = 1.000000
D = 0.000000

编辑添加:

Camilo Martinez 指出,“Unit in the Last Place”是一个特殊的概念。简单来说,有有限数量的double值,在零附近更密集:

++-+-+-+---+---+-------+---------------+-------------------------------+--

您正在计算的精确三角值几乎总是介于这两个doubles 之间(唯一的例外是sin(0.0) = 0.0cos(0.0) = 1.0):

++-+-+-+---+---+-------+---------------+-------------------------------+--
                       |    ^          |
                     lower  |       upper
                     double |       double
                            |
                   exact (mathematical) result

大多数库提供的函数在正常情况下会double立即为您提供精确结果的上方或数学结果的下方。考虑到问题的难度,这非常好。

一些库提供的函数将为您提供最接近精确结果的双精度输入(甚至1E21)。这是一个惊人的结果。直到最近,这只能以昂贵的计算为代价来获得,但现在,您甚至可以获得几乎与过去不太准确的函数一样快的结果。

最后,有时您甚至没有申请sin()或申请cos()您想要的数字,而只是对其最接近的double近似值。在您的示例中,一旦修复就是这种情况:您想将sin()andcos()应用于 π/2,但不能,因为 π/2 不能表示为 a double。您必须将它们应用到最近的可用double位置(这是固定程序所做的)。

这种不准确可能会加剧。他们确实给浮点计算带来了坏名声的过程,但实际上,浮点不准确性复合的方式是非常可预测的,并且可以在编写使用浮点的程序时考虑在内。

于 2013-04-24T13:55:13.083 回答
2

如果您确实需要以度数工作并获得正确的结果,那么标准的三角函数是不够的。例如,cos(90*M_PI/180)不会屈服0.0。错误可能小于 1ulp,除非正确结果为零(或可能非常接近零),因此您可能只是决定对使用它们感到满意。为了获得更好的结果,您需要调整现有算法以在度数上工作(在某些方面这会更容易,因为参数减少是实现三角函数最困难的部分之一,在度数上是微不足道的)并做一些数值分析,以确保您在所需的误差范围内。

以度为单位工作的快速修复方法是仅使用 30 的特殊情况倍数(所有确切结果均下降),然后cos(x*M_PI/180)对所有其他值调用等。这不会是完美的,但至少它会避免在应该精确的点上引入混乱的不精确性。

于 2013-04-24T14:49:02.947 回答