Вход Расширение int в C
Так что у меня возникли проблемы с получением поля типа int и последующим подписанием его расширения. У меня есть метод, который получает поле Int.
getField(int value, int hi, int lo);
Значение - это int, из которого я беру поле, а hi и lo - размер поля.
Так что я могу вызвать этот метод getField внутри getFieldSignExtended(int value, int hi, int lo), но как мне пойти на знак расширения его?
например value = 7, hi = 1, lo = 0
getField(7, 1, 0);
возвращает 3, потому что 7 в двоичном виде - это 111, а hi и lo принимают поле от 0 до 1.
При возвращении 3 из getField я получаю, что значение равно 0x0003.
То, что у меня есть, работает с позитивами, но сильно портит негативы. И когда я говорю "испортить", я имею в виду, что это не работает вообще. Так что, если я попытаюсь использовать его на -1, он будет показан как большой int вместо отрицательного.
Спасибо за любую помощь!:]
Изменить: Извините, я перепутал себя и некоторых из вас с противоречивым утверждением:P. Исправлена.
2 ответа
Здесь очень много чтения между строк. Однако если getField(7, 1, 0)
возвращает 3 и вам нужно getFieldSignExtended(15, 2, 0)
возвращать -3
а также getFieldSignExtended(3, 2, 0)
возвращать +3
, тогда это может быть то, что вы после.
Концепция заключается в том, что вы рассматриваете n-битное поле из битов hi:lo исходного значения как число дополнения до 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) слишком велик и поведение не определено. Вы также сталкиваетесь с поведением, определяемым реализацией правого смещения отрицательного числа. Можно было бы решить эти проблемы, используя целочисленный аргумент без знака и не &
операция, если hi - lo + 1 == INT_BITS
, Решение проблем оставлено в качестве упражнения для читателя.
Назначение bits
сдвигает значение вправо и маскирует его с правильным количеством битов. (1 << (hi - lo + 1)) - 1
сдвиг 1 влево на единицу больше, чем число битов в поле, затем вычитает единицу, чтобы сгенерировать строку двоичных единиц для каждой позиции бита в поле. Например, для hi = 2, lo = 0, это сдвиг 1 в 3 места, дает двоичный 1000; вычитание 1 дает 0111, поэтому выбираются правильные 3 бита. Так, bits
содержит соответствующий набор битов для n-битного целого числа.
if
test проверяет, установлен ли старший значащий бит n-битного целого числа. Если бит знака не установлен, мы просто возвращаем значение bits
, Если бит знака установлен, то у нас есть сложный расчет, который был (очень) неверен в первом наброске этого ответа. Предположим, что у нас есть поле 3 бита = 101. Как 3-битное число дополнения 2, которое представляет -3. Нам нужно расширить это влево со всеми 1, чтобы сгенерировать полный размер -1
, Значение ~0
все биты 1; когда это сдвинуто влево hi - lo
биты, он оставляет серию нулей для незнаковых битов значения. Это также будет работать, если вы переместитесь влево на hi - lo + 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
Есть несколько подходов, которые вы можете использовать. Если вы только начинаете, вы можете просто арифметически рассчитать количество битов в поле. Так, например:
if (value %2 >= 1)
{
// you know that the value has a `1` as the lest significant digit.
// if that's one of the digits you're looking for, you can do something like count++ here
}
else
{
// least significant digit is a '0'
}
а потом
if (value % 4 >=2)
{
// you know that the second least significant digit is `1`
// etc.
}
Если вы сделаете это таким образом, вы, вероятно, захотите объединить их в какой-то цикл.
Теперь, лучший способ сделать это - использовать побитовый андинг, например так:
if (value & 8 != 0)
// here you know that the fourth least significant digit (the one representing 8) is 1.
// do a Google search on bitwise anding to get more information.