【问题标题】:Efficient way to determine number of digits in an integer确定整数位数的有效方法
【发布时间】:2010-12-02 04:02:21
【问题描述】:

在 C++ 中确定整数中有多少位的非常高效方法是什么?

【问题讨论】:

  • 在什么基础上? 2? 10 点?
  • 我想在base 10中做
  • 我曾经问过一个相关的问题:如何获得 int 中的第一个数字?人们的答案中使用了许多与以下相同的方法。这是与您的任务相关的链接 [stackoverflow.com/questions/701322/]
  • 虽然所有这些答案都以 10 为基数,但很容易更改为任何所需基数的计算结果。
  • 您对效率的衡量标准是什么?选项包括最小化代码大小、CPU 周期数,甚至结果的准确性。但每一个都涉及以不同的方式做事。还有,你是指十进制数字、八进制数字、十六进制数字还是别的什么?

标签: c++ integer digits


【解决方案1】:
int digits = 0; while (number != 0) { number /= 10; digits++; }

注意:“0”将有 0 个数字!如果您需要 0 看起来有 1 个数字,请使用:

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

(感谢凯文·费根)

最后,使用分析器来了解这里所有答案中的哪一个在您的机器上会更快...

【讨论】:

  • 这可能会或可能不会比我采用的展开循环方法更快 - 您需要分析差异(从长远来看应该可以忽略不计)。
  • 同意,剖析是真正确定的唯一方法!我用该评论更新了我的答案,因为 Ben S 的 ceil(log10()) 答案已经消失了。
【解决方案2】:

好吧,假设您知道整数的大小,最有效的方法是查找。应该比更短的基于对数的方法更快。如果您不关心计算“-”,请删除 + 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];
}

【讨论】:

  • 可能比我的回答快,做得好。为了提高效率,如果您知道您的输入数字大多是小数字(我猜少于 100,000),那么反转测试: if (x
  • 或者重新排序和嵌套 if 语句,以进行二分查找而不是线性查找。
  • 这不是一个好主意。当架构扩展到 256 位整数时会发生什么。你需要记得回来修改这段代码。在现实生活中,这不会发生,而且这可能会被用来构建一个正确大小的缓冲区,您现在正在为大型架构上的各种缓冲区运行问题敞开大门。
  • 假设数字的均匀分布,反向线性搜索(从最大位数到 1 开始)可能比二分搜索平均更快,因为 N 位数的数字比 N-1 的数字多得多数字graphics.stanford.edu/~seander/…
  • 我不会非常担心 256 或 128 位整数。除非您需要计算宇宙中的电子数量(我上次计算时为 10^78),否则 64 位将做得很好。 32 位机器持续了 ~15 年。我猜 64 位机器会持续更长时间。对于较大的数字,多精度算术会很好,我怀疑计算位数的效率是否重要。
【解决方案3】:

最简单的方法是:

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

log10 在&lt;cmath&gt;&lt;math.h&gt; 中定义。您需要对此进行分析,以查看它是否比此处发布的任何其他内容都快。我不确定这在浮点精度方面有多稳健。此外,该参数是无符号的负值,并且 log 并没有真正混合。

【讨论】:

  • 对于 32 位整数和 56 位浮点数,这可能有效。如果输入是长的(64 位),则 56 位的双精度日志可能会导致在值接近 10^n 的大值的情况下产生错误的答案。预计麻烦超过 2^50。
  • 还有日志函数的准确度的问题。我还没有检查过它们在现代图书馆中的准确度,并且不会盲目地相信它们对十亿分之一有好处。
  • @DavidThornley:除非在编译器命令行中指定,否则日志或其他数学函数非常精确。有些将在编译时转换为 x86 内在函数。有些不存在,并将扩展为现有内在函数的公式。例如,如果使用-fpfast,您可能会看到使用 SSE instrinsics 而不是 x87,这对 IIRC 精度的保证较少。但默认没有问题。
  • @DavidThornley:不仅仅是精确。问题是是否保证所有相关 k 的 log10 (10^k) ≥ k。也就是说,它保证任何不可避免的舍入误差都会朝着正确的方向发展。 k + eps 结果有效, k - eps 无效。而“完全精确”是幼稚的。
  • 测试 i > 0 可以优化为 i > 9
【解决方案4】:

之前的一张海报提出了一个除以 10 的循环。 由于现代机器上的乘法速度要快得多,我建议改用以下代码:

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

【讨论】:

  • 魔鬼在细节中 - 说 std::numeric_limits::max == number 会发生什么 - 终止可能有问题
  • 如果您担心这种情况,可以添加一个额外的 IF 来处理非常大的值。
  • 我应该观察到,在 x86 机器上,在这种情况下使用的乘以常数 10 实际上可以由编译器实现为 LEA R2,[8*R1+R1], ADD R1,R2所以最多需要2个时钟。乘以变量需要几十个时钟,除法更糟糕。
  • 除法的优点是不用担心负数。
  • 我对乘法方法(使用晶圆厂消除符号问题)与除法方法进行了基准测试。在我的机器上,除法方法比乘法方法慢 2 倍。这是否是过早的优化实际上取决于调用的位置和方式。
【解决方案5】:

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

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

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

【讨论】:

  • 首先,您的解决方案不适用于 0。其次,您的解决方案不适用于变量的一般情况。第三,如果你使用的是常量字面量,你已经知道它有多少位了。
  • 它也适用于 0。它也适用于任何基地。其余的都是我已经概述的有效点。
  • 我不认为它确实如此。它在0 上失败,并且在基数1 上也失败:) 如果基数为0,则除以零错误。不过可以修复。无论如何,我在挑剔一个非常老的帖子,很抱歉,只是我认为这不必是一个玩笑,实际上可能很有用。
【解决方案6】:

这是一种不同的方法:

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

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

【讨论】:

  • 请求非常高效。这是相反的。
【解决方案7】:

请参阅 Bit Twiddling Hacks 以获取您接受的答案的更简短版本。如果您的输入是正态分布的,它还具有更快地找到答案的好处,方法是首先检查大常数。 (v &gt;= 1000000000) 捕获 76% 的值,因此平均而言,首先检查会更快。

【讨论】:

  • 不清楚比特旋转是否真的更快。即使在最坏的情况下,我修改后的方法也需要进行 4 次比较(如果我进一步检查分区,可能可以将其降低到 3,尽管这看起来不太可能)。我严重怀疑这会被算术运算+内存负载击败(尽管如果访问足够多,它们就会消失在 CPU 缓存中)。请记住,在他们给出的示例中,他们还将日志库 2 隐藏为一些抽象的 IntegerLogBase2 函数(它本身实际上并不便宜)。
  • 作为跟进,是的,如果数字是正态分布的,那么按顺序检查会更快。但是,它的退化情况是在最坏的情况下会慢两倍。按位数而不是输入空间的分区方法意味着该行为没有退化的情况并且始终表现最佳。此外,请记住您假设数字将均匀分布。事实上,我猜他们更有可能遵循与 en.wikipedia.org/wiki/…> 相关的一些分布。
  • bit twiddling hack 并不比上面的分区方法快,但如果你在这里有一个更一般的情况,比如 float,它们可能会很有趣。
  • 在给定 int log2 的情况下,bit twiddling hacks 提出了一种获取 int log10 的方法。它提出了几种获取 int log2 的方法,主要涉及很少的比较/分支。 (我认为你低估了不可预测分支的成本,Vitali)。如果您可以使用内联 x86 asm,BSR 指令将为您提供一个值的 int log2(即最高有效设置位的位索引)。在 K8 上有点慢(10 个周期延迟),但在 Core 2 上很快(2 或 3 个周期延迟)。即使在 K8 上,也可能比比较更快。
  • 在K10上,lzcnt计算前导零,所以和bsr几乎一样,但是输入0不再是未定义结果的特例。延迟:BSR:4,LZCNT:2。
【解决方案8】:

我喜欢 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 的成本高于从循环中删除的测试。

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

【讨论】:

  • 您希望先对上限检查进行单独的条件测试,这样您就不会在每次循环迭代时检查它。
  • 你不想把 10 放到那个 temp t 中。编译器可能会将乘以 t 视为乘以实变量,并使用通用乘法指令。如果您改为写“结果* = 10;”编译器肯定会注意到乘以常数 10 并通过一些移位和加法来实现它,这非常快。
  • 如果乘以 t 总是乘以 10,那么是的,编译器可以降低强度。但是,在这种情况下, t 不是循环不变的(它只是对我周围的整数幂函数的修改)。正确的优化是专门返回常量的类型。但是,您是对的,在这种情况下,函数总是将 10 提高到一次幂,而不是任意整数到一次幂,并且强度降低会带来很好的胜利。所以我做了一个改变......这次进一步的改变真的留作练习! (堆栈溢出是一个很大的时间槽......)
【解决方案9】:
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 中,所有n 都有(10^n)-1,这样

(10^n) &lt;std::numeric_limits&lt;type&gt;::max()

std::numeric_limits&lt;type&gt;::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,如果知道会有集群但不知道集群可能在哪里,那么自调整树实现可能是最好的

【讨论】:

    【解决方案10】:

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

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

    如果您可以处理较大值的小幅误差,则可以使用另外几条指令将其转换为以 10 为底的对数:

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

    这是特定于平台的,稍微不准确,但也不涉及分支、除法或转换为浮点数。一切都取决于您的需求。

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

    【讨论】:

    • 此解决方案计算 log2(15)= 4 位和 log2(9)=4 位。但是 15 和 9 需要不同数量的十进制数字才能打印。所以它不起作用,除非你不介意你的数字有时用太多数字打印。但在这种情况下,您始终可以选择“10”作为 int 的答案。
    • 哇,一个近似函数。不错。
    【解决方案11】:

    有效的方法

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

    【讨论】:

      【解决方案12】:

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

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

      【讨论】:

      • 如果这个解决方案是最快的,我不会感到惊讶。
      【解决方案13】:

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

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

      【讨论】:

        【解决方案14】:

        另一个代码 sn-p,与 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 次。

        【讨论】:

          【解决方案15】:

          如果需要位数AND每个数字位置的值,请​​使用:

          int64_t = number, digitValue, digits = 0;    // or "int" for 32bit
          
          while (number != 0) {
              digitValue = number % 10;
              digits ++;
              number /= 10;
          }
          

          digit 为您提供当前在循环中处理的数字位置的值。例如,对于数字 1776,数字值为:
          第一个循环中的 6 个
          7 在第二个循环
          7 在第三个循环
          第 4 个循环中的 1 个

          【讨论】:

            【解决方案16】:

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

            防止模板实例化双等。人。

            【讨论】:

              【解决方案17】:
              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】:
                // 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) );
                

                【讨论】:

                • 更正上面“blinnov.com”中的“实用笑话”
                【解决方案19】:
                #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
                            )
                        )
                    );
                }
                

                【讨论】:

                  【解决方案20】:
                  /// 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
                                  )
                              )
                          )
                      );
                  }
                  

                  【讨论】:

                    【解决方案21】:

                    这是我的做法:

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

                    【讨论】:

                    • 当真/打破综合症:D
                    • -1 这与六年前第一个答案给出的方法相同,它没有增加任何东西(实际上它明显更糟)。
                    【解决方案22】:

                    对于整数“X”,您想知道位数,可以不使用任何循环,此解决方案仅在一行中的一个公式中起作用,因此这是我见过的解决此问题的最佳解决方案。

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

                    【讨论】:

                    • INT_MAX 和负数都失败。
                    • @ranu INT_MAX 失败怎么办?当参数转换为double?或者你指的是一些不可能的整数输入与 INT_MAX 十进制数字?这里的其他答案也会失败?
                    【解决方案23】:
                     #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 位数字。

                    【讨论】:

                      【解决方案24】:
                      int numberOfDigits(int n){
                      
                          if(n<=9){
                              return 1;
                          }
                          return 1 + numberOfDigits(n/10);
                      }
                      

                      这就是我会做的,如果你想要它以 10 为底。它非常快,而且你不会得到堆栈 overflock 购买计数整数

                      【讨论】:

                        【解决方案25】:
                        int x = 1000;
                        int numberOfDigits = x ? static_cast<int>(log10(abs(x))) + 1 : 1;
                        

                        【讨论】:

                        • 虽然这在 LOC 方面是有效的,但正如公认的答案中指出的那样,使用 log 可能不会提供最佳性能。
                        • @Ian 为什么不呢?这只是几个 FPU 指令。比其他答案中的所有分支和循环都要好。
                        【解决方案26】:
                        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";
                        

                        【讨论】:

                          【解决方案27】:

                          如果更快更有效,这是对andrei alexandrescu's improvement 的改进。他的版本已经比天真的方法(每个数字除以 10)更快。下面的版本是恒定时间的,至少在所有大小的 x86-64 和 ARM 上都更快,但占用的二进制代码是两倍,因此它对缓存不友好。

                          我的PR on facebook folly 上此版本与 alexandrescu 版本的基准测试。

                          适用于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);
                          }
                          

                          【讨论】:

                            【解决方案28】:

                            我正在开发一个程序,该程序要求我检查用户是否正确回答了数字中的位数,因此我必须开发一种方法来检查整数中的位数。它最终成为一件相对容易解决的事情。

                            double check=0, exponent=1000;
                            
                            while(check<=1)
                            {
                                check=number/pow(10, exponent);
                                exponent--;
                            }
                            
                            exponent=exponent+2;
                            cout<<exponent<<endl;
                            

                            这最终成为我的答案,它目前适用于小于 10^1000 位的数字(可以通过更改指数的值来更改)。

                            附: 我知道这个答案晚了十年,但我是在 2020 年来到这里的,所以其他人可能会使用它。

                            【讨论】:

                              【解决方案29】:

                              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;
                              

                              【讨论】:

                              • 您最好将解决方案设为函数。您也可以将示例输出包含为文本。
                              【解决方案30】:

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

                              【讨论】:

                                猜你喜欢
                                • 2010-12-01
                                • 2017-11-22
                                • 1970-01-01
                                • 1970-01-01
                                • 2015-07-14
                                • 2021-11-05
                                • 1970-01-01
                                • 1970-01-01
                                相关资源
                                最近更新 更多