Написание функции: короткие 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);
}
Другие вопросы по тегам