【发布时间】:2019-09-21 03:52:03
【问题描述】:
我有这段代码计算正弦的猜测并将其与标准 C 库(在我的例子中是 glibc)的结果进行比较:
#include <stdio.h>
#include <math.h>
double double_sin(double a)
{
a -= (a*a*a)/6;
return a;
}
int main(void)
{
double clib_sin = sin(.13),
my_sin = double_sin(.13);
printf("%.16f\n%.16f\n%.16f\n", clib_sin, my_sin, clib_sin-my_sin);
return 0;
}
double_sin 的准确度很差(大约 5-6 位)。这是我的输出:
0.1296341426196949
0.1296338333333333
0.0000003092863615
如您所见,.12963 之后,结果不同。
一些注意事项:
我认为泰勒级数不适用于这种特定情况,更高准确度所需的阶乘无法存储在
unsigned long long中。查找表不是一种选择,它们占用太多空间,并且通常不提供任何有关如何计算结果的信息。
如果您使用幻数,请解释它们(尽管我更喜欢不使用它们)。
我更喜欢一种算法易于理解并且能够用作参考,而不是那些不是的算法。
结果不必完全准确。最低要求是 IEEE 754、C 和/或 POSIX。
我使用的是IEEE-754
double格式,可以信赖。支持的范围至少需要从
-2*M_PI到2*M_PI。如果包括范围缩小,那就太好了。
我可以使用什么更准确的算法来计算数字的正弦?
我有一个类似于 Newton-Raphson 的想法,但用于计算正弦值。 但是,我在上面找不到任何东西,正在排除这种可能性。
【问题讨论】:
-
在最好的情况下,您可以从浮点数中获得 6-9 位的准确度。更多你需要使用双重。即使那样,由于 ieee 754 浮点数学的性质,您的数字也永远不会与
sin()函数的版本完全相同。 -
(a)
unsigned long long与什么有什么关系?代码中没有unsigned long long。 (b) 你需要支持什么领域? (c) 你需要什么精度? -
x 的正弦完全由 x 的余数除以 2pi 决定,比 2**3 小一点。您需要大约 100 位余数来处理它恰好非常小的情况。最大的有限
double约为 2**1024。因此,支持double的整个域需要以一种或另一种方式将大约 1100 位的 2pi 构建到实现中。这通常通过在参数缩减期间使用的表来完成。这与您不使用表格的规定相冲突。在没有大量准备好的数据的情况下支持整个域是不可行的。 -
(100 位估计来自内存。找到最坏的情况很复杂,需要一些数论。)
-
IIRC,
double的参数减少期间余数中前导零位的最大数量为 62,因此肯定需要超过 100 位余数。实现一个忠实的四舍五入的实现还需要用比double更多的位来表示余数。所以余数计算的 120 位可能是更接近的估计。
标签: c math floating-point trigonometry ieee-754