在C ++中获取int的十进制表示长度的最佳方法是什么?

时间:2009-11-08 11:25:38

标签: c++

写什么是最好的方法

int NumDigits(int n);
在C ++中的

,它将返回输入的十进制表示中的位数。例如11-> 2,999-> 3,-1-> 2等等。

13 个答案:

答案 0 :(得分:17)

清洁快速,独立于sizeof(int)

int NumDigits(int n) {
    int digits = 0;
    if (n <= 0) {
        n = -n;
        ++digits;
    }
    while (n) {
        n /= 10;
        ++digits;
    }
    return digits;
}

答案 1 :(得分:12)

//Works for positive integers only
int DecimalLength(int n) {
    return floor(log10f(n) + 1);
}

答案 2 :(得分:10)

最快的方式可能是二元搜索...

//assuming n is positive
if (n < 10000)
    if (n < 100)
        if (n < 10)
            return 1;
        else
            return 2;
    else
        if (n < 1000)
            return 3;
        else
            return 4;
 else
     //etc up to 1000000000

在这种情况下,无论输入如何,它都是3次比较,我怀疑它比分割循环或使用双精度要快得多。

答案 3 :(得分:8)

一种方法是(可能不是最有效)将其转换为字符串并找到字符串的长度。像:

int getDigits(int n)
{
    std::ostringstream stream;
    stream<<n;

    return stream.str().length();
}

答案 4 :(得分:7)

要扩展Arteluis的答案,您可以使用模板生成比较:

template<int BASE, int EXP>
struct Power
{
    enum {RESULT = BASE * Power<BASE, EXP - 1>::RESULT};
};

template<int BASE>
struct Power<BASE, 0>
{
    enum {RESULT = 1};
};

template<int LOW = 0, int HIGH = 8>
struct NumDigits
{
    enum {MID = (LOW + HIGH + 1) / 2};

    inline static int calculate (int i)
    {
        if (i < Power<10, MID>::RESULT)
            return NumDigits<LOW, MID - 1>::calculate (i);
        else
            return NumDigits<MID, HIGH>::calculate (i);
    }
};

template<int LOW>
struct NumDigits<LOW, LOW>
{
    inline static int calculate (int i)
    {
        return LOW + 1;
    }
};

int main (int argc, char* argv[])
{
    // Example call.
    std::cout << NumDigits<>::calculate (1234567) << std::endl;

    return 0;
}

答案 5 :(得分:6)

numdigits = snprintf(NULL, 0, "%d", num);

答案 6 :(得分:3)

int NumDigits(int n)
{
  int digits = 0;

  if (n < 0) {
    ++digits;
    do {
      ++digits;
      n /= 10;
    } while (n < 0);
  }
  else {
    do {
      ++digits;
      n /= 10;
    } while (n > 0);
  }

  return digits;
}

编辑:更正了-2 ^ 31(等)的边缘案例行为

答案 7 :(得分:3)

已经提出了一些非常复杂的解决方案,包括已接受的解决方案。

考虑:

#include <cmath>
#include <cstdlib>

int NumDigits( int num )
{
    int digits = (int)log10( (double)abs(num) ) + 1 ;

    return num >= 0 ? digits : digits + 1 ;
}

请注意,它适用于INT_MIN + 1 ... INT_MAX,因为abs(INT_MIN)== INT_MAX + 1 == INT_MIN(由于环绕),这反过来是对log10()的无效输入。可以为这一个案例添加代码。

答案 8 :(得分:1)

由于目标是要快,所以这是对andrei alexandrescu's improvement的改进。他的版本已经比幼稚的方式快(每位数除以10)。对于大多数尺寸,至少在x86-64和ARM上,以下版本速度更快。

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

inline uint32_t digits10(uint64_t v)
{
  std::uint32_t result = 0;
  for (;;)
  {
    result += 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);
    if (v < 1000000) return result;
    v /= 1000000U;
  }
}

答案 9 :(得分:0)

我的循环版本(使用0,负值和正值):

int numDigits(int n)
{
   int digits = n<0;  //count "minus"
   do { digits++; } while (n/=10);
   return digits;
}

答案 10 :(得分:0)

如果您使用的是包含C99数学函数的C ++版本(C ++ 0x和一些早期的编译器)

static const double log10_2 = 3.32192809;

int count_digits ( int n )
{
    if ( n == 0 ) return 1;
    if ( n < 0 ) return ilogb ( -(double)n ) / log10_2 + 2;
    return ilogb ( n ) / log10_2 + 1;
}

ilogb是否比循环更快取决于体系结构,但它足以将这类问题添加到标准中。

答案 11 :(得分:0)

先前分割方法的优化。 (顺便说一下,如果n!= 0,他们都会测试,但是大多数时候n&gt; = 10似乎已经足够了,并且需要一个更昂贵的部门。)

我只是使用乘法,它似乎使它更快(这里几乎是4倍),至少在1..100000000范围内。我对这种差异感到有些惊讶,所以这可能会触发一些特殊的编译器优化,或者我错过了一些东西。

最初的改变很简单,但不幸的是我需要处理一个新的溢出问题。它使它不那么好,但在我的测试用例中,10 ^ 6技巧不仅可以补偿增加支票的成本。显然它取决于输入分布,你也可以调整这个10 ^ 6的值。

PS:当然,这种优化只是为了好玩:)

int NumDigits(int n) {
    int digits = 1;
    // reduce n to avoid overflow at the s*=10 step.
    // n/=10 was enough but we reuse this to optimize big numbers
    if (n >= 1000000) {
        n /= 1000000;
        digits += 6; // because 1000000 = 10^6
    }
    int s = 10;
    while (s <= n) {
        s *= 10;
        ++digits;
    }
    return digits;
}

答案 12 :(得分:0)

这是Alink's answer的简单版本。

int NumDigits(int n)
{
    if (n < 0)
        return NumDigits(-n) + 1;

    static int MaxTable[9] = { 10,100,1000,10000,100000,1000000,10000000,100000000,1000000000 };
    return 1 + (std::upper_bound(MaxTable, MaxTable+9, n) - MaxTable);
}