Reputation: 77
I have a problem with an arithmetic operation with unsigned integer variables.
All the variables are defined as uint32_t. This is the arithmetic operation:
batt += (uint32_t) ((((charg - discharg) * (time_now - time_old)) / 1000) + 0.5);
The values before the operation are:
batt = 8999824
charg = 21
discharg = 1500
time_now = 181
time_old = 132
The problem is that the result after the operation is
batt = 13294718
instead of
batt = 8999752
What's the reason?
Thanks in advance.
Upvotes: 1
Views: 440
Reputation: 154169
You have 2 problems.
charg < discharg
as so creates a wrap-around answer of 4294965817 for charg - discharg
. See below as to why you ended up with 13294718.
Do the biasing (+ 0.5) before the /1000
, else the integer division will all ready have tossed the fractional part.
Recommended fix 1: insure charg >= discharg.
OR
Recommended fix 1: change charg, discharg, time_now, time_old and maybe batt to int32_t
.
Recommended fix 2: change your rounding to batt += (uint32_t) ((Product / 1000.0) + 0.5);
OR
Recommended fix 2: change your rounding to batt += (Product + 500*sign(Product))/1000;
Apparent errant code - step by step.
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
Upvotes: 1
Reputation: 10136
The result of the charg - discharg
is negative, thus all expression is a negative, that is a pretty big unsigned
.
Upvotes: 1