What is the most simple/elegant way to calculate the length of a number written as text?

StackOverflow https://stackoverflow.com/questions/1260244

  •  12-09-2019
  •  | 
  •  

Question

Given the maximum possible value, how to simply express the space needed to write such number in decimal form as text ?

The real task: logging process ids (pid_t) with fixed length, using gcc on Linux. It'd be good to have a compile time expression to be used in the std::setw() iomanipulator.

I have found that linux/threads.h header contains a PID_MAX value with the maximum pid allocated to a process. So having

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

the LENGTH(PID_MAX) would be a compile time expression, but unfortunatelly this number is defined in hexa:

#define PID_MAX 0x8000

My current best solution is a bit oddish

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

But this is calculated runtime and uses functions from math.h

Was it helpful?

Solution

You could do it with a little template meta programming:

//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 }; };

This should work for anything now. For example:

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

This is all handled at compile time.

Edit: I added another layer to handle the case when the number passed in is zero.

OTHER TIPS

I don't think you can get it exactly without invoking logarithms, but you can get an upper bound:

CHAR_BIT * sizeof(PID_MAX) will give you an upper bound on the number of bits needed to represent PID_MAX. You can then precompute log(10) = 3.32 and round down to 3. Forget about floor, because integer division will truncate like that anyhow. So

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

Should give you a compile-time computable upper bound on the number of characters needed to display t in decimal.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top