我正在处理一些需要使用三角函数的编程问题。不幸的是,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
那么有没有办法让这些功能准确?或者我是否必须使用系列制作自己的功能?
我用谷歌搜索,到目前为止找不到任何方法使函数准确但使用系列。
答案 0 :(得分: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指出,“最后一位的单位”是一个专门的概念。简单来说,有double
个有限数值,密度在零附近:
++-+-+-+---+---+-------+---------------+-------------------------------+--
您计算的确切三角函数值几乎总是介于其中两个double
之间(唯一的例外是sin(0.0) = 0.0
和cos(0.0) = 1.0
):
++-+-+-+---+---+-------+---------------+-------------------------------+--
| ^ |
lower | upper
double | double
|
exact (mathematical) result
大多数库提供的函数在正常情况下会在紧接精确结果之上或紧接数学结果之下的位置提供double
。
考虑到问题的难度,这是非常好的。
对于所有输入(甚至1E21
),某些库提供的功能可以为您提供精确结果的双最近。这是一个惊人的结果。直到最近,这只能以昂贵的计算成本获得,但是现在,你甚至可以获得这种结果,几乎和过去不太准确的函数一样快。
最后,有时您甚至不会将sin()
或cos()
应用于您想要的数字,而只会将其应用于最近的double
近似值。一旦修复,您的示例就是这种情况:您希望将sin()
和cos()
应用于π/ 2,但您不能,因为π/ 2不能表示为{{1} }。您必须将它们应用到最近的可用double
(这是固定程序所做的)。
这种不准确可以复合。他们确实给浮点计算带来了坏名声的过程,但实际上,浮点不准确性的复合方式是非常可预测的,并且在编写使用浮点的程序时可以考虑到这一点。
答案 1 :(得分:2)
如果你真的需要在学位上工作并且得到正确的结果,那么标准的三角函数是不够的。例如,cos(90*M_PI/180)
不会产生0.0
。错误可能小于1ulp,除非正确的结果为零(或者可能非常接近于零),所以您可能只是决定对使用它们感到满意。为了获得更好的结果,你需要调整现有的算法以度数工作(在某些方面,这将更容易,因为参数减少,实现trig函数最困难的部分之一,在程度上是微不足道的)并做一些数值分析,以确保您在所需的误差范围内。
以度为单位的快速修正工具将是30的特殊情况倍数(其中所有确切结果都会下降),并为所有其他值调用cos(x*M_PI/180)
等。这不是完美的,但至少它会避免在应该准确的点上引入混乱的不精确性。