ここで行われている行間は非常に多くの読み物です。ただし、 3 が返され、 returnとreturngetField(7, 1, 0)
が必要な場合は、これが目的である可能性があります。getFieldSignExtended(15, 2, 0)
-3
getFieldSignExtended(3, 2, 0)
+3
概念は、元の値のビット hi:lo からの n ビット フィールドを 2 の補数として扱うことです。n ビットの最初のビットが 1 の場合、n ビット フィールドを負の数として扱います。3 ビット フィールドの最初のビットが 0 の場合は、それを正の数として扱います。
#include <assert.h>
#include <limits.h>
#include <stdio.h>
extern int getFieldSignExtended(int value, int hi, int lo);
enum { INT_BITS = CHAR_BIT * sizeof(int) };
int getFieldSignExtended(int value, int hi, int lo)
{
assert(lo >= 0);
assert(hi > lo);
assert(hi < INT_BITS - 1);
int bits = (value >> lo) & ((1 << (hi - lo + 1)) - 1);
if (bits & (1 << (hi - lo)))
return(bits | (~0U << (hi - lo)));
else
return(bits);
}
3 つのアサーションは単純明快です。唯一物議を醸しているのは、コードがビット 31 の処理を拒否していることです。hi = 31 および lo = 0 で呼び出した場合、シフト (hi - lo + 1) が大きすぎて、動作が未定義になります。また、負の数を右にシフトするという実装定義の動作にも遭遇します。&
これらの問題は、符号なし整数引数を取り、 if 操作を行わないことで解決できますhi - lo + 1 == INT_BITS
。問題の修正は、読者の課題として残されています。
への代入bits
は値を右にシフトし、正しいビット数でマスクします。(1 << (hi - lo + 1)) - 1
は、フィールド内のビット数より 1 だけ多く左に 1 をシフトし、次に 1 を減算して、フィールド内の各ビット位置に対してバイナリ 1 のストリングを生成します。たとえば、hi = 2、lo = 0 の場合、これは 1 を左に 3 桁シフトし、バイナリ 1000 を生成します。1 を引くと 0111 になるため、正しい 3 ビットが選択されます。したがって、bits
n ビット整数の適切なビット セットが含まれます。
このif
テストでは、n ビット整数の最上位ビットが設定されているかどうかをチェックします。符号ビットが設定されていない場合は、単純に value を返しますbits
。符号ビットが設定されている場合、実行するトリッキーな計算があります。これは、この回答の最初のドラフトで (非常に) 間違っていました。3 ビット = 101 のフィールドがあるとします。3 ビットの 2 の補数として、-3 を表します。フルサイズの を生成するには、これをすべて 1 で左に拡張する必要があります-1
。の値~0
はすべてビット 1 です。それがビット単位で左にシフトさhi - lo
れると、値の非符号ビットに一連のゼロが残ります。だけ左にシフトした場合も機能しますが、必要ではないhi - lo + 1
余分な計算が必要です。+ 1
このテスト ハーネスを使用して、コードが正しく機能していることを確認しました。体系的なテストの出力は厳密です (小さい数値に対して)。これにより、計算値が期待値と一致することが保証されます。「徹底的な」テストは完全ではありません。1 つの値のみをテストし、問題 (たとえば、hi = 31 と lo = 0 を使用すると私のマシンで 0 という誤った答えが返されるなど) とパターンを観察するためのものです。
static const struct
{
int value;
int hi;
int lo;
int wanted;
} tests[] =
{
{ 0x0F, 1, 0, -1 },
{ 0x0F, 2, 0, -1 },
{ 0x0F, 2, 1, -1 },
{ 0x0F, 3, 1, -1 },
{ 0x0F, 4, 2, +3 },
{ 0x0F, 5, 0, +15 },
{ 0x0F, 5, 1, +7 },
{ 0x0F, 5, 2, +3 },
{ 0x0F, 5, 3, +1 },
{ 0x0F, 5, 4, 0 },
{ 0x03, 2, 0, +3 },
{ 0xF3, 2, 0, +3 },
{ 0xF3, 3, 0, +3 },
{ 0xF3, 4, 0, -13 },
{ 0xF3, 5, 0, -13 },
{ 0xF3, 6, 0, -13 },
{ 0xF3, 7, 0, -13 },
{ 0xF3, 7, 1, -7 },
{ 0xF3, 7, 2, -4 },
{ 0xF3, 7, 3, -2 },
{ 0xF3, 7, 4, -1 },
{ 0xF3, 8, 0, 0xF3 },
};
enum { NUM_TESTS = sizeof(tests) / sizeof(tests[0]) };
static const char s_pass[] = "== PASS ==";
static const char s_fail[] = "!! FAIL !!";
static void systematic_test(void)
{
int fail = 0;
for (int i = 0; i < NUM_TESTS; i++)
{
char const *pf = s_fail;
int actual = getFieldSignExtended(tests[i].value, tests[i].hi, tests[i].lo);
if (actual == tests[i].wanted)
pf = s_pass;
else
fail++;
printf("%s GFSX(%+4d = 0x%.4X, %d, %d) = %+4d = 0x%.8X (wanted %+4d = 0x%.8X)\n",
pf, tests[i].value, tests[i].value, tests[i].hi, tests[i].lo, actual, actual,
tests[i].wanted, tests[i].wanted);
}
printf("%s\n", (fail == 0) ? s_pass : s_fail);
}
static void exhaustive_test(void)
{
int value = 0x5FA03CE7;
for (int i = 1; i < INT_BITS - 1; i++)
{
for (int j = 0; j < i; j++)
{
int actual = getFieldSignExtended(value, i, j);
printf("%11sGFSX(%d = 0x%X, %2d, %2d) = %+10d = 0x%.8X\n", "",
value, value, i, j, actual, actual);
}
}
}
int main(void)
{
int result1 = getFieldSignExtended(15, 2, 0);
int result2 = getFieldSignExtended( 3, 2, 0);
printf("GFSX(15, 2, 0) = %+d = 0x%.8X\n", result1, result1);
printf("GFSX( 3, 2, 0) = %+d = 0x%.8X\n", result2, result2);
printf("\nSystematic test\n");
systematic_test();
printf("\nExhaustive test\n");
exhaustive_test();
return(0);
}
これは、徹底的なテストの前のテスト コードの出力と、徹底的なテストからの出力の小さな選択です。
GFSX(15, 2, 0) = -1 = 0xFFFFFFFF
GFSX( 3, 2, 0) = +3 = 0x00000003
Systematic test
== PASS == GFSX( +15 = 0x000F, 1, 0) = -1 = 0xFFFFFFFF (wanted -1 = 0xFFFFFFFF)
== PASS == GFSX( +15 = 0x000F, 2, 0) = -1 = 0xFFFFFFFF (wanted -1 = 0xFFFFFFFF)
== PASS == GFSX( +15 = 0x000F, 2, 1) = -1 = 0xFFFFFFFF (wanted -1 = 0xFFFFFFFF)
== PASS == GFSX( +15 = 0x000F, 3, 1) = -1 = 0xFFFFFFFF (wanted -1 = 0xFFFFFFFF)
== PASS == GFSX( +15 = 0x000F, 4, 2) = +3 = 0x00000003 (wanted +3 = 0x00000003)
== PASS == GFSX( +15 = 0x000F, 5, 0) = +15 = 0x0000000F (wanted +15 = 0x0000000F)
== PASS == GFSX( +15 = 0x000F, 5, 1) = +7 = 0x00000007 (wanted +7 = 0x00000007)
== PASS == GFSX( +15 = 0x000F, 5, 2) = +3 = 0x00000003 (wanted +3 = 0x00000003)
== PASS == GFSX( +15 = 0x000F, 5, 3) = +1 = 0x00000001 (wanted +1 = 0x00000001)
== PASS == GFSX( +15 = 0x000F, 5, 4) = +0 = 0x00000000 (wanted +0 = 0x00000000)
== PASS == GFSX( +3 = 0x0003, 2, 0) = +3 = 0x00000003 (wanted +3 = 0x00000003)
== PASS == GFSX(+243 = 0x00F3, 2, 0) = +3 = 0x00000003 (wanted +3 = 0x00000003)
== PASS == GFSX(+243 = 0x00F3, 3, 0) = +3 = 0x00000003 (wanted +3 = 0x00000003)
== PASS == GFSX(+243 = 0x00F3, 4, 0) = -13 = 0xFFFFFFF3 (wanted -13 = 0xFFFFFFF3)
== PASS == GFSX(+243 = 0x00F3, 5, 0) = -13 = 0xFFFFFFF3 (wanted -13 = 0xFFFFFFF3)
== PASS == GFSX(+243 = 0x00F3, 6, 0) = -13 = 0xFFFFFFF3 (wanted -13 = 0xFFFFFFF3)
== PASS == GFSX(+243 = 0x00F3, 7, 0) = -13 = 0xFFFFFFF3 (wanted -13 = 0xFFFFFFF3)
== PASS == GFSX(+243 = 0x00F3, 7, 1) = -7 = 0xFFFFFFF9 (wanted -7 = 0xFFFFFFF9)
== PASS == GFSX(+243 = 0x00F3, 7, 2) = -4 = 0xFFFFFFFC (wanted -4 = 0xFFFFFFFC)
== PASS == GFSX(+243 = 0x00F3, 7, 3) = -2 = 0xFFFFFFFE (wanted -2 = 0xFFFFFFFE)
== PASS == GFSX(+243 = 0x00F3, 7, 4) = -1 = 0xFFFFFFFF (wanted -1 = 0xFFFFFFFF)
== PASS == GFSX(+243 = 0x00F3, 8, 0) = +243 = 0x000000F3 (wanted +243 = 0x000000F3)
== PASS ==
Exhaustive test
GFSX(1604336871 = 0x5FA03CE7, 1, 0) = -1 = 0xFFFFFFFF
GFSX(1604336871 = 0x5FA03CE7, 2, 0) = -1 = 0xFFFFFFFF
GFSX(1604336871 = 0x5FA03CE7, 2, 1) = -1 = 0xFFFFFFFF
GFSX(1604336871 = 0x5FA03CE7, 3, 0) = +7 = 0x00000007
GFSX(1604336871 = 0x5FA03CE7, 3, 1) = +3 = 0x00000003
GFSX(1604336871 = 0x5FA03CE7, 3, 2) = +1 = 0x00000001
GFSX(1604336871 = 0x5FA03CE7, 4, 0) = +7 = 0x00000007
GFSX(1604336871 = 0x5FA03CE7, 4, 1) = +3 = 0x00000003
GFSX(1604336871 = 0x5FA03CE7, 4, 2) = +1 = 0x00000001
GFSX(1604336871 = 0x5FA03CE7, 4, 3) = +0 = 0x00000000
GFSX(1604336871 = 0x5FA03CE7, 5, 0) = -25 = 0xFFFFFFE7
GFSX(1604336871 = 0x5FA03CE7, 5, 1) = -13 = 0xFFFFFFF3
GFSX(1604336871 = 0x5FA03CE7, 5, 2) = -7 = 0xFFFFFFF9
GFSX(1604336871 = 0x5FA03CE7, 5, 3) = -4 = 0xFFFFFFFC
GFSX(1604336871 = 0x5FA03CE7, 5, 4) = -2 = 0xFFFFFFFE
GFSX(1604336871 = 0x5FA03CE7, 6, 0) = -25 = 0xFFFFFFE7
GFSX(1604336871 = 0x5FA03CE7, 6, 1) = -13 = 0xFFFFFFF3
GFSX(1604336871 = 0x5FA03CE7, 6, 2) = -7 = 0xFFFFFFF9
GFSX(1604336871 = 0x5FA03CE7, 6, 3) = -4 = 0xFFFFFFFC
GFSX(1604336871 = 0x5FA03CE7, 6, 4) = -2 = 0xFFFFFFFE
GFSX(1604336871 = 0x5FA03CE7, 6, 5) = -1 = 0xFFFFFFFF
...
GFSX(1604336871 = 0x5FA03CE7, 29, 28) = +1 = 0x00000001
GFSX(1604336871 = 0x5FA03CE7, 30, 0) = -543146777 = 0xDFA03CE7
GFSX(1604336871 = 0x5FA03CE7, 30, 1) = -271573389 = 0xEFD01E73
GFSX(1604336871 = 0x5FA03CE7, 30, 2) = -135786695 = 0xF7E80F39
GFSX(1604336871 = 0x5FA03CE7, 30, 3) = -67893348 = 0xFBF4079C
GFSX(1604336871 = 0x5FA03CE7, 30, 4) = -33946674 = 0xFDFA03CE
GFSX(1604336871 = 0x5FA03CE7, 30, 5) = -16973337 = 0xFEFD01E7
GFSX(1604336871 = 0x5FA03CE7, 30, 6) = -8486669 = 0xFF7E80F3
GFSX(1604336871 = 0x5FA03CE7, 30, 7) = -4243335 = 0xFFBF4079
GFSX(1604336871 = 0x5FA03CE7, 30, 8) = -2121668 = 0xFFDFA03C
GFSX(1604336871 = 0x5FA03CE7, 30, 9) = -1060834 = 0xFFEFD01E
GFSX(1604336871 = 0x5FA03CE7, 30, 10) = -530417 = 0xFFF7E80F
GFSX(1604336871 = 0x5FA03CE7, 30, 11) = -265209 = 0xFFFBF407
GFSX(1604336871 = 0x5FA03CE7, 30, 12) = -132605 = 0xFFFDFA03
GFSX(1604336871 = 0x5FA03CE7, 30, 13) = -66303 = 0xFFFEFD01
GFSX(1604336871 = 0x5FA03CE7, 30, 14) = -33152 = 0xFFFF7E80
GFSX(1604336871 = 0x5FA03CE7, 30, 15) = -16576 = 0xFFFFBF40
GFSX(1604336871 = 0x5FA03CE7, 30, 16) = -8288 = 0xFFFFDFA0
GFSX(1604336871 = 0x5FA03CE7, 30, 17) = -4144 = 0xFFFFEFD0
GFSX(1604336871 = 0x5FA03CE7, 30, 18) = -2072 = 0xFFFFF7E8
GFSX(1604336871 = 0x5FA03CE7, 30, 19) = -1036 = 0xFFFFFBF4
GFSX(1604336871 = 0x5FA03CE7, 30, 20) = -518 = 0xFFFFFDFA
GFSX(1604336871 = 0x5FA03CE7, 30, 21) = -259 = 0xFFFFFEFD
GFSX(1604336871 = 0x5FA03CE7, 30, 22) = -130 = 0xFFFFFF7E
GFSX(1604336871 = 0x5FA03CE7, 30, 23) = -65 = 0xFFFFFFBF
GFSX(1604336871 = 0x5FA03CE7, 30, 24) = -33 = 0xFFFFFFDF
GFSX(1604336871 = 0x5FA03CE7, 30, 25) = -17 = 0xFFFFFFEF
GFSX(1604336871 = 0x5FA03CE7, 30, 26) = -9 = 0xFFFFFFF7
GFSX(1604336871 = 0x5FA03CE7, 30, 27) = -5 = 0xFFFFFFFB
GFSX(1604336871 = 0x5FA03CE7, 30, 28) = -3 = 0xFFFFFFFD
GFSX(1604336871 = 0x5FA03CE7, 30, 29) = -2 = 0xFFFFFFFE