2016-08-20 12 views
-5

我試圖消除在嵌入式應用中的所有浮點計算,我需要縮放/乘以0.0000000004656f符號長32位整數。 (2147483648分之1)計算,而不花車乘長整型(32位)0.0000000004656f

的背景是

(pulse[i] * (triosc[i] * 0.0000000004656f)) 

兩個pulse[i]triosc[i]簽署長32個整數

所以我需要0.0f1.0f之間進行約束我triosc[i]值,而不使用浮動算術。

編輯:

saw_x2[i] = (long)(pulse[i] * (triosc[i] * 0.0000000004656f)); 
sine_osc[i] = (long)(((triangle2[i] * (saw_x2[i] * 0.0000000004656f))) * 
         (pulse[i] * 0.0000000004656f)) << 2; 
return (sine_osc[i]); 
+0

您是否在尋找「是/否」的答案? – usr2564301

+1

由於'2147483648'在十六進制中是'8000000',你只需保留這個符號,那實際上是你想要的嗎? – fvu

+0

看看**部門之後的代碼**,瞭解部門完成的原因以及劃分的值如何使用。像往常一樣,我們可以給你提供的信息非常有限的唯一答案是「可能」和「它取決於」... – fvu

回答

6

pulse[i]triosc[i]中的固定點值是帶符號數量,單位爲2 -31。數學值爲pulse [i]/2 and triosc [i]/2。雖然你可以,只要你不溢出添加這些值,乘以他們需要通過2 調整。這是與pulse[i] * (triosc[i] * 0.0000000004656f))約完成,但要注意,浮點值不夠精確,它會更精確的寫pulse[i] * (triosc[i]/2147483648.F),但結果仍然會失去精度,由於只有23 matissa的比特float表示。

在執行整數運算的乘法與一個64位的中間步驟實際上是更精確的。

這是可以做到這樣:

((uint64_t)pulse[i] * triosc[i]) >> 31 

或等價:

((long long)pulse[i] * triosc[i]) >> 31 

編輯

你真的應該使用類型從<stdint.h>以避免對大小假設long。它是你當前的系統在32位,但它可能是64上的下一個硬件。這裏是你如何可以重寫表達式:但是

int32_t saw_x2[SIZE]; 
int32_t pulse[SIZE]; 
int32_t triosc[SIZE]; 
int32_t triangle2[SIZE]; 
int32_t sine_osc[SIZE]; 

... 

saw_x2[i] = (int32_t)(((int64_t)pulse[i] * triosc[i]) >> 31); 
int64_t temp = ((int64_t)triangle2[i] * saw_x2[i]) >> 31; 
sine_osc[i] = (int32_t)(((temp * pulse[i]) >> 31) << 2); 
return sine_osc[i]; 

注意,如果其中的任何值變爲負值,右移位不能保證產生正確的結果。通過2147483648分割將是所要求的方法,但可能會產生低效率的代碼:

saw_x2[i] = (int32_t)((int64_t)pulse[i] * triosc[i]/2147483648); 
int64_t temp = (int64_t)triangle2[i] * saw_x2[i]/2147483648; 
sine_osc[i] = (int32_t)((temp * pulse[i]/2147483648) << 2); 
return sine_osc[i]; 

另外,由於你通過4在最後一步繁殖,則可以通過將由2 代替分割得到的精度2以上位:

sine_osc[i] = (int32_t)(temp * pulse[i]/536870912); 
+1

當然'pluse [i]'和'triosc [i]'中的值是整數。重要的是暗含的分母。換句話說,小數部分的位數(*小數點後*)。如果值限制在[-1.0; 1.0 []範圍內,則可以使用小數部分的31位。 – chqrlie

+1

好吧,對不起,它的工作原理! –

+0

感謝您的回答。 –

5

使用此

(((int64_t)pulse[i]) * triosc[i]) >> 31 

其結果將是一個有符號的32位整數,範圍從-1.0..0.9999...時解釋爲與小數點右邊的固定點數目在符號位之後。 (注意-1解釋。另一種解釋可能是INT_MIN實際上-0是。)

之前乘以轉換爲更大的數據類型的原因是,否則你將失去準確性。由於您的目標大小恰好是輸入操作數的大小,因此您會失去一切。

+1

問題的實際翻譯將是'((int_64t)pulse [i] * triosc [i])>> 31;'還要注意答案代碼中缺少括號。 – chqrlie

+0

@chqrlie:31? (思考)啊 - **兩個** int32都有一個符號位。得到它了! – usr2564301

+0

「*停止形成*」在哪個意義上? @JohnAm – alk