2012-04-02 35 views
1

現在我做如下:我怎麼能提高精度,無漂浮Ç

uint8_t ManualFlow = 40; // 0 -> 255  Unsigned Char 

uint24_t ME; // 0 -> 16777215 Unsigned Short Long 
ME = (uint24_t) ManualFlow*10; // Have to make this hack otherwise malfunction in calculation 
ME /= 6; 
ME *= (80 - 60); 
ME /= 100; 
ME *= 414; 

最終結果是:

40*10 = 400 
400/6 = 66 
66*20 = 1320 
1320/100 = 13 
13*414 = 5382 

我很想與此類似:

4/60 = 0,0667 * 20 * 4188 * 0,998 = 5576 (more accurate). 

如何在不使用float s或double s的情況下做到這一點更準確,最重要的是 不會增加我的代碼太多。

親切的問候 Sonite

+0

因爲我有一個uint24_t我想我會只是增加ManualFlow * 10 * Manualflow 100。這將使它更準確。我可以有 最大的值是:「1000」 * 10/6 *「100」/100 * 414 = 689724 – Christian 2012-04-03 09:12:00

+0

你在那裏浪費位......如果你有一個uint8_t和uint24_t,這意味着你可以左移的uint8_t乘以16位。這比乘以100大約多600倍,並且再快一點,與位移相比,乘法運算非常昂貴。 – 2012-04-03 10:18:40

回答

0

結論:

我的初始代碼沒有那麼好的準確性,是「這個大」。

通過這樣做,下面我增加了與「38字節」的代碼,並取得了較好的精度

ME = (uint24_t) ManualFlow*100; 
ME /= 6; 
ME *= (Port[2].AD - Port[3].AD); 
ME /= 100; 
ME *= 414; 
ME /= 10; 

我做固定點,但它增加了代碼多「1148個字節的最佳精度 - >

// Utility macros for dealing with 16:16 fixed-point numbers 
#define I2X(v) ((int32_t) ((v) * 65536.0 + 0.5)) // Int to Fix32 
#define X2I(v) ((int16_t) ((v) + 0x8000 >> 16))  // Fix to Int 

ME = I2X(ManualFlow*10); //400 * 65536.0 + 0.5 = 26214400 
ME = I2X(ME/6); // 26214400/6 = 4369066 
ME = I2X(ME * 20); // = 87381320 
ME = I2X(ME/100); // = 873813 
ME = I2X(ME * 414); // 361758582 
ME = X2I(ME); // 158FFF76 + 8000 >> 16 15907F76 >> 16 = 5520 

希望它可以幫助別人!

親切的問候 Sonite

0

乘所有通過例如輸入(1 < < 8)轉換爲更大的數據類型,然後執行所需的數學運算,然後將結果除以(1 < < 8)。

1

如果你確信結果將永遠不會溢出,做你的乘法部門之前:

uint24_t ME; 
ME = (uint24_t)ManualFlow*10; 
ME *= (80 - 60); 
ME *= 414; 
ME /= (6 * 14); 

如果你需要比整數精度更高,但要避免浮點,可以考慮使用fixed-point arithmetic代替。

+0

啊...這是一個接近的。我可以在這裏得到的最大值是:400 *(100)* 414 /(6 * 14)= 16560000.就像你說的,必須確定它不會溢出。 我認爲另一個approatch後,我會去。 – Christian 2012-04-03 09:06:55

1

你指的是定點算術(而不是浮點)。您可以隨時將整數的大小增加到uint64_t之類的值並乘以10以達到所需的精度。然而,我會建議使用base-2固定點(即向左移動一定數量的比特,而不是乘以10來達到某個功率)。它(更快)並且可以更準確。

0

我可能是有點晚來回答原始的海報,但對後人還應當指出的是,定點部門往往還可以避免當速度是一個非常重要的小型處理器。由變量司往往不可避免的,但可以(幾乎)總是使用一個乘法和一個常數,其可以吃了許多處理器週期,尤其是對類型的比小的處理器的數據寬度更大的代替除法的移位。取而代之的

uint16_t x = somevalue; //somevalue known to be between 0 and 65535 
x /= 107; 

您可以使用:

uint32_t x = somevalue; 
x *= 39199; //chosen to be 2^n/107 
      //n chosen to maximum value without exceeding 65536 
x >>= 22; //n = 22 in this case 

注:這是不太可讀的代碼,但如果這是一種算法,其中性能是至關重要的,這種優化可以使用(謹慎)。