Написание функции: короткие GetBits(короткие данные, int p, int n)
Я пишу функцию short getBits(короткие данные, int p, int n)
Я пытался:
public static short getBits(short data, int p, int n) {
short bitmask = (short) ((~0 << (16 -n)) >>> p);
short returnVal = (short) ((bitmask & data) >>> (16 - n));
return returnVal;
}
Это работает для getBits( (short) 0x7000, 0, 4), но если я заменю 7 на 8, я получу отрицательное значение.
2 ответа
Есть несколько вещей, которые нужно помнить о типах данных Java, чтобы заставить это работать.
Я предполагаю, что вы используете переменные типа int из-за отсутствия явных приведений в выражении. Если вы используете тип int для своих переменных: data start_pos и length; вы должны использовать 32 вместо 16, так как int являются 32-битными значениями.
Также, если вы собираетесь использовать целочисленные примитивные типы, такие как int, short или byte, помните, что эти примитивные типы являются дополнением к двум, которые расширены до знака, что означает, что если вы сделаете правильный сдвиг на отрицательных числах, таких как ~0 (оценивается как -1) единицы будут добавлены к биту более высокого порядка (знаковый бит) вместо нулей.
Например:
1111 1111 1111 1111 1111 1111 1111 1000
>>1
1111 1111 1111 1111 1111 1111 1111 1100
Теперь вернемся к вашей проблеме. Общая идея заключается в том, чтобы иметь возможность сделать:
data & mask
Теперь генерировать маску немного сложно для подписанных типов данных. Было бы целесообразно создать маску, используя:
(~0 << (32 - length) >> (32 - length - start_pos))
Но это не сработает, конечно, из-за расширения знака.
Я бы предложил, чтобы вместо использования сдвига вправо >>, использовался оператор rotate >>>, чтобы вместо добавляемых к биту более высокого порядка, оператор rotate добавлял бит более низкого порядка.
Например:
1111 1111 1111 1111 1111 1111 1111 1000
>>>1
0111 1111 1111 1111 1111 1111 1111 1100
так...
mask = (~0 << 32-length >>> 32-length-start_pos)
И ваш окончательный ответ будет выглядеть примерно так:
(data & (~0 << 32-length >>> 32-length-start_pos)) >>> start_pos
Внешняя операция поворота перемещает ваши замаскированные данные в младшие биты.
Не уверен, почему вам нужно использовать короткие. Вот решение, использующее долго.
public static long getBits(long data, int p, int n) {
assert p >= 0 && p < 64;
assert n >= 0 && n < 64;
return (data >> p) & ((1 << n) - 1);
}