到this SO question的答案是在執行方面非常全面。下面是多一點的解釋比我看到那邊:
一種方法是將所有的號碼強行進入一個範圍,比如[-1.0,1.0)。然後將這些數字映射到範圍[-2^15,(2^15)-1]。例如,
Half = round(0.5*32768); //16384
Third = round((1.0/3.0)*32768); //10923
當你乘這兩個數字你會得到32768
Temp = Half*Third; //178962432
Result = Temp/32768; //5461 = round(1.0/6.0)*32768
分水嶺在最後一行大約需要一個額外的縮放步驟乘法提出的觀點Patros。如果你明確地寫出2^N比例,這就更有意義了:
x1 = x1Float*(2^15);
x2 = x2Float*(2^15);
Temp = x1Float*x2Float*(2^15)*(2^15);
Result = Temp/(2^15); //get back to 2^N scaling
這就是算術。爲了便於實施,請注意,兩個16位整數乘法需要一個32位的結果,所以溫度應該是32位。此外,32768在16位變量中無法表示,因此請注意,編譯器將生成32位立即數。而當你已經注意到,你可以轉移到乘以2的冪/分,所以你可以寫
N = 15;
SInt16 x1 = round(x1Float * (1 << N));
SInt16 x2 = round(x2Float * (1 << N));
SInt32 Temp = x1*x2;
Result = (SInt16)(Temp >> N);
FloatResult = ((double)Result)/(1 << N);
但假設[-1,1)是不正確的範圍是多少?如果您想限制你的號碼,比方說,[-4.0,4.0),你可以使用N = 13,那麼你有1個符號位,二進制點之前兩個位,和13後。這些分別稱爲1.15和3.13定點小數類型。您在淨空分數中交易精度。
添加和減去分數類型,只要罰款,你看出來的飽和度的作品。正如帕特洛斯所說,分割實際上取消了。所以,你所要做的
,或者保持精度
Quotient = (SInt16)(((SInt32)x1 << N)/x2); //x1 << N needs wide storage
乘法和整數除以正常工作。例如,要除以6,你可以簡單地寫
Quotient = x1/6; //equivalent to x1Float*(2^15)/6, stays scaled
而且在通過2的冪劃分的情況下,
Quotient = x1 >> 3; //divides by 8, can't do x1 << -3 as Patros pointed out
加和減整數,不過,並沒有天真地工作。您必須首先查看該整數是否適合您的x.y類型,製作等效的小數類型,然後繼續。
我希望這可以幫助的想法,看看在清潔的實現,其他問題的代碼。
這就是我的想法。但是,你不會乘以2的冪來得到你的定點嗎?這隻涉及移位。 – 2009-09-18 15:58:34
當您使用簽名的整數時,移動會變得時髦。兩者的能力更有效率,但更難以調試。如果這是第一次使用固定點,我會建議十的權力。 – patros 2009-09-18 16:10:06
感謝您的回答! 我還沒有找到一個實現無浮動ADSR信封的優雅方法。 我剛試過右移樣本,結果是除以2的任意冪,因此降低了幅度 - 但我無法弄清楚如何創建一個平滑的包絡。 – 2009-09-18 18:36:27