2009-11-15 70 views
2

有没有人知道(最好是快速)的方式来计算在4.12固定点的角度的正弦? (其中,其结果是一个圆的任32768ths或度)定点逆正弦

4.12定点装置的数目是16位并且被左移12,所以变为1.0(1 < < 12)或4096 0.5是(0.5 < < 12)== 2048等

+0

你在找什么语言约5%? C/C++? – 2009-11-15 03:21:27

回答

8

如果您想要最高速度,预先计算是要走的路。既然你有可能的输入,那么天真的方法就是拥有一组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

所以您的查找表只需要按住VA介于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,真正的和插值的一个表如下(假设我们只存储值甚至xx奇数值进行插值,标有以下*):

现在
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或六个半K.

+1

用于表格查找的+1,但不是插值,您可能需要使用CORDIC。 – 2010-07-13 13:13:28

1

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

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