Битовая позиция числа во время компиляции

Я реализую математику с фиксированной точкой во встроенной системе, используя C.

Для удобства чтения я указываю знаменатель как степень числа 2:

#define Fixed_Point_Base 4096U

Однако, когда я конвертирую в математику с фиксированной точкой и обратно, мне нужно количество сдвига:

#define Fixed_Point_Bit_Position 12U

Чтобы упростить обслуживание и сделать код более надежным, я хотел бы иметь #define для битовой позиции (количество сдвигов) с точки зрения числа Fixed_Point_Base:

#define Fixed_Point_Bit_Position(x) {/*...*/}

Единственный известный мне метод включает логарифмы и деление, и я действительно не хочу использовать логарифмы или деление во встроенной системе:

bit count = ln(4096) / ln(2)

Я ищу макрос препроцессора или решение времени компиляции, которое возвращает битовую позицию степени 2.

Мой веб-поиск вернул примеры в коде, но не как решение времени компиляции/препроцессора.

К вашему сведению, я использую IAR Embedded Workbench с процессором ARM7TDMI.
Изменить 1: я использую рекомендации MISRA C 2004 с инструментами Parasoft Static Analysis и Coverity Static Analysis. Ответы должны соответствовать этим ограничениям.


person Thomas Matthews    schedule 27.02.2014    source источник
comment
Наоборот (определить Fixed_Point_Bit_Position, использовать Fixed_Point_Base(x) для получения знаменателя) было бы тривиально. Вы не можете сделать это?   -  person    schedule 27.02.2014
comment
Это не так читабельно, Fixed_Point_Base(12) не так читабельно, как 4096U.   -  person Thomas Matthews    schedule 27.02.2014


Ответы (3)


Ваш вопрос очень связан с моим старым вопросом:

Есть ли любой способ вычислить ширину целочисленного типа во время компиляции?

для которого принятый ответ решает вашу проблему:

https://stackoverflow.com/a/4589384/379897

В частности, используйте:

#define Fixed_Point_Bit_Position(x) IMAX_BITS((x)-1)

где IMAX_BITS — один из макросов из этого ответа.

person R.. GitHub STOP HELPING ICE    schedule 27.02.2014

Вы можете сделать обратное тому, что вы делаете сейчас, определив битовую точность и определив Fixed_Point_Base оттуда следующим образом:

#define PRECISIONS_IN_BITS ( 12 )
#define FIXED_POINT_BASE   ( 1 << PRECISION_IN_BITS )

Таким образом, вы можете сохранить только один номер.

person Paul Buckley    schedule 27.02.2014
comment
Хороший ответ, однако мой компилятор и инструменты статического анализа требуют проверки выражения (1 << PRECISION_IN_BITS), чтобы убедиться, что выражение не превышает количество битов в слове. Вот почему мы используем десятичные числа вместо выражения сдвига. - person Thomas Matthews; 27.02.2014
comment
Но литерал 1 имеет тип int, и он гарантированно будет не менее 16 бит, так что время компиляции гарантированно не переполнится. Я не понимаю, почему статический анализ может жаловаться — это совершенно обычная идиома. Однако я бы предложил ((unsigned)(1u << PRECISION_IN_BITS)) и определил PRECISION_IN_BITS как 12u. - person Clifford; 27.02.2014

Для этого работает грубая сила!

Простое (ну, «простое») решение, которое создает константное выражение уровня C (может использоваться для констант времени компиляции, таких как размеры массива):

#define Fixed_Point_Base 4096U

#define FPB_BITSET(X, K) (((Fixed_Point_Base >> (X) & 1) == 1) ? (X) : (K))
#define MAX_FP_BIT_32 FPB_BITSET(31, FPB_BITSET(30, FPB_BITSET(29, FPB_BITSET(28, FPB_BITSET(27, FPB_BITSET(26, FPB_BITSET(25, FPB_BITSET(24, \
                      FPB_BITSET(23, FPB_BITSET(22, FPB_BITSET(21, FPB_BITSET(20, FPB_BITSET(19, FPB_BITSET(18, FPB_BITSET(17, FPB_BITSET(16, \
                      FPB_BITSET(15, FPB_BITSET(14, FPB_BITSET(13, FPB_BITSET(12, FPB_BITSET(11, FPB_BITSET(10, FPB_BITSET(9, FPB_BITSET(8, \
                      FPB_BITSET(7, FPB_BITSET(6, FPB_BITSET(5, FPB_BITSET(4, FPB_BITSET(3, FPB_BITSET(2, FPB_BITSET(1, FPB_BITSET(0, -1 \
                      ))))))))))))))))))))))))))))))))
const unsigned int Fixed_Point_Bit_Position = MAX_FP_BIT_32;

Ограничено до 32-битного ради моего пальца вставки: расширить это тривиально. Казалось бы, малоизвестный факт, что тернарный оператор является константным выражением.

Версия только для препроцессора (если вам нужно токен-вставить результат или что-то в этом роде):

#define FPB_BITSET(X) (((Fixed_Point_Base >> (X) & 1) == 1) * (X))

#if FPB_BITSET(31)
#  define Fixed_Point_Bit_Position 31
#elif FPB_BITSET(30)
#  define Fixed_Point_Bit_Position 30
#elif FPB_BITSET(29)
#  define Fixed_Point_Bit_Position 29
#elif //etc...
person Leushenko    schedule 01.05.2014