定点反正弦

时间:2009-11-15 03:14:57

标签: algorithm trigonometry fixed-point

有人知道(最好是快速)计算4.12定点角度正弦的方法吗? (结果是一个圆或度数的32768ths)

4.12定点意味着该数字是16位并且左移12,所以1.0变为(1 <12)或4096. 0.5是(0.5 <12)== 2048等等。

2 个答案:

答案 0 :(得分:8)

如果您想要最高速度,预先计算是可行的方法。由于你有2个 16 (65,536)个可能的输入,所以天真的方法是拥有一个包含许多16位值的数组(总共使用128K内存)。

但如果您不想使用所有内存(以一点速度为代价),那么可以稍微改进一下。

假设你的输入是弧度(我假设它们是因为4.12数字的范围是0到15.999 ......,不足以代表圆圈中的所有度数),你可以利用这些事实:

  • sin (n) = sin (n % (2*PI)) for n >= 2*PI
  • sin (n) = -sin (n - PI) for PI <= n < 2*PI
  • sin (n) = sin (PI - n) for PI/2 <= n < PI

因此,您的查找表只需要保持0到PI / 2弧度之间的值,从而显着降低存储要求:您只存储0到PI / 2(~1.571)而不是0到15.999的整个范围。减少了约90%。

然后,您只需要使用模数(第一个规则)将值降低到2 * PI弧度以下,并使用其他两个规则对其进行修改,以找到要查找的正确索引。 Modulo可以像整数一样快速地在固定点上工作。

所以你会看到类似的东西:

def sin(r):
    if r >= PI_BY_2:
        return sin (r % PI_BY_2)
    if r >= PI:
        return -sin (r - PI)
    if r >= PI_DIV_2:
        return sin (PI - r)
    return sin_lookup[r]
def cos(r):
    if r < PI_DIV_2:
        return sin (r + PI_DIV_2_BY_3)
    return sin (r - PI_DIV_2)

cos函数显示从同一个表中获取余弦是多么便宜,因为它们实际上只是从正弦相移90度。

如果速度极为重要且内存无关紧要,只需使用全部索引即可,无需进行任何计算。

另一个技巧是,如果你愿意牺牲一些准确性,增加使用更少的内存,就是不存储所有输入值的查找值。

鉴于正弦函数是平滑函数(没有不连续性),您可以存储每一个值,并通过简单地平均它们两侧的值来插入其间的值。

例如,如果我们有函数f(x) = x * x,则会有一个实数和插值的表(假设我们只存储偶数x的值,奇数值x是插值,标有以下*):

 x    real f(x)   interpolated f(x)
--    ---------   -----------------
 0            0                   0
 1            1                   2 *
 2            4                   4
 3            9                  10 *
 4           16                  16
 5           25                  26 *
 6           36                  36
 7           49                  50 *
 8           64                  64
 9           91                  82 *
10          100                 100

现在,这不是完美的示例,因为f(x)值之间的差异可能非常大,但对于值更接近的函数,它会更好。

例如,sin(0),sin(1)和sin(2)(度,而不是弧度)的实数值是0,0.017452406和0.034899496(这是斜率最大的地方)。 sin(0)和sin(2)的平均值为0.017449748,误差为实际值的0.0152%,一部分为6,500。

因此,对于最小的错误,您可以将内存需求减半至128K的约5%或六个半K.

答案 1 :(得分:1)

最快的方法是简单地预先计算它们并将其存储在查找表中。

当然,这一切都取决于您期望计算的值的精度。更多细节会很好。