【问题标题】:Finding the length of an integer in C在C中查找整数的长度
【发布时间】:2011-03-05 08:20:33
【问题描述】:

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

例如:

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

等等。

如何在 C 中做到这一点?

【问题讨论】:

  • 如果整数为0,“长度”的定义是什么?否定?
  • stackoverflow.com/questions/679602/…。这几乎是重复的,但不完全是 .NET 问题。
  • 正确的问题不是整数的长度,而是表示该数字所需的最小十进制位数(保存在 C int 中)。 log10 是你的朋友:log10(10000) = 4, +1 位数(log10 必须被截断)...如果 num 为 neg,如果你想计算它,你需要一个 - 符号,并且log10(-num)(因为负数的对数是“有问题的”。
  • 您如何确定log10(10000) 将返回 4 而不是 3.999999...?
  • 嗯。实验表明log10(10**n) 产生从 1 到 2**19 的 10 次方的精确值,至少在 gcc 和 glibc 中是这样。但我不会指望它用于所有实现。 (** 表示求幂;C 中没有这样的运算符。)

标签: c integer digit


【解决方案1】:

解决方案

使用整数长度变化的限制,在小数的情况下它是10的幂,因此每次验证指定的整数没有超过限制时使用一个计数器。

使用math.h 依赖:

#include <math.h>

int count_digits_of_integer(unsigned int integer) {
    int count = 1;

    while(1) {
        int limit = pow(10, count);
        if(integer < limit) break;
        count++;

    }

    return count;
}

无依赖:

int int_pow(int base, int exponent) {
    int potency = base;

    for(int i = 1; i < exponent; i++) potency *= base;

    return potency;

}

int count_digits_of_integer(unsigned int integer) {
    int count = 1;
    
    while(1) {
        int limit = int_pow(10, count);
        if(integer < limit) break;
        count++;

    }
    
    return count;
}

实施

#include <stdio.h>

// Copy and paste the solution code here

int main() {
    
    printf("%i -> (%i digits)\n", 0, count_digits_of_integer(0));
    printf("%i -> (%i digits)\n", 12, count_digits_of_integer(12));
    printf("%i -> (%i digits)\n", 34569, count_digits_of_integer(34569));
    printf("%i -> (%i digits)\n", 1234, count_digits_of_integer(1234));
    printf("%i -> (%i digits)\n", 3980000, count_digits_of_integer(3980000));
    printf("%i -> (%i digits)\n", 100, count_digits_of_integer(100));
    printf("%i -> (%i digits)\n", 9, count_digits_of_integer(9));
    printf("%i -> (%i digits)\n", 385784, count_digits_of_integer(385784));
    
    return 0;
}

输出:

0 -> (1 digits)
12 -> (2 digits)
34569 -> (5 digits)
1234 -> (4 digits)
3980000 -> (7 digits)
100 -> (3 digits)
9 -> (1 digits)
385784 -> (6 digits)

【讨论】:

    【解决方案2】:

    对于简单的程序...

    int num = 456, length=0 // or read value from the user to num
    while(num>0){
        num=num/10;
        length++;
    }
    

    使用另一个变量来保留初始num 值。

    【讨论】:

      【解决方案3】:
      // Variables 
      
      long c = 2222882;
      long b = c;
      float x = 10;
      int length = 0;
      
      //Loop to know the length
      
          for(int i = 0; b != 0; i++)
          {
              b = (float) c / x;
              x = x*10;
              length++;
          }
      //Print this one
          printf("%i", length);
      

      【讨论】:

      • 请在您的答案中添加一些上下文,以便其他人可以轻松理解您的方法。
      【解决方案4】:

      你为什么不把你的整数转换成 String 并得到这样的长度:

      int data = 123;
      int data_len = String(data).length();
      

      【讨论】:

        【解决方案5】:

        在这个问题中,我使用了一些算术解决方案。谢谢:)

        int main(void)
        {
            int n, x = 10, i = 1;
            scanf("%d", &n);
            while(n / x > 0)
            {
                x*=10;
                i++;
            }
            printf("the number contains %d digits\n", i);
        
            return 0;
        }
        

        【讨论】:

          【解决方案6】:

          请在一行代码中找到我的答案:

          #include <stdio.h> int main(void){ int c = 12388884; printf("length of integer is: %d",printf("%d",c)); return 0; }

          这是简单而聪明的! 喜欢的话点个赞吧!

          【讨论】:

          • 您的解决方案似乎也打印了数字本身,而不仅仅是长度!
          【解决方案7】:
          int returnIntLength(int value){
              int counter = 0;
              if(value < 0)
              {
                  counter++;
                  value = -value;
              }
              else if(value == 0)
                  return 1;
          
              while(value > 0){
                  value /= 10;
                  counter++;
              }
          
              return counter;
          }
          

          我认为这种方法非常适合这项任务:

          价值和答案:

          • -50 -> 3 //它会计算 - 如果你不想计算,也可以作为一个字符 减去然后从第 5 行删除 counter++。

          • 566666 -> 6

          • 0 -> 1

          • 505 -> 3

          【讨论】:

            【解决方案8】:

            这适用于消极和积极的intigers

                int get_len(int n)
                {
                    if(n == 0)
                    return 1;
            
                    if(n < 0)    
                    {
                       n = n * (-1); // if negative
                    }
            
                    return  log10(n) + 1;
                }
            

            同样的逻辑也适用于循环

              int get_len(int n)
              {
                   if(n == 0)
                   return 1;
            
                   int len = 0;
                   if(n < 0)
                   n = n * (-1);
            
                   while(n > 1)
                   {
                      n /= 10;
                      len++;
                   }
            
                   return len;
              }
            

            【讨论】:

              【解决方案9】:

              int main(void){ 无符号整数 n,大小=0;

              printf("get the int:");
              scanf("%u",&n);
              
              /*the magic*/
              for(int i = 1; n >= i; i*=10){
                  size++;
              }
              
              printf("the value is: %u \n", n);
              printf("the size is: %u \n", size);
              
              return 0;
              

              }

              【讨论】:

                【解决方案10】:

                更详细的方法是使用此函数。

                int length(int n)
                {
                    bool stop;
                    int nDigits = 0;
                    int dividend = 1;
                    do
                    {
                        stop = false;
                        if (n > dividend)
                        {
                            nDigits = nDigits + 1;
                            dividend = dividend * 10;
                        }
                        else {
                            stop = true;
                        }
                
                
                    }
                    while (stop == false);
                    return nDigits;
                }
                

                【讨论】:

                  【解决方案11】:

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

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

                  虽然它可能不会因为最巧妙的解决方案而获奖,但理解起来很简单,执行起来也很简单 - 所以速度很快。

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

                  int res = 0;
                  for(int i = -2000000000; i < 2000000000; i += 200) res += printLen(i);
                  

                  此解决方案耗时 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;
                          }
                      }
                  }
                  

                  这个解决方案在大数字上仍然是 0.062 秒,而对于较小的数字会降到 0.09 秒左右 - 在这两种情况下都比智能日志方法更快。 (gcc 使代码更快;此解决方案为 0.052,智能日志方法为 0.09s)。

                  【讨论】:

                  • 一想到完全用三元运算符编写的第二个版本会是什么样子,我不寒而栗……
                  • 如果这被用来咀嚼一长串数字,那么大量的分支代码会对 CPUs branch prediction and not produce the fastest execution Im 造成严重破坏。
                  • 在我的基准测试中,它仍然是最快的解决方案 - 请注意,所有其他积分解决方案也需要多个分支,唯一真正的替代方案是使用浮点日志进行 int-to-double 转换(因为它结果也不便宜)。
                  • @earthdan:该解决方案很好,但由于存在分歧而相当缓慢。它也总是使用比此代码的第二个版本更多的分支,并且平均比此处发布的第一个解决方案更多。此外,该解决方案非常聪明(以一种糟糕的方式),因为它起作用的原因并不完全明显。如果您想要一个简短+明显的解决方案,请使用stackoverflow.com/a/3068412/42921;如果您想要一个快速而明显的解决方案,请使用它。无法想象stackoverflow.com/a/6655759/2382629 的用例(尽管它当然是一个有趣的智力练习!)
                  【解决方案12】:

                  你可以用这个-

                  (data_type)log10(variable_name)+1

                  例如:

                  len = (int)log10(number)+1;

                  【讨论】:

                    【解决方案13】:

                    C:

                    为什么不直接取数字绝对值的以 10 为底的对数,四舍五入再加一?这适用于非 0 的正数和负数,并且避免使用任何字符串转换函数。

                    log10absfloor 函数由 math.h 提供。例如:

                    int nDigits = floor(log10(abs(the_integer))) + 1;
                    

                    您应该将其包装在一个子句中,确保the_integer != 0,因为log10(0) 根据man 3 log 返回-HUGE_VAL

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

                    Java:

                    int nDigits = Math.floor(Math.log10(Math.abs(the_integer))) + 1;
                    

                    注意此方法中涉及的计算的浮点性质可能会导致它比更直接的方法慢。有关效率的一些讨论,请参阅康坎答案的 cmets。

                    【讨论】:

                    • 其实你应该使用 floor 并添加 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
                    • 这个问题对长度的定义并不完全清楚(所以你可能会想到“不包括前导零的位数”),但我希望 0 和 -1 返回 1 和 2作为其字符表示的长度,而不是 -2147483648 和 1。
                    • @Pete 感谢您提醒我有关日志的域限制和负数情况 - 我已经编辑了答案。
                    • +1 nice & short - 这是我的首选答案,即使它是最慢的 - 毕竟,速度差异并不大,而且这种代码不太可能成为性能。无论如何都是瓶颈。
                    • 这不适用于 999999999999999999,这是一个 C 整数,它将被转换为更大的双精度值,从而产生错误的位数。 OP 没有指定int,只是整数。
                    【解决方案14】:
                    int digits=1;
                    
                    while (x>=10){
                        x/=10;
                        digits++;
                    }
                    return digits;
                    

                    【讨论】:

                      【解决方案15】:

                      n 的长度:

                      length =  ( i==0 ) ? 1 : (int)log10(n)+1;
                      

                      【讨论】:

                      • 您可能应该避免通过强制转换进行舍入,而是使用更明确(又名可移植且一致)的舍入方法。
                      • casting 是如何实现的?如何实现像地板这样的功能? (我们假设在硬件中具有 ieee 的处理器,或通过数学协处理器,或软件功能的可用性来执行通常存在于支持 fp 的处理器上的相同功能)......最后(int)是可移植的并且在大多数情况(我敢说,我们通常关心的所有情况)
                      • 如其他帖子中提到的,当n = 0时这将失败
                      • @Lutz:假设从 double 到 int 的转换是未定义的,您购买了什么样的可移植性?实际上是否有相关平台可以解决这种情况?
                      • @Chris Lutz 如果它是符合标准的 C 实现,那么它遵守 当实浮点类型的有限值转换为除 _Bool 以外的整数类型时,小数部分被丢弃(即,值被截断为零)。
                      【解决方案16】:
                      int intlen(int integer){
                          int a;
                          for(a = 1; integer /= 10; a++);
                          return a;
                      }
                      

                      【讨论】:

                        【解决方案17】:

                        我的方式:

                        只要数字不能被 10 整除,就除以:

                        u8 NumberOfDigits(u32 number)
                        {
                            u8 i = 1;
                            while (number /= 10) i++;
                        
                            return i;
                        }
                        

                        不知道跟其他命题比起来有多快..

                        【讨论】:

                          【解决方案18】:

                          在我看来,最短和最简单的解决方案是:

                          int length , n;
                          
                          printf("Enter a number: ");
                          
                          scanf("%d", &n);
                          
                          length = 0;
                          
                          while (n > 0) {
                             n = n / 10;
                             length++;
                          }
                          
                          printf("Length of the number: %d", length);
                          

                          【讨论】:

                          • 如果 (n) 等于 0,这将返回 (n) 的长度为 0。使用 do...while 所以循环在 (n) 等于 0 时执行一次。
                          【解决方案19】:

                          我认为我找到了找到整数长度的最有效方法 这是一种非常简单优雅的方式 在这里:

                          int PEMath::LengthOfNum(int Num)
                          {
                          int count = 1;  //count starts at one because its the minumum amount of digits posible
                          if (Num < 0)
                          {
                              Num *= (-1);
                          }
                          
                          for(int i = 10; i <= Num; i*=10)
                          {
                               count++;
                          }      
                          return count;
                                          // this loop will loop until the number "i" is bigger then "Num"
                                          // if "i" is less then "Num" multiply "i" by 10 and increase count
                                          // when the loop ends the number of count is the length of "Num".
                          }
                          

                          【讨论】:

                          • Num *= (-1) 似乎有点笨拙,尽管您的编译器可能会将其优化为更高效的Num = -Num。请注意,乘法通常是一项昂贵的操作,而对整数求反则非常简单。
                          • 不是 C 代码。不适用于 INT_MIN,也不适用于 INT_MAX,实际上不适用于大于或等于小于 INT_MAX 的 10 的最大幂的数字,例如 int32_t 的 1000000000。
                          【解决方案20】:
                          sprintf(s, "%d", n);
                          length_of_int = strlen(s);
                          

                          【讨论】:

                            【解决方案21】:

                            正确的snprintf 实现:

                            int count = snprintf(NULL, 0, "%i", x);
                            

                            【讨论】:

                            • 如果 x 为负数会怎样?
                            • 那么count 将有一个额外的减号单位。
                            【解决方案22】:

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

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

                            我的上网本上的 2000 万次调用需要 0.65 秒(可能为时过早);像 zed_0xff 这样的迭代除法需要 1.6 秒,像康坎这样的递归除法需要 1.8 秒,使用浮点函数(Jordan Lewis 的代码)需要高达 6.6 秒。使用 snprintf 需要 11.5 秒,但会给您 snprintf 任何格式所需的大小,而不仅仅是整数。 Jordan 报告说,他的处理器没有维护时序的顺序,它的浮点运算速度比我的快。

                            最简单的可能是向 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;
                            }
                            

                            【讨论】:

                            • 如果你要使用snprintf(),为什么不用snprintf(NULL, 0, "%d", x)而不写任何东西呢? (至少,在你的函数中使用静态缓冲区。)
                            • 因为今天早上我还没有喝够咖啡,正在思考答案的第一站。
                            • 这取决于你为什么想要长度 - 如果你想知道 snprintf 需要多少个字符,你最好使用 snprintf;如果你想要愚蠢的优化代码,你可能想要第一个。
                            • " C99 允许 str 在这种情况下为 NULL [n==0 的情况],并给出返回值(一如既往)作为如果输出字符串已经够大了”所以没关系,何乐而不为
                            • 您的解决方案不适用于INT_MIN。使用本地 unsigned 变量进行测试并使用 x &gt;= 0 ? x : -(unsigned)x 进行初始化
                            【解决方案23】:

                            继续除以十直到得到零,然后输出除数。

                            int intLen(int x)
                            {
                              if(!x) return 1;
                              int i;
                              for(i=0; x!=0; ++i)
                              {
                                x /= 10;
                              }
                              return i;
                            }
                            

                            【讨论】:

                            • 这是不正确的。如果 x = 0,这将返回一个任意数字。
                            • 打赌它不会...但是它会返回错误的 0 值。
                            • @phleet,我很确定 i=0 之后的分号是一个序列点,但零仍然是错误的输出。不过现在已经修好了。
                            【解决方案24】:
                            int get_int_len (int value){
                              int l=1;
                              while(value>9){ l++; value/=10; }
                              return l;
                            }
                            

                            第二个也适用于负数:

                            int get_int_len_with_negative_too (int value){
                              int l=!value;
                              while(value){ l++; value/=10; }
                              return l;
                            }
                            

                            【讨论】:

                            • 我喜欢这个。没有假设大小的临时字符缓冲区。
                            • 快速而优雅,但是,这不适用于负数。不知道这是否是问题海报的关注点
                            • 会的。试一试。它将返回 1
                            • 你是对的 - 它确实会:-)。通过 if-return 而不是否定来区分这种情况对我来说会更清楚(并且不会更慢)。
                            【解决方案25】:

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

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

                            int numDigits = 0;
                            do
                            {
                                ++numDigits;
                                x = x / 10;
                            } while ( x );
                            

                            如果整数是0 在第一个解决方案中返回1,您必须小心一点,并且您可能还想处理负整数(如果x &lt; 0 使用-x)。

                            【讨论】:

                            • 是的,一个不错的简单 do 循环。
                            【解决方案26】:

                            很简单

                            int main() {
                                int num = 123;
                                char buf[50];
                            
                                // convert 123 to string [buf]
                                itoa(num, buf, 10);
                            
                                // print our string
                                printf("%s\n", strlen (buf));
                            
                                return 0;
                            }
                            

                            【讨论】:

                            • 不过写起来很容易
                            【解决方案27】:

                            你可以这样写一个函数:

                            unsigned numDigits(const unsigned n) {
                                if (n < 10) return 1;
                                return 1 + numDigits(n / 10);
                            }
                            

                            【讨论】:

                            • 这是不必要的低效——当你可以通过一次调用 log10 来完成时,为什么还要使用大约 18 个递归函数调用?
                            • @Jordan Lewis 在我的上网本上调用这 2000 万次需要 1.8 秒;调用您的代码需要 6.6 秒(两者都是 gcc -O3)。对 log10 的一次调用比它进行的所有递归调用要慢得多。
                            • @Pete 我在我的 Intel i7 上看到 log10 版本的 .001s 和递归版本的 .44s,使用 -O3 2000 万次。
                            • @Jordan 我在开头添加了if ( x &lt; 0 ) return 1 + printed_length ( -x );
                            • @Pete 我一定犯了一个错误,导致编译器优化了之前的实际调用。我现在观察到像您这样的差距 - 递归版本为 0.26 秒,浮点算术版本为 1.68 秒。有趣!
                            【解决方案28】:

                            是的,使用 sprintf。

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

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

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

                            【讨论】:

                            • 不,这实际上相当危险并且容易出错。你应该使用snprintf(),这样你就不必写任何东西(并冒着溢出的风险)。
                            • 假设他指的是一个 C 整数(不是 bignum 类型),溢出不会有任何问题。
                            • 电脑变大会出问题。当然,您需要一台 512 位计算机来破解您的代码,但他们可能有一天会制造出来。
                            • 不,很可能 128 位将成为最后的边界……没有任何理由超越(夸张地说,我说没有理由超越 64 位,但我是 几乎已经错了,但目前还没有真正的 128 位处理器可用,而且它们几乎不会出现,至少在消费者计算中......我希望,因为他们需要它们,这意味着操作系统也会脂肪,我们会记住这些日子是更好的日子)
                            • 你可以简单地使用sprintf()的返回值而不调用strlen()
                            猜你喜欢
                            • 2016-08-04
                            • 1970-01-01
                            • 2011-01-31
                            • 2010-11-03
                            • 2014-05-04
                            • 2017-04-15
                            • 2011-05-10
                            • 2015-02-22
                            • 1970-01-01
                            相关资源
                            最近更新 更多