Редактировать: В исходном вопросе была неправильная формула, и испробованный алгоритм делал что-то совершенно отличное от того, что предполагалось. Прошу прощения и решил переписать вопрос, чтобы устранить всю путаницу.
Мне нужно вычислить во время компиляции (результат будет использоваться как нетиповой параметр шаблона) минимальное количество битов, необходимое для хранения n
разных состояний:
constexpr unsigned bitsNeeded(unsigned n);
или через шаблон
Результаты должны быть:
+-----------+--------+
| number of | bits |
| states | needed |
+-----------+--------+
| 0 | 0 | * or not defined
| | |
| 1 | 0 |
| | |
| 2 | 1 |
| | |
| 3 | 2 |
| 4 | 2 |
| | |
| 5 | 3 |
| 6 | 3 |
| 7 | 3 |
| 8 | 3 |
| | |
| 9 | 4 |
| 10 | 4 |
| .. | .. |
| 16 | 4 |
| | |
| 17 | 5 |
| 18 | 5 |
| .. | .. |
+-----------+--------+
Исходный (как-то исправленный) вариант для справки:
Мне нужно вычислить во время компиляции (результат будет использоваться как параметр шаблона, не являющийся типом) минимальное количество битов, необходимое для хранения n
различных состояний, т. е. целой части (округлено вниз) округление двоичного логарифма в большую сторону:
constexpr unsigned ceilLog2(unsigned n);
Вот что я придумал (совершенно неправильно):
constexpr unsigned intLog2(unsigned num_states_) {
return
num_states_ == 1 ?
1 :
(
intLog2(num_states_ - 1) * intLog2(num_states_ - 1) == num_states_ - 1 ?
intLog2(num_states_ - 1) + 1 :
intLog2(num_states_ - 1)
);
}
Это дает правильный результат (для num_states_ != 0
), но рекурсия вырывается экспоненциально, и она практически непригодна для любых входных данных, превышающих 10 (использование памяти во время компиляции превышает 2 ГБ , ОС зависает и компилятор падает).
Как я могу вычислить это во время компиляции на практике?
intLog2Runtime(256) = 16
,intLog2Runtime(1024) = 32
. - person DanielKO   schedule 21.05.2014