确定整数位数的有效方法

时间:2009-09-28 23:20:15

标签: c++ integer digits

确定C ++中整数中有多少位数的 高效 方式是什么?

30 个答案:

答案 0 :(得分:99)

嗯,假设您知道整数的大小,最有效的方法是查找。应该比基于对数的方法更短。如果您不关心计算' - ',请删除+ 1。

// 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 32-bit numbers
template<>
int numDigits(int32_t x)
{
    if (x == MIN_INT) 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];
}

答案 1 :(得分:68)

最简单的方法是:

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

log10在<cmath><math.h>中定义。您需要对此进行分析,以确定它是否比此处发布的其他任何内容更快。我不确定这对于浮点精度有多强大。此外,参数是无符号的负值,而log并不真正混合。

答案 2 :(得分:52)

也许我误解了这个问题,但这不是吗?

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

答案 3 :(得分:32)

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

注意:“0”将有0位数!如果您需要0来显示1位数,请使用:

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

(谢谢Kevin Fegan)

最后,使用分析器知道您机器上的所有答案中的哪一个会更快...

答案 4 :(得分:11)

实用笑话: 这是 最有效的方式(在编译时计算的位数):

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

可能有助于确定格式化,输入元素等中数字字段所需的宽度。

答案 5 :(得分:9)

请参阅Bit Twiddling Hacks,了解您接受的答案的更短版本。如果您的输入是正态分布的,它还可以通过首先检查大常量来更快地找到答案。 (v >= 1000000000)捕获了76%的值,因此首先检查它的速度会更快。

答案 6 :(得分:8)

转换为字符串,然后使用内置函数

unsigned int i;
cout<< to_string(i).length()<<endl;

答案 7 :(得分:6)

之前的海报提出了一个除以10的循环。 由于现代机器上的倍数要快得多,我建议使用以下代码:

 int digits = 1, pten=10; while ( pten <= number ) { digits++; pten*=10; }

答案 8 :(得分:5)

ppc架构有一个位计数指令。这样,您可以在单个指令中确定正整数的对数基数2。例如,32位将是:

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

如果您可以在较大的值上处理一小部分错误,可以使用其他几条指令将其转换为log base 10:

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

这是特定于平台的并且稍微不准确,但也不涉及分支,划分或转换为浮点。一切都取决于你需要什么。

我只知道ppc指令,但其他架构应该有类似的指令。

答案 9 :(得分:4)

int x = 1000;
int numberOfDigits = x ? static_cast<int>(log10(abs(x))) + 1 : 1;

答案 10 :(得分:3)

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

这可能是解决问题的最简单方法,假设您只关心小数点前的数字,并假设小于10的数字只是1位数。

答案 11 :(得分:2)

#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 adolfo.dimare@gmail.com
/// - \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
            )
        )
    );
}

答案 12 :(得分:1)

使用 log10(n) 方法的最佳和有效方法,只需 对数 时间即可获得所需的结果。

对于负数 abs() 将其转换为正数,对于数字 0if 条件会阻止您继续进行并将输出打印为 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;
}

答案 13 :(得分:1)

/// Determine the number of digits for a 64 bit integer.
/// - Uses at most 5 comparisons.
/// - (cX) 2014 adolfo.dimare@gmail.com
/// - \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
                )
            )
        )
    );
}

答案 14 :(得分:1)

我喜欢Ira Baxter的回答。这是一个模板变体,它处理各种大小并处理最大整数值(更新以提升循环的上限检查):

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

要从循环中提升附加测试来实际获得改进的性能,您需要专门化max_decimal()以返回平台上每种类型的常量。一个足够神奇的编译器可以将对max_decimal()的调用优化为常量,但是今天大多数编译器的专业化都会更好。就目前而言,这个版本可能更慢,因为max_decimal的成本高于从循环中删除的测试。

我将把所有这些留作读者的练习。

答案 15 :(得分:0)

如果需要数字位数 AND ,则需要使用以下数字:

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

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

digit为您提供当前在循环中处理的数字邮件的值。例如,对于数字1776,数字值是:
6在第1循环中 7在第二循环中 7在第3循环中 第4循环中的1

答案 16 :(得分:0)

首选解决方案的C ++ 11更新:

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

使用double,et阻止模板实例化。人

答案 17 :(得分:0)

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

答案 18 :(得分: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) );

答案 19 :(得分:0)

另一个代码片段,基本上与Vitali相同,但采用二进制搜索。每个无符号类型实例,Powers数组被延迟初始化一次。有符号的类型超载负责减号。

#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) );
}

如果有人关心进一步优化,请注意,powers数组的第一个元素从未使用过,l出现+1 2次。

答案 20 :(得分:0)

有效方式

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

答案 21 :(得分:0)

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

powers_and_max我们(10^n)-1 n所有(10^n) <

std::numeric_limits<type>::max() std::numeric_limits<type>::max()

数组中的

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()); } };

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);

这是一个简单的测试:

powers_and_max

当然,有序集的任何其他实现都可以用于{{1}},如果知道存在集群但不知道集群可能在哪里,那么自调整树实现可能是最好的< / p>

答案 22 :(得分:0)

int numberOfDigits(int n){

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

这就是我要做的,如果你想要它的基础10.它相当快,你不会得到一个堆栈overflock购买计数整数

答案 23 :(得分: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";

答案 24 :(得分:0)

如果更快更有效,则是andrei alexandrescu's improvement的改进。他的版本已经比幼稚的方式快(每位数除以10)。下面的版本是恒定时间的,至少在所有尺寸的x86-64和ARM上都更快,但是占用的二进制代码数量是后者的两倍,因此它对缓存的友好程度不高。

我的PR on facebook folly上的该版本与亚历山大版本的基准。

unsigned上工作,而不在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);
}

答案 25 :(得分:0)

我正在开发一个程序,该程序需要我检查用户是否正确回答了一个数字中有多少个数字,因此我不得不开发一种方法来检查整数中的数字量。最终这是一个相对容易解决的事情。

double check=0, exponent=1000;

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

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

这最终是我的答案,该答案当前适用于少于10 ^ 1000个数字的数字(可以通过更改指数的值来更改)。

P.S。 我知道这个答案已经晚了十年,但我于2020年到达这里,以便其他人可以使用它。

答案 26 :(得分:0)

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;

答案 27 :(得分:-1)

对于整数'X'你想知道数字的位数,好吧不使用任何循环,这个解决方案只在一行中的一个公式中运行,所以这是我遇到过的这个问题的最佳解决方案。

 int x = 1000 ; 
 cout<<numberOfDigits = 1+floor(log10(x))<<endl ; 

答案 28 :(得分:-2)

这是我的方法:

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

        return count;
    }

答案 29 :(得分:-3)

这是一种不同的方法:

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

这可能效率不高,只是与其他人建议的不同。

相关问题