2013-04-22 136 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

相关问题