Перейти к содержанию
    

Как с помощью #define определить позицию бита

Хочу, например, для числа 0x0100 найти позицию бита, который в 1, то есть, получить число 8.

В-принципе, этот бит будет один (младший бит в группе), но если их несколько, нужно определить позицию младшего.

Как это сделать макрофункцией?

Тогда я смогу задавать сдвиг "магических чисел" в регистре по имени группы битов в этом регистре.

P.S. Обратная функция легко делается сдвигом 1 << NUM.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для одного бита: log2(0x0100)=8

Не скажу за все препроцессоры, но AVRASM2 понимает такое LOG2(0x0100)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хочу, например, для числа 0x0100 найти позицию бита, который в 1, то есть, получить число 8.

В-принципе, этот бит будет один (младший бит в группе), но если их несколько, нужно определить позицию младшего.

Как это сделать макрофункцией?

Что-то в голову ничего, кроме вариаций на тему условного rvalue, не приходит.

P.S. Обратная функция легко делается сдвигом 1 << NUM.

Вот нифига. AFAIR, стандарт не определяет используемый тип сдвига, арифметический или круговой. Так что результат, скорее, неопределенный, если не маскировать специально.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для этих целей есть Find First Set (ffs).

 

Или вот ещё -> "Number of leading zeros algorithms"

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот нифига. AFAIR, стандарт не определяет используемый тип сдвига, арифметический или круговой. Так что результат, скорее, неопределенный, если не маскировать специально.

Шутки шутите?

 

Э, да ведь можно с помощью #if перебрать все варианты!

#if   (VAL == 0x8000)
#define NUM 15
#elif (VAL == 0x4000)
#define NUM 14
...

 

А еще проще через лестницу тернарных операторов. :yeah:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А еще проще через лестницу тернарных операторов. :yeah:

о, а это хорошая идея.

Есть такой алгоритм, приличный С-компилятор должен это вычислить во время компиляции

//calc position of rightmost nonzero bit
#define m2b(x) (\
(((x & -x) & 0x0000FFFF) ? 0 : 16)+\
(((x & -x) & 0x00FF00FF) ? 0 : 8)+\
(((x & -x) & 0x0F0F0F0F) ? 0 : 4)+\
(((x & -x) & 0x33333333) ? 0 : 2)+\
(((x & -x) & 0x55555555) ? 0 : 1)+\
((x & -x) ? 0 : 1))

Плюс в том, что это макроопределение можно использовать прямо внутри выражения.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Правильно ли я понял: допустим у вас есть

#define MASK 0x000FF0

И вы хотите из этого MASK получить 4 чтобы сделать Reg = N << 4;

 

Можно сделать (я делаю) так:

Reg = N * (MASK & -MASK);

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Правильно ли я понял:...

Да, правильно. Спасибо! Супер.

И ведь видел когда-то... :rolleyes:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если описать конкретно младший бит в группе, то можно пользоваться тем же умножением, что я и сам делаю ( :lol: показывал в другой теме). Только сомножители местами переставлены. :rolleyes:

 

Reg |= N * MASK_0;

 

Компилятор все эти умножения на сдвиги заменяет, естественно.

 

Есть такой алгоритм, приличный С-компилятор должен это вычислить во время компиляции

...

Плюс в том, что это макроопределение можно использовать прямо внутри выражения.

Да, спасибо, макро работает, компилируется в число.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Случайно нагуглил тему. Может пригодится кому-нибудь: __builtin_ctz() и его друзья.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 8/28/2014 at 11:26 PM, Сергей Борщ said:

Можно сделать (я делаю) так:

Reg = N * (MASK & -MASK);

Тут ошибка?
У нас такое выражение используется для установки полей по маске:
 

(REG & ~MASK) | (N * (MASK & ~(MASK << 1)) & MASK)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 минут назад, Lagman сказал:

Тут ошибка?

У меня работает...

MASK = 0xF0, 5 * (0xF0 & 0xFFFFFF10) = 5 * 0x10 = 0x50, что и требовалось.

10 минут назад, Lagman сказал:

У нас такое выражение используется для установки полей по маске:

У вас другое выражение - в нем инверсия, в моем отрицательное число.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я ни в каких либах не видел такого извращения. Везде явно задают маски и позиции полей. (например через имена вида х_Msk, x_Pos)
Сделать конешн можно, но после препроцессинга оно развернется в дикую дичъ. под стать плюсовым шаблонам. Имхо, это плохой путь.

Или понадобилось нечто особенное?

 

Я тэту задачу решал такими макро:
 

// @brief is low n-bits clear
#define IS_CTZn(x, n)   ( ((x) & ((1<<(n))-1)) == 0 )

#define CTZ_1(n) ( IS_CTZn((n), 1) ? 1 : 0)
#define CTZ_2(n) ( IS_CTZn((n), 2) ? (2 + CTZ_1((n)>>2)) : CTZ_1(n))
#define CTZ_4(n) ( IS_CTZn((n), 4) ? (4 + CTZ_2((n)>>4)) : CTZ_2(n))
#define CTZ_8(n) ( IS_CTZn((n), 8) ? (8 + CTZ_4((n)>>8)) : CTZ_4(n))
#define CTZ(n)   ( IS_CTZn((n), 16) ? (16 + CTZ_8((n)>>16)) : CTZ_8(n) )

Мне оно зашло лучше чем использование (x & -x), ибо позволяет работать с unsigned без сюрпризов

Изменено пользователем AlexRayne

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 28.08.2014 в 19:14, SSerge сказал:
((x & -x) ? 0 : 1))

Плюс в том, что это макроопределение можно использовать прямо внутри выражения.

тут нужно еще Х скобками обернуть

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, AlexRayne сказал:

Мне оно зашло лучше чем использование (x & -x), ибо позволяет работать с unsigned без сюрпризов

Аналог -x очень прост: ~(x)+1u

Если надо без знаковости...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...