写什么是最好的方法
int NumDigits(int n);
在C ++中的,它将返回输入的十进制表示中的位数。例如11-> 2,999-> 3,-1-> 2等等。
答案 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);
}