获取整数中的数字个数

21

如何检测整数的长度?比如我有这样一个整数:int test(234567545);

我怎样知道这个整数的长度?想知道其中有9个数字吗?

*我尝试过的方法:

char buffer_length[100];


    //  assign directly to a string.

    sprintf(buffer_length, "%d\n", 234567545);

    string sf = buffer_length;


    cout <<sf.length()-1 << endl;

但一定有更简单或更清晰的方法可以做到这一点...


7
一个想法:如何处理负数? - Joey
3
在这里为什么需要 std::string?你可以直接使用 strlen(buffer_length)。你也不需要 \n,因此也不需要 -1 - leemes
可能是重复问题: https://dev59.com/zXI_5IYBdhLWcg3wMf5_ - Rishi
5
C和C++是不同的编程语言。一个数字本身没有数字,只有它的十进制表示才有数字。 - Basile Starynkevitch
简单来说,使用 snprintf() 技巧,例如 int needed = snprintf (NULL, 0, "%d", 234567545); 参见man 3 printf 中 "RETURN VALUE" 第二段的第二句话。 - David C. Rankin
10个回答

44

除法怎么样:

int length = 1;
int x = 234567545;
while ( x /= 10 )
   length++;

或者使用<math.h>中的log10方法。

注意log10返回一个double,因此您需要调整结果。


谢谢! :) 这正是我需要知道的。 - user1417815
4
注意,log(0)的结果为负无穷大,在将其转换为整数时会产生未定义行为。 - Potatoswatter

11

创建一个函数:

int count_numbers ( int num) {
   int count =0;
   while (num !=0) {   
      count++;  
      num/=10;
   } 
   return count;
}

2
我认为我们可以在while之前添加一个简单的if。 - Shehzad Bilal
1
你的函数能够正常工作,但是有点晚了。不过这并不妨碍我给你一个赞! - user1417815
3
еҰӮжһңnum==0пјҢеҲҷеә”иҝ”еӣһ1пјҢеӣ дёәе®ғеҸӘжңүдёҖдҪҚж•°еӯ—гҖӮ - shinzou

9
没人提到将其转换为字符串,然后获取长度。虽然不是最高效的方法,但绝对可以在一行代码中完成 :)
int num = -123456;
int len = to_string(abs(num)).length();

cout << "LENGTH of " << num << " is " << len << endl;    
// prints "LENGTH of 123456 is 6"

只需检查负值即可 ;) - Blood-HaZaRd
@Blood-HaZaRd - 哈哈.. 你是对的... 把它改成 int len = to_string(abs(num)).length(); - jmg
2
除了原帖的作者,好像没有人提到过这个问题? :-) - Steve Summit

5
您可以使用以下代码中所示的 stringstream 进行操作。
stringstream ss;
int i = 234567545;
ss << i;
cout << ss.str().size() << endl;

4

如果 "i" 是整数,则

int len ;

char buf[33] ;

itoa (i, buf, 10) ; // or maybe 16 if you want base-16 ?

len = strlen(buf) ;

if(i < 0)
    len-- ;    // maybe if you don't want to include "-" in length ?

buf[12] 应该足够了(最多10个数字+符号+'\0')。 - leemes

4
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {

    int i=2384995;
    char buf[100];

    itoa(i, buf, 10); // 10 is the base decimal

    printf("Lenght: %d\n", strlen(buf));


    return 0;
}

注意,itoa不是标准函数,尽管许多编译器都支持它。


1
buf[12] 应该足够了(最多10个数字 + 符号 + '\0')。 - leemes

2

len=1+floor(log10(n));//c++ code lib (cmath)


5
为什么贫穷的数字0没有爱? - Revolver_Ocelot

1
在浏览互联网时,常见的错误是将计数器变量初始化为0,然后进入一个预条件循环,测试是否计数不等于0。使用do-while循环可以完美避免这种情况。
    unsigned udc(unsigned u) //unsigned digit count
    {
      unsigned c = 0;
      do
        ++c;
      while ((u /= 10) != 0);
      return c;
    }

我建议您在测试u是否小于10时进行优化,这样可以避免不必要的除法、增量和比较操作。

此外,在优化方面,您还可以将u与常数幂次的ten进行比较。

    unsigned udc(unsigned u) //unsigned digit count
    {
      if (u < 10)   return 1;
      if (u < 100)  return 2;
      if (u < 1000) return 3;
      //...
      return 0; //number was not supported
    }

这种方法每个数字可以节省3条指令,但适应不同的基数较差,而且不够美观,手写起来也很繁琐。在这种情况下,您最好编写一个例程来编写程序之前的例程。因为C只支持非常有限的数字,64位32位16位8位,在生成例程时,您可以将自己限制在最大值以使所有大小都受益。
要考虑负数,您只需在计算数字数量之前,如果u < 0,就简单地对u进行取反。当然,首先要使例程支持有符号数。
如果您知道u < 1000,那么直接编写而不是编写例程可能更容易。
   if (u > 99) len = 3;
   else
   if (u > 9)  len = 2;
   else        len = 1;

0

这里有几个不同的C++实现*,它们都是一个名为digits()的函数,该函数以size_t为参数并返回其数字的数量。如果您的数字是负数,则必须将其绝对值传递给函数,以便它正常工作:

While循环

int digits(size_t i)
{
    int count = 1;
    while (i /= 10) {
        count++;
    }
    return count;
}

穷举优化技术

int digits(size_t i) {
    if (i > 9999999999999999999ull) return 20;
    if (i > 999999999999999999ull) return 19;
    if (i > 99999999999999999ull) return 18;
    if (i > 9999999999999999ull) return 17;
    if (i > 999999999999999ull) return 16;
    if (i > 99999999999999ull) return 15;
    if (i > 9999999999999ull) return 14;
    if (i > 999999999999ull) return 13;
    if (i > 99999999999ull) return 12;
    if (i > 9999999999ull) return 11;
    if (i > 999999999ull) return 10;
    if (i > 99999999ull) return 9;
    if (i > 9999999ull) return 8;
    if (i > 999999ull) return 7;
    if (i > 99999ull) return 6;
    if (i > 9999ull) return 5;
    if (i > 999ull) return 4;
    if (i > 99ull) return 3;
    if (i > 9ull) return 2;
    return 1;  
}

递归的方式

int digits(size_t i) { return i < 10 ? 1 : 1 + digits(i / 10); }

使用 snprintf() 作为字符计数器

⚠ 需要 #include <stdio.h>,与其他解决方案相比可能会产生显著的性能损失。这种方法利用了 snprintf() 在缓冲区满时丢弃的字符数量。因此,通过正确的参数和格式说明符,我们可以强制 snprintf() 给出任何 size_t 的数字位数。

int digits(size_t i) { return snprintf (NULL, 0, "%llu", i); }

对数方法

⚠ 需要 #include <cmath>,对于超过14位数字的无符号整数不可靠。

// WARNING! There is a silent implicit conversion precision loss that happens
// when we pass a large int to log10() which expects a double as argument.
int digits(size_t i) { return !i? 1 : 1 + log10(i); }

驱动程序

您可以使用此程序测试任何取size_t为参数并返回其数字个数的函数。只需替换以下代码中digits()函数的定义:

#include <iostream>
#include <stdio.h>
#include <cmath>
#include <chrono>
using std::cout;
using namespace std::chrono;

// REPLACE this function definition with the one you want to test.
int digits(size_t i)
{
    int count = 1;
    while (i /= 10) {
        count++;
    }
    return count;
}

// driver code
int main ()
{
    const int max = digits(~0ull);
    size_t i = 0, d;
    do {
        auto t0 = high_resolution_clock::now();
        d = digits(i);
        auto t1 = high_resolution_clock::now();
        duration<double, std::nano> te = t1 - t0;
        cout << i << " has " << d << " digits (" << te.count() << " ns).\n";
        i = d < max ? (!i ? 9 : 10 * i - 1) : ~0ull;
        t0 = high_resolution_clock::now();
        d = digits(i);
        t1 = high_resolution_clock::now();
        te = t1 - t0;
        cout << i << " has " << d << " digits (" << te.count() << " ns).\n";
    } while (++i);
}

* 所有内容都是在 Windows 10 (64位) 的机器上使用 Visual Studio Code 中的 GCC 12.2.0 进行测试的。


结果是什么?哪个最快? - Tom Tom
@TomTom 我已经修改了驱动程序代码,以显示该函数返回数字数量所需的时间。我无法找到最快的方法。你能告诉我你的用例吗? - q-l-p
我需要从一个返回浮点数的函数中计算数字。范围在FLOAT_MAX和FLOAT_MIN之间,需要计算10,000个随机值。 - Tom Tom

0
只要您混合使用C stdio和C++ iostream,就可以使用snprintf NULL 0技巧来获取数字的整数表示中的位数。具体而言,请参见man 3 printf,如果字符串超过提供的大小参数并被截断,则snprintf()将返回。
   ... the number of characters (excluding the terminating null byte)
   which would have been written to the final string if enough space
   had been available.

这允许使用snprintf(),并将str参数设置为NULL,将size参数设置为0,例如:

    int ndigits = snprintf (NULL, 0, "%d", 234567545)

在您仅希望输出所需表示的数字数量的情况下,您可以简单地输出返回值,例如:
#include <iostream>
#include <cstdio>

int main() {

  std::cout << "234567545 is " << snprintf (NULL, 0, "%d", 234567545) <<
               " characters\n";

}

示例使用/输出

$ ./bin/snprintf_trick
234567545 is 9 characters

注意:使用snprintf()技巧的缺点是必须提供转换说明符,这将限制可表示的数字位数。例如,"%d"将限制为int值,而"%lld"则会为long long值留出空间。使用std::stringstream的C++方法虽然仍然仅限于使用<<运算符进行数值转换,但可以处理不同的整数类型,无需手动指定转换方式。这是需要考虑的一些事情。

第二个注意点:不应该在sprintf()转换的末尾悬挂"\n"。将换行符作为输出的一部分添加即可,您不必从长度中减去1...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接