Java: Как создать метод для извлечения битов разбиения целого числа из байтового массива с помощью маски - PullRequest
1 голос
/ 05 июля 2010

Работая над декодированием некоторых стандартов потокового видео, я заметил много случаев, когда биты целочисленного значения представлены в любых значениях из 2-6 байтов, но разделены зарезервированными битами, как показано ниже:

// Specification (16 bits)
// -----------------------
// Reserved         1  bit
// Value A [6-7]    2  bit
// Reserved         2  bit
// Value A [4-5]    2  bit
// Reserved         3  bit
// Value A [0-3]    4  bit
// Reserved         2  bit

Например, значение 185 (10111001 или 0xB9) будет храниться в двухбайтовом массиве следующим образом:

01000110 00100100

Я знаю, что это чокнутый, но эти парнизакодировали свой поток данных.Его можно извлечь, используя следующие битовые операции

int w = 0;
w |= (0x60 & data[0]) >>> 5;  // extract the first 2 bits shifted to the front
w <<= 2;                      // bump them up 2 bits for the next section
w |= (0x06 & data[0]) >>> 1;  // extract the next 2 bits shifted to the front
w <<= 4;                      // bump them up 4 bits for the last section
w |= (0x3C & data[0]) >>> 2;  // extract the last 4 bits shifted to the front

// w now will equal 10111001 (185)

Я хотел бы создать метод, который будет принимать массив байтов неопределенной длины и Int, представляющий маску битов, которыесоставляют значение, которое мы пытаемся извлечь, исходя из предоставленной спецификации.Примерно так

public static void testMethod() {

    byte[] data = new byte[] {0x46, 0x24}; // 01000110 00100100 
    int mask = 0x663C;                     // 01100110 00111100
    int x = readIntFromMaskedBytes(data, mask);

}

public static int readIntFromMaskedBytes(byte[] data, int mask) {
    int result = 0;

    // use the mask to extract the marks bits from each
    // byte and shift them appropriately to form an int

    return result;
}

Я завершил проект, над которым работал, используя оригинальный «ручной» подход, но я не удовлетворен тем, что он настолько чист, насколько это могло быть из-за огромного количества этихвхождения и их сложность.Я хотел бы придумать более общий метод, который мог бы выполнить то же самое.

К сожалению, я все еще новичок, когда дело доходит до этой сложности сдвига битов, и я надеялся, что кто-нибудь сможет дать некоторые советы или предложения о том, как лучше всего это сделать.

Xela

Примечание. Извините за любые синтаксические ошибки в приведенном выше псевдокоде. Он предназначен только для пояснения варианта использования.

1 Ответ

1 голос
/ 05 июля 2010

На самом деле, я склонен думать, что подход с использованием встроенной маски и сдвига (если он реализован немного чище, чем ваш псевдокод) лучше, чем попытка написать метод общего назначения.Для опытного разработчика низкоуровневого битового кода чтение кода с маской и сдвигом не должно быть проблемой.Проблема с универсальным методом, который вы предлагаете, состоит в том, что он будет значительно менее эффективен ... и JIT-компилятору будет трудно оптимизировать.

Кстати, именно так я и написал бы код.

// extract and assemble xxxx from yyyy 
int w = ((0x003C & data[0]) >> 2) | 
        ((0x0600 & data[0]) >> 6) | 
        ((0x6000 & data[0]) >> 7);

РЕДАКТИРОВАТЬ

Я все же хотел бы понять, как такой общий подход может быть закодирован, как учебное упражнение.

Примерно так:

public static int readIntFromMaskedBytes(int data, int mask) {
    int result = 0;
    int shift = 0;
    while (mask != 0) {
        if (mask & 1) {
            result |= (data & 1) << shift++;
        }
        data >>>= 1;
        mask >>>= 1;
    }
}

Как видите, для ответа вам потребуется до 32 циклов цикла.Для вашего примера я бы сказал, что этот подход примерно в 10 раз медленнее, чем оригинальная версия.

...