Efficient way to determine number of digits in an integer
Asked Answered
C

33

173

What is a very efficient way of determining how many digits there are in an integer in C++?

Clustered answered 28/9, 2009 at 23:20 Comment(9)
In what base? 2? 10?Filomena
I would like to do it in base 10Clustered
I once asked a related question: How can you get the first digit in an int? Many of the same methodologies as below were used in people's answers. Here's the link in case it's relevant to your task [stackoverflow.com/questions/701322/]Sadick
Does inline assembly qualify?Scrounge
How would inline assembly help?Lute
While all these answers are in terms of base 10, it is pretty easy to change to compute the result for any desired base.Tallow
What's your measure of efficiency? Options include minimising code size, number of CPU cycles, even accuracy of result. But each involves doing things differently. And, do you mean decimal digit, octal digit, hexadecimal digit, or something else?Mogul
Math.log10(value)+1 is the most efficient way on any measure.Friend
Also: How many digits does 0 have?Abscind
L
125

Well, the most efficient way, presuming you know the size of the integer, would be a lookup. Should be faster than the much shorter logarithm based approach. If you don't care about counting the '-', remove the + 1.

#include <climits>

// generic solution
template <class T>
int numDigits(T number)
{
    int digits = 0;
    if (number < 0) digits = 1; // remove this line if '-' counts as a digit
    while (number) {
        number /= 10;
        digits++;
    }
    return digits;
}

// partial specialization optimization for 64-bit numbers
template <>
int numDigits(int64_t x) {
    if (x == INT64_MIN) return 19 + 1;
    if (x < 0) return digits(-x) + 1;

    if (x >= 10000000000) {
        if (x >= 100000000000000) {
            if (x >= 10000000000000000) {
                if (x >= 100000000000000000) {
                    if (x >= 1000000000000000000)
                        return 19;
                    return 18;
                }
                return 17;
            }
            if (x >= 1000000000000000)
                return 16;
            return 15;
        } 
        if (x >= 1000000000000) {
            if (x >= 10000000000000)
                return 14;
            return 13;
        }
        if (x >= 100000000000)
            return 12;
        return 11;
    }
    if (x >= 100000) {
        if (x >= 10000000) {
            if (x >= 100000000) {
                if (x >= 1000000000)
                    return 10;
                return 9;
            }
            return 8;
        }
        if (x >= 1000000)
            return 7;
        return 6;
    }
    if (x >= 100) {
        if (x >= 1000) {
            if (x >= 10000)
                return 5;
            return 4;
        }
        return 3;
    }
    if (x >= 10)
        return 2;
    return 1;
}

// partial specialization optimization for 32-bit numbers
template<>
int numDigits(int32_t x)
{
    if (x == INT32_MIN) return 10 + 1;
    if (x < 0) return numDigits(-x) + 1;

    if (x >= 10000) {
        if (x >= 10000000) {
            if (x >= 100000000) {
                if (x >= 1000000000)
                    return 10;
                return 9;
            }
            return 8;
        }
        if (x >= 100000) {
            if (x >= 1000000)
                return 7;
            return 6;
        }
        return 5;
    }
    if (x >= 100) {
        if (x >= 1000)
            return 4;
        return 3;
    }
    if (x >= 10)
        return 2;
    return 1;
}

// partial-specialization optimization for 8-bit numbers
template <>
int numDigits(char n)
{
    // if you have the time, replace this with a static initialization to avoid
    // the initial overhead & unnecessary branch
    static char x[256] = {0};
    if (x[0] == 0) {
        for (char c = 1; c != 0; c++)
            x[c] = numDigits((int32_t)c);
        x[0] = 1;
    }
    return x[n];
}
Lute answered 28/9, 2009 at 23:35 Comment(14)
Probably faster than my answer, well done. For added efficiency, if you know that your input numbers will be mostly small ones (I'm guessing less than 100,000), then reverse the tests: if (x < 10) return 1; if (x < 100) return 2; etc., so that the function will do less tests and exit faster.Unsteady
Or perhaps reorder and nest the if statements, to do a binary search instead of a linear search.Blomquist
That's not a good idea. What happens when the architecture expands to 256 bit integers. You need to remember to come back and modify this code. In real life that will not happen and sice this is probably going to be used to build a buffer of the correct size you are now opening yourself to all sorts of buffer over run problems on larger architectres.Crease
Hence the original disclaimer that it's for 32-bit. I've added the template solution that does it generically too.Lute
I'm not sure if it makes sense in the general solution to do the loop until you are < MAX_INT & then fall through to the specialized case. That makes the solution uglier - the speed will be very architecture specific.Lute
In the generic solution you should add if (number == 0) { return 1; } to be consistent with the specializations.Unsteady
assuming a uniform distribution of numbers, the reverse linear search ( starting from max digits to 1 ) may be faster on average than the binary search as there are quite more numbers with N digits than with N-1 digits graphics.stanford.edu/~seander/…Poree
I wouldn't worry very hard about 256 or 128 bit integers. Unless you need to count the number of electrons in the Universe (10^78 last time I did it), 64 bits will do pretty well. 32 bit machines lasted ~~15 years. I'd guess 64 bit machines will last a lot longer. For larger number, multiprecision arithmetic will be fine, and I doubt if efficiency of computing digit count will matter.Tallow
gcc has __int128_t, useful to hold the result of multiplying two 64 bit integers (amd64 has 64bit x 64bit = 128 bit in hardware). You don't have to count real things to have big numbers; crypto routinely uses large integers.Dissolve
That algorithm assumes the values are equally distributed based on the number of digits, which is almost never the case. See fa's comment. BTW, those aren't partial specializations; they're complete explicit specializations. :-)Aromaticity
on 32 bit systems and on win64, int and long both have 32 bits, so for a production quality implementation, it would need to be implemented differently.Disappoint
In the generic solution, to return the correct length when (number == 0) change "if (number < 0) digits = 1;" to "if (number <= 0) digits = 1;". Or change "while" loop to "do...while" loop so "digits" will be incremented once when (number == 0).Alongshore
Will this works with float and double too? FLOAT_MAX has a mantisse of 64.Lashio
This answer is broken. The edits over time have mangled it beyond recognition. It hasn't compiled for almost three years now because digits() should be numDigits(), and it returns 0 digits for the number 0. I'd stay clear of it.Olden
R
86

The simplest way is to do:

unsigned GetNumberOfDigits (unsigned i)
{
    return i > 0 ? (int) log10 ((double) i) + 1 : 1;
}

log10 is defined in <cmath> or <math.h>. You'd need to profile this to see if it's faster than any of the others posted here. I'm not sure how robust this is with regards to float point precision. Also, the argument is unsigned as negative values and log don't really mix.

Ravish answered 29/9, 2009 at 0:0 Comment(5)
For 32 bit ints and 56 bit floats, this probably works. If the input is a long (64 bits), the 56 bits of double-precision log may cause this to produce the wrong answer in cases of values near large values of 10^n. Expect trouble above 2^50.Tallow
There's also the question of how accurate the log functions are. I haven't checked how accurate they are in modern libraries, and wouldn't be comfortable blindly trusting them to be good to one part in a billion.Metallography
@DavidThornley: log or other math functions are perfectly precise unless specified on the compiler command line. some will be converted to x86 intrinsics at compile time. some don't exist and will expand into formulas of existing intrinsics. for example if using -fpfast you could see usage of SSE instrinsics rather than x87, which yields less guarantee on the precision IIRC. but by default no problem.Doornail
@DavidThornley: It's more than precision. The question is whether it is guaranteed or not that log10 (10^k) ≥ k for all relevant k. That is is it guaranteed that any inevitable rounding error goes in the right direction. k + eps as a result works, k - eps doesn't. And "Perfectly precise" is naïve.Nanny
The test i > 0 could be optimized to i > 9Tomato
U
79

Perhaps I misunderstood the question but doesn't this do it?

int NumDigits(int x)  
{  
    x = abs(x);  
    return (x < 10 ? 1 :   
        (x < 100 ? 2 :   
        (x < 1000 ? 3 :   
        (x < 10000 ? 4 :   
        (x < 100000 ? 5 :   
        (x < 1000000 ? 6 :   
        (x < 10000000 ? 7 :  
        (x < 100000000 ? 8 :  
        (x < 1000000000 ? 9 :  
        10)))))))));  
}  
Urine answered 30/9, 2009 at 14:43 Comment(5)
And I wouldn't be surprised if this solution will be the fastest.Displace
@Displace It seems like the accepted answer is ~1.7 times faster @ quick-bench so the binary tree thingy to keep the comparisons down seems to work (if the input is uniformly distributed over the whole range).Rye
@TedLyngmo Probably, x = abs(x) gives extra weight here.Displace
@Displace True. The function in the accepted answer calls itself for negative numbers and adds 1. Since the functions under test didn't do the same thing for negative numbers, I removed negative numbers and made the type std::uint_fast32_t in both functions.Rye
i like that with C++ the closer you get to literally spelling out what the machine should do, the better off you are speed wise.Chlordane
U
35
int digits = 0; while (number != 0) { number /= 10; digits++; }

Note: "0" will have 0 digits! If you need 0 to appear to have 1 digit, use:

int digits = 0; do { number /= 10; digits++; } while (number != 0);

(Thanks Kevin Fegan)

In the end, use a profiler to know which of all the answers here will be faster on your machine...

Unsteady answered 28/9, 2009 at 23:31 Comment(2)
This may or may not be faster than the unrolled loop approach I took - you'd need to profile the difference (should be negligible in the long run).Lute
Agreed, profiling is the only way to really know for sure! I updated my answer with that comment, as Ben S's ceil(log10()) answer has disappeared.Unsteady
H
15

convert to string and then use built-in functions

unsigned int i;
cout<< to_string(i).length()<<endl;
Holography answered 24/3, 2013 at 15:53 Comment(0)
H
11

Practical joke: This is the most efficient way (number of digits is calculated at compile-time):

template <unsigned long long N, size_t base=10>
struct numberlength
{
    enum { value = 1 + numberlength<N/base, base>::value };
};

template <size_t base>
struct numberlength<0, base>
{
    enum { value = 0 };
};

May be useful to determine the width required for number field in formatting, input elements etc.

Headfirst answered 29/9, 2009 at 1:32 Comment(4)
First, your solution doesn't work for 0. Secondly your solution is inapplicable to the general case of a variable. Thirdly, if you are using a constant literal, you already know how many digits it has.Lute
It works for 0 too. It also works for any base. The rest are valid points that I already outlined.Headfirst
I don't think it does actually. It fails on 0 and also fails on base 1 :) and gives divide by zero errors if the base is given as 0. It can be fixed though. Anyway I'm nitpicking over a very old post, so sorry, it's just that I think this needn't be a joke and could actually be useful.Strumpet
I provided here a C++20 version which works with 0 https://mcmap.net/q/142640/-efficient-way-to-determine-number-of-digits-in-an-integerTina
B
10

See Bit Twiddling Hacks for a much shorter version of the answer you accepted. It also has the benefit of finding the answer sooner if your input is normally distributed, by checking the big constants first. (v >= 1000000000) catches 76% of the values, so checking that first will on average be faster.

Bartel answered 29/9, 2009 at 5:58 Comment(5)
It's unclear if the bit-twiddling is actually faster. Even in the worst case, my modified approach requires 4 comparisons (might be able to take it down to 3 if I examined the partitioning further, although that looks unlikely). I seriously doubt that that is going to be beat by arithmetic operations + memory loads (although if accessed enough, those disappear into the CPU cache). Remember, in the example they give, they also hide the log base 2 as some abstract IntegerLogBase2 function (which itself is actually not cheap).Lute
Just as a follow up, yes if the numbers are normally distributed, doing the in-order check is faster. However, it has the degenerate case of being twice as slow in the worst case. The partitioned approach by number of digits instead of input space means that the behaviour does not have a degenerate case and always performs optimally. Furthermore, remember you are making the assumption that the numbers will be uniformly distributed. In fact, they are more likely to follow some distribution related to <a href="en.wikipedia.org/wiki/…> would be my guess.Lute
The bit twiddling hacks are not faster than the partition method above, but they are potentially interesting if you had a more general case like a float here.Davie
The bit twiddling hacks suggests a way to get the int log10, given the int log2. It suggests several way to get int log2, mostly involving few compare/branches. (I think you're underestimating the cost of unpredictable branches, Vitali). If you can use inline x86 asm, the BSR instruction will give you the int log2 of a value (i.e. the bit index of a the most significant set bit). It's a bit slow on K8 (10 cycle latency), but fast on Core 2 (2 or 3 cycle latency). Even on K8, may well be faster than the comparisons.Kunkel
On K10, lzcnt counts leading zeros, so it's almost the same as bsr, but an input of 0 is no longer a special case with undefined results. Latencies: BSR: 4, LZCNT: 2.Kunkel
O
8
int x = 1000;
int numberOfDigits = x ? static_cast<int>(log10(abs(x))) + 1 : 1;
Ovariectomy answered 4/7, 2018 at 0:45 Comment(2)
While this is efficient in terms of LOCs, as noted in the accepted answer use of log will probably not give the best performance.Bant
@Bant Why not? It's only a couple of FPU instructions. Miles better than all the branches and loops in other answers.Friend
T
7

A previous poster suggested a loop that divides by 10. Since multiplies on modern machines are a lot faster, I'd recommend the following code instead:

 int digits = 1, pten=10; while ( pten <= number ) { digits++; pten*=10; }
Tallow answered 29/9, 2009 at 1:5 Comment(7)
the devil is in the details - what happens with say std::numeric_limits<int>::max == number - it might have a problem terminatingConvolvulaceous
If you are worried about that case, you can add one additional IF to handle very large values.Tallow
I should observe that on x86 machines, a multiply by a constant 10 as used in this case can actually be implemented by the compiler as LEA R2,[8*R1+R1], ADD R1,R2 so it takes 2 clocks max. Multiplys by variables take tens of clocks, and divides are much worse.Tallow
the advantage with the divide approach is that you dont need to worry about negative numbers.Disappoint
When I first saw that divide loop, I thought of working up and multiplying too. On the other hand, this whole question seems to be a pathological case of premature optimization, but also a nice inquiry about something programmers "should" know.Aruabea
I benchmarked the multipication approach (with a fabs to remove the sign issue) versus the division approach. On my machine the division approach is factor 2 slower than the multiplication approach. Whether this is premature optimization or not really depends on where and how this is called.Bushy
@SpaceMoose: Factor of 2 with fabs? So you did this benchmark with floats? I'd expect the speed difference for the integer version to be relatively faster, because that hardwired multiply by 10 should be much faster than idiv.Tallow
P
5

The ppc architecture has a bit counting instruction. With that, you can determine the log base 2 of a positive integer in a single instruction. For example, 32 bit would be:

#define log_2_32_ppc(x) (31-__cntlzw(x))

If you can handle a small margin of error on large values you can convert that to log base 10 with another few instructions:

#define log_10_estimate_32_ppc(x) (9-(((__cntlzw(x)*1233)+1545)>>12))

This is platform specific and slightly inaccurate, but also involves no branches, division or conversion to floating point. All depends on what you need.

I only know the ppc instructions off hand, but other architectures should have similar instructions.

Pick answered 29/9, 2009 at 6:30 Comment(2)
This solution computes log2(15)= 4 bits and log2(9)=4 bits. But 15 and 9 require different numbers of decimal digits to print. So it doesn't work, unless you don't mind your numbers printing with too many digits sometimes. But in that case, you can always choose "10" as the answer for int.Tallow
Wow, an approximate function. Nice.Aruabea
W
4
 #include <iostream>
 #include <math.h>

 using namespace std;

 int main()
 {
     double num;
     int result;
     cout<<"Enter a number to find the number of digits,  not including decimal places: ";
     cin>>num;
     result = ((num<=1)? 1 : log10(num)+1);
     cout<<"Number of digits "<<result<<endl;
     return 0;
 }

This is probably the simplest way of solving your problem, assuming you only care about digits before the decimal and assuming anything less than 10 is just 1 digit.

Wheatworm answered 1/3, 2017 at 20:18 Comment(0)
T
4

You can use this to calculate the number of digits on compile time:

C++20 solution:

template<std::integral auto num>
constexpr int number_of_digits = num >= -9 && num <= 9 ? 1 : 1 + number_of_digits<num / 10>;

Works for negative numbers, zero and positive numbers.

Note: to make it work with C++14 change "std::integral auto" to "long long".

Note: if you want the minus sign in negative numbers to also be counted, then change -9 to 0;

Usage example:

int k = number_of_digits<101>; // k = 3

The way this works is that a number is going to be divided by 10 recursively until it becomes a single digit, in which case we finish by adding +1 to the total sum.

Tina answered 11/6, 2022 at 21:15 Comment(1)
Interesting! Will this works for float and double too? My problem is I have do count digits for float, FLOAT_MIN/MAX has a mantisse of 64! Most implantations fails in other implantations.Lashio
C
3

If faster is more efficient, this is a improvement on andrei alexandrescu's improvement. His version was already faster than the naive way (dividing by 10 at every digit). The version below is constant time and faster at least on x86-64 and ARM for all sizes, but occupies twice as much binary code, so it is not as cache-friendly.

Benchmarks for this version vs alexandrescu's version on my PR on facebook folly.

Works on unsigned, not signed.

inline uint32_t digits10(uint64_t v) {
  return  1
        + (std::uint32_t)(v>=10)
        + (std::uint32_t)(v>=100)
        + (std::uint32_t)(v>=1000)
        + (std::uint32_t)(v>=10000)
        + (std::uint32_t)(v>=100000)
        + (std::uint32_t)(v>=1000000)
        + (std::uint32_t)(v>=10000000)
        + (std::uint32_t)(v>=100000000)
        + (std::uint32_t)(v>=1000000000)
        + (std::uint32_t)(v>=10000000000ull)
        + (std::uint32_t)(v>=100000000000ull)
        + (std::uint32_t)(v>=1000000000000ull)
        + (std::uint32_t)(v>=10000000000000ull)
        + (std::uint32_t)(v>=100000000000000ull)
        + (std::uint32_t)(v>=1000000000000000ull)
        + (std::uint32_t)(v>=10000000000000000ull)
        + (std::uint32_t)(v>=100000000000000000ull)
        + (std::uint32_t)(v>=1000000000000000000ull)
        + (std::uint32_t)(v>=10000000000000000000ull);
}
Consubstantiate answered 6/6, 2019 at 21:9 Comment(0)
D
1

I like Ira Baxter's answer. Here is a template variant that handles the various sizes and deals with the maximum integer values (updated to hoist the upper bound check out of the loop):

#include <boost/integer_traits.hpp>

template<typename T> T max_decimal()
{
    T t = 1;

    for (unsigned i = boost::integer_traits<T>::digits10; i; --i)
        t *= 10;

    return t;
}

template<typename T>
unsigned digits(T v)
{
    if (v < 0) v = -v;

    if (max_decimal<T>() <= v)
        return boost::integer_traits<T>::digits10 + 1;

    unsigned digits = 1;
    T boundary = 10;

    while (boundary <= v) {
        boundary *= 10;
        ++digits;
    }

    return digits;
}

To actually get the improved performance from hoisting the additional test out of the loop, you need to specialise max_decimal() to return constants for each type on your platform. A sufficiently magic compiler could optimise the call to max_decimal() to a constant, but specialisation is better with most compilers today. As it stands, this version is probably slower because max_decimal costs more than the tests removed from the loop.

I'll leave all that as an exercise for the reader.

Dissolve answered 29/9, 2009 at 6:3 Comment(3)
You want to make the upper limit check a seperate conditional tested first so you don't check it on each loop iteration.Tallow
You don't want to put 10 into that temp t. The compiler might consider multiplying by t to be multiplying by a real variable, and use a general purpose multiply instruction. If you instead wrote "result*=10;" the compiler will surely notice the multiply by constant 10 and implement that with a few shifts and adds, which is extremely fast.Tallow
If the multiplication by t was always a multiplication by 10, then yes, the compiler could do strength reduction. However, t is not loop-invariant in this case (it is just a modification of an integer power function I had lying around). The correct optimisation is specialisation on type returning a constant. However, you are right that, in this case, the function is always raising 10 to a power, not an arbitrary integer to a power, and strength reduction gives a good win. So I made a change ... This time further changes really are left as an exercise! (Stack Overflow is a big time sink ...)Dissolve
F
1
#include <stdint.h> // uint32_t [available since C99]

/// Determine the number of digits for a 32 bit integer.
/// - Uses at most 4 comparisons.
/// - (cX) 2014 [email protected]
/// - \see http://stackoverflow.com/questions/1489830/#27669966
/**  #d == Number length vs Number of comparisons == #c
     \code
         #d | #c   #d | #c
         ---+---   ---+---
         10 | 4     5 | 4
          9 | 4     4 | 4
          8 | 3     3 | 3
          7 | 3     2 | 3
          6 | 3     1 | 3
     \endcode
*/
unsigned NumDigits32bs(uint32_t x) {
    return // Num-># Digits->[0-9] 32->bits bs->Binary Search
    ( x >= 100000u // [6-10] [1-5]
    ?   // [6-10]
        ( x >= 10000000u // [8-10] [6-7]
        ?   // [8-10]
            ( x >= 100000000u // [9-10] [8]
            ? // [9-10]
                ( x >=  1000000000u // [10] [9]
                ?   10
                :    9
                )
            : 8
            )
        :   // [6-7]
            ( x >=  1000000u // [7] [6]
            ?   7
            :   6
            )
        )
    :   // [1-5]
        ( x >= 100u // [3-5] [1-2]
        ?   // [3-5]
            ( x >= 1000u // [4-5] [3]
            ? // [4-5]
                ( x >=  10000u // [5] [4]
                ?   5
                :   4
                )
            : 3
            )
        :   // [1-2]
            ( x >=  10u // [2] [1]
            ?   2
            :   1
            )
        )
    );
}
Finely answered 27/12, 2014 at 17:59 Comment(0)
M
1

sample console output

long long num = 123456789;
int digit = 1;
int result = 1;

while (result != 0) 
{
    result = num / 10;
    if (result != 0)
    {
        ++digit;
    }
    num = result;
}

cout << "Your number has " << digit << "digits" << endl;
Mogilev answered 31/12, 2020 at 19:49 Comment(1)
You should make the solution a function, preferrably. Also you can include the sample output as text.Raffish
G
1

Use the best and efficient way of log10(n) approach which gives you the desired result in just logarithmic time.

For negative number abs() converts it into positive number and for the number 0, the if condition stops you from proceeding further and prints the output as 0.

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n; std::cin >> n;
    if(n)
        std::cout << floor(log10(abs(n))+1) << std::endl;
    else
        std::cout << 0 << std::endl;
    return 0;
}
Garwin answered 4/6, 2021 at 17:21 Comment(0)
C
1

Here is neat trick that uses fact that intLog2 is easy and fast and that: log10(x) = log2(x)/log2(10). Rounding issue have to be taken into account.

demo

constexpr int intPow(int base, int n) {
    int result = 1;
    while (n) {
        if (n & 1 == 1)
            result *= base;
        base *= base;
        n >>= 1;
    }
    return result;
}

constexpr int intLog2(int x) {
    int result = -1;
    while (x) {
        x >>= 1;
        ++result;
    }
    return result;
}

constexpr int intLog10(int x) {
    constexpr int powersOf10[]{1,         10,        100,     1000,
                               10000,     100000,    1000000, 10000000,
                               100000000, 1000000000};
    auto aprox = (intLog2(x) + 1) * 1233 >> 12;
    return aprox - (x < powersOf10[aprox]);
}

All is done on integers. No divisions, so should be quite fast, but lookup table is probably faster (maybe will provide benchmark for that).

Concerted answered 17/2, 2022 at 15:7 Comment(3)
Can you extend this for float? My problem is I can't cast float in int.Lashio
For floats it is a complex problem and depends on definition how number should be representedConcerted
intLog2 can be rewritten as return std::numeric_limits<int>::digits - std::countl_zero(static_cast<unsigned>(x));Martinmas
C
0

Yet another code snippet, doing basically the same as Vitali's but employs binary search. Powers array is lazy initialized once per unsigned type instance. Signed type overload takes care of minus sign.

#include <limits>
#include <type_traits>
#include <array>

template <class T> 
size_t NumberOfDecPositions ( T v, typename std::enable_if<std::is_unsigned<T>::value>::type* = 0 )
{
    typedef std::array<T,std::numeric_limits<T>::digits10+1> array_type;
    static array_type powers_of_10;
    if ( powers_of_10.front() == 0 )
    {
        T n = 1;
        for ( T& i: powers_of_10 )
        {
            i = n;
            n *= 10;
        }
    }

    size_t l = 0, r = powers_of_10.size(), p;
    while ( l+1 < r )
    {
        p = (l+r)/2;
        if ( powers_of_10[p] <= v )
            l = p;
        else
            r = p;
    }
    return l + 1;
};

template <class T> 
size_t NumberOfDecPositions ( T v, typename std::enable_if<std::is_signed<T>::value>::type* = 0 )
{
    typedef typename std::make_unsigned<T>::type unsigned_type;
    if ( v < 0 )
        return NumberOfDecPositions ( static_cast<unsigned_type>(-v) ) + 1;
    else
        return NumberOfDecPositions ( static_cast<unsigned_type>(v) );
}

If anybody cares of further optimization, please note that the first element of powers array is never used, and the l appears with +1 2 times.

Chitin answered 16/9, 2013 at 16:58 Comment(0)
M
0

in case the number of digits AND the value of each digit position is needed use this:

int64_t = number, digitValue, digits = 0;    // or "int" for 32bit

while (number != 0) {
    digitValue = number % 10;
    digits ++;
    number /= 10;
}

digit gives you the value at the number postition which is currently processed in the loop. for example for the number 1776 the digit value is:
6 in the 1st loop
7 in the 2nd loop
7 in the 3rd loop
1 in the 4th loop

Mischiefmaker answered 27/3, 2014 at 15:50 Comment(0)
G
0

C++11 update of preferred solution:

#include <limits>
#include <type_traits>
        template <typename T>
        typename std::enable_if<std::numeric_limits<T>::is_integer, unsigned int>::type
        numberDigits(T value) {
            unsigned int digits = 0;
            if (value < 0) digits = 1;
            while (value) {
                value /= 10;
                ++digits;
            }
            return digits;
        }

prevents template instantiation with double, et. al.

Gentianaceous answered 2/11, 2014 at 17:52 Comment(0)
F
0
// Meta-program to calculate number of digits in (unsigned) 'N'.    
template <unsigned long long N, unsigned base=10>
struct numberlength
{   // http://stackoverflow.com/questions/1489830/
    enum { value = ( 1<=N && N<base ? 1 : 1+numberlength<N/base, base>::value ) };
};

template <unsigned base>
struct numberlength<0, base>
{
    enum { value = 1 };
};

{
    assert( (1 == numberlength<0,10>::value) );
}
assert( (1 == numberlength<1,10>::value) );
assert( (1 == numberlength<5,10>::value) );
assert( (1 == numberlength<9,10>::value) );

assert( (4 == numberlength<1000,10>::value) );
assert( (4 == numberlength<5000,10>::value) );
assert( (4 == numberlength<9999,10>::value) );
Finely answered 21/12, 2014 at 17:11 Comment(1)
Correction for "Practical joke" from 'blinnov.com' aboveFinely
F
0
/// Determine the number of digits for a 64 bit integer.
/// - Uses at most 5 comparisons.
/// - (cX) 2014 [email protected]
/// - \see http://stackoverflow.com/questions/1489830/#27670035
/**  #d == Number length vs Number of comparisons == #c
     \code
         #d | #c   #d | #c     #d | #c   #d | #c
         ---+---   ---+---     ---+---   ---+---
         20 | 5    15 | 5      10 | 5     5 | 5
         19 | 5    14 | 5       9 | 5     4 | 5
         18 | 4    13 | 4       8 | 4     3 | 4
         17 | 4    12 | 4       7 | 4     2 | 4
         16 | 4    11 | 4       6 | 4     1 | 4
     \endcode
*/
unsigned NumDigits64bs(uint64_t x) {
    return // Num-># Digits->[0-9] 64->bits bs->Binary Search
    ( x >= 10000000000ul // [11-20] [1-10]
    ?
        ( x >= 1000000000000000ul // [16-20] [11-15]
        ?   // [16-20]
            ( x >= 100000000000000000ul // [18-20] [16-17]
            ?   // [18-20]
                ( x >= 1000000000000000000ul // [19-20] [18]
                ? // [19-20]
                    ( x >=  10000000000000000000ul // [20] [19]
                    ?   20
                    :   19
                    )
                : 18
                )
            :   // [16-17]
                ( x >=  10000000000000000ul // [17] [16]
                ?   17
                :   16
                )
            )
        :   // [11-15]
            ( x >= 1000000000000ul // [13-15] [11-12]
            ?   // [13-15]
                ( x >= 10000000000000ul // [14-15] [13]
                ? // [14-15]
                    ( x >=  100000000000000ul // [15] [14]
                    ?   15
                    :   14
                    )
                : 13
                )
            :   // [11-12]
                ( x >=  100000000000ul // [12] [11]
                ?   12
                :   11
                )
            )
        )
    :   // [1-10]
        ( x >= 100000ul // [6-10] [1-5]
        ?   // [6-10]
            ( x >= 10000000ul // [8-10] [6-7]
            ?   // [8-10]
                ( x >= 100000000ul // [9-10] [8]
                ? // [9-10]
                    ( x >=  1000000000ul // [10] [9]
                    ?   10
                    :    9
                    )
                : 8
                )
            :   // [6-7]
                ( x >=  1000000ul // [7] [6]
                ?   7
                :   6
                )
            )
        :   // [1-5]
            ( x >= 100ul // [3-5] [1-2]
            ?   // [3-5]
                ( x >= 1000ul // [4-5] [3]
                ? // [4-5]
                    ( x >=  10000ul // [5] [4]
                    ?   5
                    :   4
                    )
                : 3
                )
            :   // [1-2]
                ( x >=  10ul // [2] [1]
                ?   2
                :   1
                )
            )
        )
    );
}
Finely answered 27/12, 2014 at 18:6 Comment(0)
A
0

for integer 'X' you want to know the number of digits , alright without using any loop , this solution act in one formula in one line only so this is the most optimal solution i have ever seen to this problem .

 int x = 1000 ; 
 cout<<numberOfDigits = 1+floor(log10(x))<<endl ; 
Archangel answered 27/2, 2017 at 21:16 Comment(3)
Fails for INT_MAX and also for negative numbers.Richie
@Richie Fails for INT_MAX how? When the argument is converted to double? Or are you referring to some impossible integer input with INT_MAX decimal digits? Which would also fail every other answer here?Friend
This is "efficient" w.r.t. space efficiency of the source code of the executable. Usually, "efficiency [of a program]" refers to time or space efficiency of the algorithm, since these actually reduce runtime and main memory requirements. I would suggest to never code in C++ like that. The algorithm is terribly inefficient (with little automated optimization potential) and even involves floating-point arithmetic to solve a very simple task. If you nontheless prefer that style, there are declarative programming languages like Haskell for it.Increase
D
0
int numberOfDigits(int n){

    if(n<=9){
        return 1;
    }
    return 1 + numberOfDigits(n/10);
}

This is what i would do, if you want it for base 10.Its pretty fast and you prolly wont get a stack overflock buy counting integers

Degeneration answered 23/3, 2018 at 18:54 Comment(0)
I
0
int num,dig_quant = 0;
cout<<"\n\n\t\t--Count the digits in Number--\n\n";
cout<<"Enter Number: ";
cin>>num;
for(int i = 1; i<=num; i*=10){
    if(num / i  > 0){
      dig_quant += 1;
    }
}
 cout<<"\n"<<number<<" include "<<dig_quant<<" digit"
 cout<<"\n\nGoodbye...\n\n";
Internuncial answered 23/1, 2019 at 11:51 Comment(0)
C
0

I was working on a program that required me to check if the user correctly answered how many digits were in a number, so i had to develop a way to check the amount of digits in an integer. It ended up being a relatively easy thing to solve.

double check=0, exponent=1000;

while(check<=1)
{
    check=number/pow(10, exponent);
    exponent--;
}

exponent=exponent+2;
cout<<exponent<<endl;

This ended up being my answer which currently works with numbers with less than 10^1000 digits (can be changed by changing the value of exponent).

P.S. I know this answer is ten years late but I got here on 2020 so other people might use it.

Crozier answered 29/3, 2020 at 19:24 Comment(0)
S
0

You can use this recursive function, which calls itself while its argument is greater or equal to 10.

int numDigits(int n) {
    return n >= 10 ? numDigits(n / 10) + 1 : 1;
}

Example usage:

#include <iostream>

int numDigits(int n) {
    return n >= 10 ? numDigits(n / 10) + 1 : 1;
}

int main() {
    int values[] = {0, 4, 10, 43, 789, 1500};
    for (int n : values) {
        std::cout << n << ": " << numDigits(n) << '\n';
    }
    return 0;
}

Output:

0: 1
4: 1
10: 2
43: 2
789: 3
1500: 4
Subdued answered 16/2, 2022 at 14:34 Comment(1)
Good, but it is not fast enough, and fails (like many others) with float FLOAT_MAX.Lashio
C
-1
template <typename type>
class number_of_decimal_digits {   
    const powers_and_max<type> mPowersAndMax;
public:
    number_of_decimal_digits(){
    }   
    inline size_t ndigits( type i) const {
        if(i<0){
             i += (i == std::numeric_limits<type>::min());
             i=-i;
        }
        const type* begin = &*mPowersAndMax.begin();
        const type* end = begin+mPowersAndMax.size();
        return 1 + std::lower_bound(begin,end,i) - begin;
    }
    inline size_t string_ndigits(const type& i) const {
        return (i<0) + ndigits(i);
    }
    inline size_t operator[](const type& i) const {
       return string_ndigits(i);
    }
};

where in powers_and_max we have (10^n)-1 for all n such that

(10^n) < std::numeric_limits<type>::max()

and std::numeric_limits<type>::max() in an array:

template <typename type>
struct powers_and_max : protected std::vector<type>{
    typedef std::vector<type> super;
    using super::const_iterator;
    using super::size;
    type& operator[](size_t i)const{return super::operator[](i)};
    const_iterator begin()const {return super::begin();} 
    const_iterator end()const {return super::end();} 
    powers_and_max() {
       const int size = (int)(log10(double(std::numeric_limits<type>::max())));
       int j = 0;
       type i = 10;
       for( ; j<size ;++j){
           push_back(i-1);//9,99,999,9999 etc;
           i*=10;
       }
       ASSERT(back()<std::numeric_limits<type>::max());
       push_back(std::numeric_limits<type>::max());
   }
};

here's a simple test:

number_of_decimal_digits<int>  ndd;
ASSERT(ndd[0]==1);
ASSERT(ndd[9]==1);
ASSERT(ndd[10]==2);
ASSERT(ndd[-10]==3);
ASSERT(ndd[-1]==2);
ASSERT(ndd[-9]==2);
ASSERT(ndd[1000000000]==10);
ASSERT(ndd[0x7fffffff]==10);
ASSERT(ndd[-1000000000]==11);
ASSERT(ndd[0x80000000]==11);

Of course any other implementation of an ordered set might be used for powers_and_max and if there was knowledge that there would be clustering but no knowledge of where the cluster might be perhaps a self adjusting tree implementation might be best

Convolvulaceous answered 29/9, 2009 at 6:10 Comment(0)
B
-1

effective way

int num;
int count = 0;
while(num)
{
   num /= 10;
   ++count;
}

#include <iostream>

int main()
{
   int num;
   std::cin >> num;

   std::cout << "number of digits for " << num << ": ";

   int count = 0;
   while(num)
   {
      num /= 10;
      ++count;
   }

   std::cout << count << '\n';

   return 0;
}
Benedetto answered 30/9, 2009 at 13:23 Comment(0)
C
-1
int numberOfDigits(double number){
    if(number < 0){
        number*=-1;
    }
    int i=0;
        while(number > pow(10, i))
            i++;    
    cout << "This number has " << i << " digits" << endl;
    return i;
}
Cyclometer answered 14/12, 2014 at 21:21 Comment(0)
O
-2

This is my way to do that:

   int digitcount(int n)
    {
        int count = 1;
        int temp = n;
        while (true)
        {
            temp /= 10;
            if (temp != 0) ++count;
            if (temp == 0) break;
        }

        return count;
    }
Ostracod answered 1/8, 2015 at 8:14 Comment(2)
while true / break syndrome :DLourielouse
-1 this is the same approach that the first answer gave six years earlier, and it adds nothing (in fact it is significantly worse).Barbate
P
-4

Here's a different approach:

digits = sprintf(numArr, "%d", num);    // where numArr is a char array
if (num < 0)
    digits--;

This may not be efficient, just something different than what others suggested.

Pyrone answered 29/9, 2009 at 5:32 Comment(1)
The request was for extremely efficient. This is the opposite.Tallow

© 2022 - 2024 — McMap. All rights reserved.