減算する必要がある2つの符号なし整数(xとy)があります。 xは常にyよりも大きい。ただし、xとyはどちらもラップアラウンドできます。たとえば、両方がバイトの場合、0xffの後に0x00が来ます。問題のケースは、xが回り込む場合、yは回り込む場合です。ここで、xはyよりも小さいように見えます。幸い、xは2回ラップしません(1回だけが保証されます)。バイトを想定すると、xはラップされて0x2になりましたが、yはラップされておらず、0xFEです。 x-yの正解は0x4であるはずです。
多分、
( x > y) ? (x-y) : (x+0xff-y);
しかし、私は別の方法があると思います、2の補数を含む何かですか?そしてこの組み込みシステムでは、xとyは最大のunsigned int型なので、0xff ...を追加することはできません
ステートメントを記述する最良の方法は何ですか(ターゲット言語はC)。
2つのnsigned整数を仮定:
明確にするために:元のポスターで説明されているシナリオは混乱を招くようですが、ハードウェアティックカウンターやプロトコルのシーケンス番号など、固定幅のカウンターが単調に増加するのが一般的です。カウンタが(たとえば8ビットの場合)0xfc、0xfd、0xfe、0xff、0x00、0x01、0x02、0x03などになり、xとyの2つの値のうち、xが後であることがわかります。 x == 0x02およびy == 0xfeの場合、2つのn-bit値の減算がモジュロ2をラップすると仮定して、x-y(8ビットの結果として)の計算は4の正しい答えを与えます。ん -どのC99が符号なしの値の減算を保証するか。 (注:C標準ではnotはsigned値の減算に対してこの動作を保証します。)
ここでは、「大きい」から「小さい」を差し引いたときに「うまくいく」理由をもう少し詳しく説明します。
これに入るいくつかの事…
1。ハードウェアでは、減算は加算を使用します。適切なオペランドは、加算される前に単に否定されます。
2。 2の補数(ほとんどすべてが使用)で、整数はすべてのビットを反転してから1を追加することによって否定されます。
ハードウェアは、これを上記の説明よりも効率的に実行しますが、これは減算の基本的なアルゴリズムです(値が符号なしの場合でも)。
したがって、8ビットの符号なし整数を使用して図2 – 250にしましょう。バイナリでは、
0 0 0 0 0 0 1 0
- 1 1 1 1 1 0 1 0
減算されるオペランドを否定してから加算します。否定するには、すべてのビットを反転してから1を追加することを思い出してください。2番目のオペランドのビットを反転した後、
0 0 0 0 0 1 0 1
次に、1を追加した後、
0 0 0 0 0 1 1 0
今、追加を実行します...
0 0 0 0 0 0 1 0
+ 0 0 0 0 0 1 1 0
= 0 0 0 0 1 0 0 0 = 8, which is the result we wanted from 2 - 250
多分私は理解していませんが、何が間違っているのですか?
unsigned r = x - y;
述べられているように、質問は紛らわしいです。符号なしの値を減算しているとおっしゃいました。あなたが言ったように、x
が常にy
よりも大きい場合、x - y
は、ラップアラウンドまたはオーバーフローすることはできません。だからあなたはただx - y
(必要な場合)、それだけです。
これは、循環バッファの空き容量を決定したり、スライディングウィンドウフロー制御を行ったりするための効率的な方法です。 head
とtail
には_unsigned int
_ sを使用してください-それらをインクリメントしてラップしてください!バッファー長は2の累乗でなければなりません。
free = ((head - tail) & size_mask)
、ここで_size_mask
_は2 ^ n-1のバッファーまたはウィンドウサイズです。
問題は次のように述べられるべきです:
クロックの2つのポインターa
とb
の位置(角度)がuint8_tで指定されていると仮定します。全体の状況は、uint8_tの256の値に分割されます。 2つのポインター間の短い距離を効率的に計算するにはどうすればよいですか?
解決策は次のとおりです。
uint8_t smaller_distance = abs( (int8_t)( a - b ) );
さもなければabs()よりも効率的なものがあるので、私にはこれ以上効率的なものはないと思います。
すでに正しい答えをコードに入れるだけです:
Xが小さい方の値であることがわかっている場合は、次の計算が機能します。
int main()
{
uint8_t x = 0xff;
uint8_t y = x + 20;
uint8_t res = y - x;
printf("Expect 20: %d\n", res); // res is 20
return 0;
}
どちらが小さいかわからない場合:
int main()
{
uint8_t x = 0xff;
uint8_t y = x + 20;
int8_t res1 = (int8_t)x - y;
int8_t res2 = (int8_t)y - x;
printf("Expect -20 and 20: %d and %d\n", res1, res2);
return 0;
}
この場合、違いはuint8_t
の範囲内でなければなりません。
コードの実験は、ソリューションをよりよく理解するのに役立ちました。
他の全員の返信をエコーするには、2つを差し引いて、結果を符号なしと解釈すれば問題ありません。
明示的な反例がない限り。
x = 0x2
、y= 0x14
の例は0x4
ではなく、0xEE
になります。