2013-04-22 33 views
1

我對使用無符號整數變量的算術運算有問題。使用無符號整數運算結果錯誤

所有變量定義爲uint32_t。 這是算術運算:

batt += (uint32_t) ((((charg - discharg) * (time_now - time_old))/1000) + 0.5); 

操作之前的值是:

batt = 8999824 
charg = 21 
discharg = 1500 
time_now = 181 
time_old = 132 

的問題是,操作後的結果是

batt = 13294718 

代替

batt = 8999752 

是什麼原因?

在此先感謝。

+0

'charg - discharg'使無符號整型溢出。 – MYMNeo 2013-04-22 08:09:57

+0

'charg - discharg'對你的輸入不重要。 – 2013-04-22 08:10:09

+0

'charg - discharg'低於零,因此溢出。那是故意的嗎? – CodesInChaos 2013-04-22 08:10:13

回答

1

您有2個問題。

  1. charg < discharg爲使創建的爲4294965817一charg - discharg環繞的答案。請看下面爲什麼你最終以13294718結束。

  2. /1000之前進行偏置(+0.5),否則整數除法將全部準備好拋出小數部分。

建議修復1:確保charg> = discharg。

OR

推薦修復1:變化臨時代辦,discharg,TIME_NOW,time_old也許棉絮到int32_t

推薦修復2:改變你的舍入到batt += (uint32_t) ((Product/1000.0) + 0.5);

OR

推薦修復2:改變你的舍入到batt += (Product + 500*sign(Product))/1000;


表觀不確定的代碼 - 分步實施。

uint32_t batt = 8999824; 
uint32_t charg = 21; 
uint32_t discharg = 1500; 
uint32_t time_now = 181; 
uint32_t time_old = 132; 
// batt += (uint32_t) ((((charg - discharg) * (time_now - time_old))/1000) + 0.5); 

// The big problem occurs right away. 
// Since charg is less than discharg, and unsigned arithmetic "wrap around", 
// you get (21 - 1500) + 2**32 = (21 - 1500) + 4294967296 = 4294965817 
uint32_t d1 = charg - discharg; 
uint32_t d2 = time_now - time_old; // 49 
// The product of d1 and d2 will overflow and the result is mod 4294967296 
// (49 * 4294965817) = 210453325033 
// 210453325033 mod 4294967296 = 4294894825 
uint32_t p1 = d1 * d2; 
uint32_t q1 = p1/1000; // 4294894825/1000 = 4294894.825. round to 0 --> 4294894 
double s1 = q1 + 0.5; // 4294894 + 0.5 --> 4294894.5; 
uint32_t u1 = (uint32_t) s1; // 4294894.5 round to 0 --> 4294894 
batt += u1; // 8999824 + 4294894 --> 13294718 
1

charg - discharg的結果是負數,因此所有表達式都是負數,這是一個相當大的unsigned

+0

由於兩個值都是相同的無符號類型(如果此類型小於「int」,則可能爲負),所以差異不可能爲負數。所以,差異可能是一個很大的正面價值。其他可能的問題包括乘法溢出和除法精度損失。 – 2013-04-22 08:25:00