使用无符号整数操作的结果错误

时间:2013-04-22 08:08:01

标签: c unsigned-integer

我对使用无符号整数变量的算术运算有问题。

所有变量都定义为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

是什么原因?

提前致谢。

2 个答案:

答案 0 :(得分:1)

charg - discharg的结果是否定的,因此所有表达式都是否定,这是一个非常大的unsigned

答案 1 :(得分:1)

你有两个问题。

  1. charg < discharg因此为charg - discharg创建了一个环绕答案4294965817。请参阅下文,了解您最终使用13294718的原因。

  2. /1000之前做偏差(+ 0.5),否则整数除法都准备好抛出小数部分。

  3. 推荐修复1:确保charg&gt; = discharg。

    OR

    推荐修复1:更改charg,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