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

どういう理由ですか?

前もって感謝します。

4

2 に答える 2

1

2 つの問題があります。

  1. charg < dischargそのため、 に対して 4294965817 のラップアラウンド回答が作成されcharg - dischargます。13294718 になった理由については、以下を参照してください。

  2. の前にバイアス (+ 0.5) を行ってください/1000

推奨される修正 1: 充電 >= 放電を保証します。

また

推奨される修正 1: charg、discharg、time_now、time_old、および多分 batt を に変更しint32_tます。

推奨される修正 2: 丸めをbatt += (uint32_t) ((Product / 1000.0) + 0.5);

また

推奨される修正 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
于 2013-07-03T16:50:05.363 に答える