Какой самый простой / элегантный способ рассчитать длину числа, записанного в виде текста? - PullRequest
3 голосов
/ 11 августа 2009

Учитывая максимально возможное значение, как просто выразить пространство, необходимое для записи такого числа в десятичной форме, как текст?

Реальная задача: регистрация идентификаторов процесса (pid_t) фиксированной длины с использованием gcc в Linux. Было бы хорошо иметь выражение времени компиляции для использования в std::setw() iomanipulator.

Я обнаружил, что заголовок linux / threads.h содержит значение PID_MAX с максимальным значением pid, выделенным для процесса. Итак, имея

#define LENGTH(t) sizeof(#t)-1

LENGTH(PID_MAX) будет выражением времени компиляции, но, к сожалению, это число определено в гекса:

#define PID_MAX 0x8000

Мое настоящее лучшее решение немного странно

static_cast<int>( ::floor( ::log(PID_MAX)/::log(10) + 1 ) );

Но это рассчитанная среда выполнения и использует функции из math.h

Ответы [ 2 ]

14 голосов
/ 11 августа 2009

Вы можете сделать это с небольшим шаблоном метапрограммирования:

//NunLength_interal does the actual calculation. 
template <unsigned num>
struct NumLength_internal
{ enum { value = 1 + NumLength_internal<num/10>::value }; };

template <>
struct NumLength_internal<0>
{ enum { value = 0 }; };

//NumLength is a wrapper to handle zero. For zero we want to return
//a length of one as a special case.
template <unsigned num>
struct NumLength
{ enum { value = NumLength_internal<num>::value };};

template <>
struct NumLength<0>
{ enum { value = 1 }; };

Теперь это должно работать для всего. Например:

cout << NumLength<0>::value      << endl; // writes: 1
cout << NumLength<5>::value      << endl; // writes: 1
cout << NumLength<10>::value     << endl; // writes: 2
cout << NumLength<123>::value    << endl; // writes: 3
cout << NumLength<0x8000>::value << endl; // writes: 5

Все это обрабатывается во время компиляции.

Редактировать: я добавил еще один слой для обработки случая, когда переданное число равно нулю.

2 голосов
/ 11 августа 2009

Я не думаю, что вы можете получить его точно без вызова логарифмов, но вы можете получить верхнюю границу:

CHAR_BIT * sizeof(PID_MAX) даст вам верхнюю границу количества битов, необходимых для представления PID_MAX. Затем вы можете предварительно вычислить log (10) = 3,32 и округлить до 3. Забудьте о поле, так как целочисленное деление будет так или иначе сокращаться. Так

#define LENGTH(t) (((CHAR_BIT * sizeof(t)) / 3) + 1)

Должен дать вам вычисляемую верхнюю границу времени компиляции для количества символов, необходимых для отображения t в десятичном виде.

...