在C中查找整数的长度

mar*_*048 61 c integer digit

我想知道如何在C中找到整数的长度.

例如:

  • 1 => 1
  • 25 => 2
  • 12512 => 5
  • 0 => 1

等等.

我怎么能在C中这样做?

Jor*_*wis 98

C:

为什么不直接取数字的绝对值的基数10日志,将其四舍五入,并添加一个?这适用于非0的正数和负数,并且避免必须使用任何字符串转换函数.

这些log10,absfloor函数由提供math.h.例如:

int nDigits = floor(log10(abs(the_integer))) + 1;
Run Code Online (Sandbox Code Playgroud)

你应该将它包装在一个条款中,确保the_integer != 0,因为log10(0)返回-HUGE_VAL根据man 3 log.

此外,如果输入为负数,您可能希望在最终结果中添加一个,如果您对数字的长度感兴趣,包括其负号.

Java的:

int nDigits = Math.floor(Math.log10(Math.abs(the_integer))) + 1;
Run Code Online (Sandbox Code Playgroud)

NB此方法涉及的计算的浮点性质可能导致它比更直接的方法更慢.有关效率的一些讨论,请参阅Kangkan答案的评论.

  • +1.每个程序员都应该了解基础数学. (3认同)
  • 实际上你应该使用下限并加 1。Math.Ceil(Math.Log(99)) = 2 但 Math.Ceil(Math.Log(10)) = 1。 Math.Floor(Math.Log(99)) + 1 = 2 和 Math.Floor(Math.对数(10)) = 2 (2认同)
  • 这不适用于 999999999999999999,这是一个 C 整数,它将被转换为更大的双精度值,从而产生错误的数字计数。OP 没有指定`int`,只是整数。 (2认同)

Eam*_*nne 45

如果您对快速非常简单的解决方案感兴趣,以下可能是最快的(这取决于相关数字的概率分布):

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

int printLen(int x) {
    return x < 0 ? lenHelper(-x) + 1 : lenHelper(x);
}
Run Code Online (Sandbox Code Playgroud)

虽然它可能无法为最巧妙的解决方案赢得奖品,但理解并轻松执行是微不足道的 - 所以它很快.

在使用MSC的Q6600上,我使用以下循环对此进行了基准测试:

int res = 0;
for(int i = -2000000000; i < 2000000000; i += 200) res += printLen(i);
Run Code Online (Sandbox Code Playgroud)

这个解决方案需要0.062秒,Pete Kirkham使用智能对数方法的第二快解决方案需要0.115秒 - 几乎是两倍.但是,对于10000左右及以下的数字,智能日志更快.

以一些清晰度为代价,您可以更可靠地击败智能日志(至少在Q6600上):

int lenHelper(unsigned x) { 
    // this is either a fun exercise in optimization 
    // or it's extremely premature optimization.
    if(x >= 100000) {
        if(x >= 10000000) {
            if(x >= 1000000000) return 10;
            if(x >= 100000000) return 9;
            return 8;
        }
        if(x >= 1000000) return 7;
        return 6;
    } else {
        if(x >= 1000) {
            if(x >= 10000) return 5;
            return 4;
        } else {
            if(x >= 100) return 3;
            if(x >= 10) return 2;
            return 1;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对于较大的数字,此解决方案仍为0.062秒,对于较小的数字,此解决方案降至约0.09秒 - 两种情况下都比智能对数方法更快.(gcc使代码更快;此解决方案为0.052,智能对数方法为0.09).

  • 我不禁想到第二个版本看起来完全是用三元运算符编写的...... (10认同)

zed*_*xff 26

int get_int_len (int value){
  int l=1;
  while(value>9){ l++; value/=10; }
  return l;
}
Run Code Online (Sandbox Code Playgroud)

第二个也适用于负数:

int get_int_len_with_negative_too (int value){
  int l=!value;
  while(value){ l++; value/=10; }
  return l;
}
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这个.没有关于大小的假设的临时字符缓冲区. (3认同)

Kan*_*kan 18

你可以写一个这样的函数:

unsigned numDigits(const unsigned n) {
    if (n < 10) return 1;
    return 1 + numDigits(n / 10);
}
Run Code Online (Sandbox Code Playgroud)

  • @Jordan Lewis称这2000万次在我的上网本上花了1.8秒; 调用代码需要6.6秒(两者都是gcc -O3).对log10的一次调用比这使得所有递归调用慢得多. (8认同)
  • 这是不必要的低效率 - 为什么在一次调用log10时可以使用最多18个递归函数调用? (4认同)
  • @Pete我一定犯了一个错误,导致编译器优化之前的实际调用.我现在观察到像你这样的差距 - 递归版本为.26秒,浮点算术版本为1.68秒.有趣! (4认同)
  • @Pete我看到log10版本为.001s,英特尔i7上的递归版本为.44s,-O3为2000万次. (2认同)

Fri*_*ner 11

n的长度:

length =  ( i==0 ) ? 1 : (int)log10(n)+1;
Run Code Online (Sandbox Code Playgroud)


IVl*_*lad 7

整数的位数x等于1 + log10(x).所以你可以这样做:

#include <math.h>
#include <stdio.h>

int main()
{
    int x;
    scanf("%d", &x);
    printf("x has %d digits\n", 1 + (int)log10(x));
}
Run Code Online (Sandbox Code Playgroud)

或者你可以运行一个循环来自己计算数字:整数除以10,直到数字为0:

int numDigits = 0;
do
{
    ++numDigits;
    x = x / 10;
} while ( x );
Run Code Online (Sandbox Code Playgroud)

1如果整数0在第一个解决方案中并且您可能还想要处理负整数(使用-xif x < 0),则必须要小心返回.


Pet*_*ham 7

最有效的方法可能是使用基于快速对数的方法,类似于用于确定整数中最高位集的方法.

size_t printed_length ( int32_t x )
{
    size_t count = x < 0 ? 2 : 1;

    if ( x < 0 ) x = -x;

    if ( x >= 100000000 ) {
        count += 8;
        x /= 100000000;
    }

    if ( x >= 10000 ) {
        count += 4;
        x /= 10000;
    }

    if ( x >= 100 ) {
        count += 2;
        x /= 100;
    }

    if ( x >= 10 )
        ++count;

    return count;
}
Run Code Online (Sandbox Code Playgroud)

这个(可能是不成熟的)优化需要0.65秒才能在我的上网本上拨打2000万个电话; 像zed_0xff这样的迭代划分需要1.6s,像Kangkan这样的递归划分需要1.8s,并且使用浮点函数(Jordan Lewis的代码)需要高达6.6s.使用snprintf需要11.5秒,但会为你提供snprintf对任何格式所需的大小,而不仅仅是整数.乔丹报告说,他的处理器没有保留时序的排序,这比我的浮点更快.

最简单的可能是询问snprintf的打印长度:

#include <stdio.h>

size_t printed_length ( int x )
{
    return snprintf ( NULL, 0, "%d", x );
}

int main ()
{
    int x[] = { 1, 25, 12512, 0, -15 };

    for ( int i = 0; i < sizeof ( x ) / sizeof ( x[0] ); ++i )
        printf ( "%d -> %d\n", x[i], printed_length ( x[i] ) );

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 这取决于你想要长度的原因 - 如果你想知道snprintf需要多少个字符,你最好使用snprintf; 如果你想要愚蠢的优化代码,你可能想要第一个. (2认同)

Jam*_*ong 6

是的,使用sprintf.

int num;
scanf("%d",&num);
char testing[100];
sprintf(testing,"%d",num);
int length = strlen(testing);
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用该log10函数以数学方式执行此操作.

int num;
scanf("%d",&num);
int length;
if (num == 0) {
  length = 1;
} else {    
  length = log10(fabs(num)) + 1;
  if (num < 0) length++;
}
Run Code Online (Sandbox Code Playgroud)


sam*_*var 6

正确的snprintf实施:

int count = snprintf(NULL, 0, "%i", x);
Run Code Online (Sandbox Code Playgroud)


小智 5

int digits=1;

while (x>=10){
    x/=10;
    digits++;
}
return digits;
Run Code Online (Sandbox Code Playgroud)