2009-11-15 72 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

最快的方法是簡單地預先計算它們並將其存儲在查找表中。

當然,這一切都取決於您期望計算它的值的精度。更多細節會很好。