Установите дробную часть поплавка, используя 6 бит - PullRequest
0 голосов
/ 31 января 2012

Я распаковываю некоторые данные из двойных слов.

unsigned char * current_word = [address of most significant byte]

Мои первые 14 MSB являются целочисленными значениями.Я планирую извлечь их, используя побитовое И с 0xFFFC.

int value = (int)( (uint_16)current_word & 0xFFFC );

Мои следующие 6 битов являются дробным значением.Здесь я застрял на эффективной реализации.Я мог бы извлечь один бит за раз и построить дробь 1/2 * бит + 1/4 + бит + 1/8 * бит и т. Д., Но это не эффективно.

float fractional = ?

Последний12 LSB - это другое значение типа int, которое, я чувствую, я могу вывести, используя снова и снова.

int other_value = (int) ( (uint_16)current_word[2] & 0x0FFF );    

Эта операция будет выполнена с 16348 двойными словами и должна быть завершена в течение 0,05 мс, чтобы работать как минимум на 20 Гц.

Я очень плохо знаком с битовыми операциями, но я рад учиться.Чтение материалов и / или примеров будет с благодарностью!

Редактировать: я написал ИЛИ, когда имел в виду И

Ответы [ 4 ]

2 голосов
/ 31 января 2012

Поскольку вы начинаете с [address of most significant byte] и используете оттуда увеличивающиеся адреса, ваши данные, по-видимому, располагаются в байтовом порядке с прямым порядком байтов.Поэтому указатели приведения не будут работать почти на всех настольных компьютерах, которые используют порядок байтов Little-Endian.

Следующий код будет работать независимо от собственного порядка байтов:

int value = (current_word[0] << 6) | (current_word[1] >> 2);
double fractional = (current_word[1] & 0x03) / 4.0 + (current_word[2] & 0xF0) / 1024.0;
int other_value = (current_word[2] & 0x0F) << 8 | current_word[3];
2 голосов
/ 31 января 2012

Во-первых, вам будет эффективнее сразу ввести двойное слово в int и маскировать / сдвигать оттуда.

Получить дробную часть легко: замаскируйте и сдвиньте, чтобы получить целое число, а затем разделите на число с плавающей точкой, чтобы масштабировать результат.

float fractional = ((current_int >> 12) & 0x3f) / 64.;
0 голосов
/ 31 января 2012

Если вы читаете ваши данные как беззнаковый символ *, вы не сможете получить более 8-битных данных за раз, и ваш пример должен измениться.Если ваш адрес выровнен или ваша платформа позволяет, вы должны считать ваши данные как int *, но тогда возникает вопрос о том, как хранятся ваши данные.Хранится ли оно 20 бит на целое число с 12 битами другой информации, или это 20-битный поток, в котором вам нужно отслеживать свой указатель битов.Если второе, это еще сложнее, чем вы думаете.Я опубликую дальше, как только почувствую, как ваши данные размещаются в оперативной памяти.

0 голосов
/ 31 января 2012

Есть 5 видов сменных инструкций:

  1. Сдвиг вправо со знаком расширения: он будет копировать ваш текущий левый бит как новый бит в крайний левый после смещения всех бит вправо. Самый правый сбрасывается.
  2. Сдвиг вправо с расширением нуля: аналогично (1), но предположим, что ваш новый самый левый бит всегда равен нулю.
  3. Сдвиг влево: заменить вправо в (1) и (2) на влево , влево на вправо и прочитать (2 ) снова.
  4. Бросок вправо: сдвиньте биты вправо, вместо того, чтобы бросить вправо, он станет самым левым.
  5. Свернуть влево: заменить вправо дюйм (4) на влево , влево на вправо и снова прочитать (4).

Вы можете менять столько раз, сколько хотите. В C больше, чем количество битов в вашем типе данных, не определено. Типы без знака и со знаком меняются по-разному, хотя синтаксис одинаков.

...