C++ - 如何找到整数的长度

31

我正在寻找一种方法来确定整数的长度(数字个数)并将其放置在一个整数数组中。该任务还要求在不使用STL类的情况下完成,尽管程序规范说我们可以使用“常见的C库”(我打算问我的教授是否可以使用cmath库,因为我认为log10(num) + 1是最简单的方法,但我想知道是否还有其他方法)。

啊,这个程序不必处理负数。只处理非负数。

我正试图创建一个“MyInt”类的变体,使用动态数组处理更广泛范围的值。任何提示都将不胜感激!谢谢!


1
@KerrekSB 实际上我认为他指的是总无符号值。那应该是2的(sizeof(int)*8-1)次方,对吧?编辑:没事了。 - Ben
3
一个十进制整数的位数是 (log(number) / log(10))。 - Thomas Matthews
1
不要重复造轮子,使用“大数”库。在网上搜索“c++大数库”。 - Thomas Matthews
1
int len = n?0:1; while (n) { len++, n/=10 } - sehe
1
谢谢你的建议,Thomas,但这实际上是一项课程作业,对于一个新手来说是一个小小的编程挑战! - user1888527
17个回答

44

不一定是最高效的,但以下是使用C++编写的最短且最易读的代码之一:

std::to_string(num).length()

3
这个问题字面意思是“这不必处理负数”。 - Riot
7
这个解决方案符合要求,并且还能处理负数。 xD - smsware

39
在任何进制下,整数 n 的位数可以通过除法轻松获得:

将该数一直除以进制数,直到商为零为止。

unsigned int number_of_digits = 0;

do {
     ++number_of_digits; 
     n /= base;
} while (n);

1
没有理由使用这个解决方案,因为基于log10的解决方案要好得多。 - tleb
@tleb:更好的意义是什么?你比较过这两种方法吗? - Kerrek SB
比起使用 log10 的解决方案,我更喜欢这个,但为了可读性,我更希望使用一个更明确的 while (n != 0)。不过,这仍然值得点赞。 - paxdiablo

28
有一种更好的方法来做这件事
    #include<cmath>
    ...
    int size = trunc(log10(num)) + 1
....

适用于整数和小数。
更新日期:2023年7月27日
我们可以使用这行代码来检查负数和零值。
int size = num == 0 ? 1 : (num < 0 ? static_cast<int>(log10(std::abs(num))) + 1 : static_cast<int>(log10(num)) + 1);

1
我喜欢这个(因此点赞),只是不幸的是它不能处理数字零... - Abdel Aleem
我同意这是一个非常好的答案,值得点赞。如果您的用例不期望或已经有防范措施来避免零出现,那么这是最佳解决方案。 - Arrowkill
但是当num==0时,你会遇到问题。 log10(0)是未定义的。 - Refael

11

如果您可以使用C库,那么一种方法是使用sprintf函数,例如:

#include <cstdio>

char s[32];

int len = sprintf(s, "%d", i);

10
你可以使用snprintf(nullptr, 0, "%d", i)来代替s,无需使用s - Tony Delroy
1
这对于128位整数也不起作用。@Tony提供的nullptr解决方案可以解决这个问题。 - paxdiablo

9

"我的意思是整数中数字的数量,比如说'123'的长度为3"

int i = 123;

// the "length" of 0 is 1:
int len = 1;

// and for numbers greater than 0:
if (i > 0) {
    // we count how many times it can be divided by 10:
    // (how many times we can cut off the last digit until we end up with 0)
    for (len = 0; i > 0; len++) {
        i = i / 10;
    }
}

// and that's our "length":
std::cout << len;

输出 3


4

计算最长int的闭合公式(这里使用int,但适用于任何有符号整型):

1 + (int) ceil((8*sizeof(int)-1) * log10(2))

解释:

                  sizeof(int)                 // number bytes in int
                8*sizeof(int)                 // number of binary digits (bits)
                8*sizeof(int)-1               // discount one bit for the negatives
               (8*sizeof(int)-1) * log10(2)   // convert to decimal, because:
                                              // 1 bit == log10(2) decimal digits
    (int) ceil((8*sizeof(int)-1) * log10(2))  // round up to whole digits
1 + (int) ceil((8*sizeof(int)-1) * log10(2))  // make room for the minus sign

对于一个4字节的int类型,结果为11。一个有11个十进制数字的4字节int的例子是:“-2147483648”。
如果您想要某个int值的十进制位数,可以使用以下函数:
unsigned base10_size(int value)
{
    if(value == 0) {
        return 1u;
    }

    unsigned ret;
    double dval;
    if(value > 0) {
        ret = 0;
        dval = value;
    } else {
        // Make room for the minus sign, and proceed as if positive.
        ret = 1;
        dval = -double(value);
    }

    ret += ceil(log10(dval+1.0));

    return ret;
}

我在g++ 9.3.0(x86-64)下测试了整个int范围的函数。


3
ceil(log10(var+1))在INT_MAX的情况下会失败。 (意思是取一个整数变量 var 的位数时,使用这个公式会出错,因为 INT_MAX 已经超出了该数据类型能表示的最大值,导致公式计算失败) - bricklore
这不是可靠的,类型的最大值会失败。完全同意bricklore的观点。我更喜欢像Riot说的那样使用std::to_string(num).length()。 - 123iamking
通过在加1之前转换为“double”来解决“INT_MAX”的问题。 - lvella

3
int intLength(int i) {
    int l=0;
    for(;i;i/=10) l++;
    return l==0 ? 1 : l;
}

这里有一个小巧高效的代码。

你必须保存 i == 0 的情况,这也是1,当前函数返回0; - sergio

2
这种方法是否高效?将其转换为字符串并查找长度属性?
int num = 123  
string strNum = to_string(num); // 123 becomes "123"
int length = strNum.length(); // length = 3
char array[3]; // or whatever you want to do with the length

虽然不是很高效。 - ranu

2

最好的方法是使用日志查找,它总是有效的。

int len = ceil(log10(num))+1;

1
对于num==50,log10(50) ~= 1.7,ceil(1.7) = 2加1得3。使用ceil向上取整是错误的方法。 - Paul Floyd
你应该截断而不是四舍五入。 - Abdel Aleem

2

以下是针对0和负数同样适用的解决方案:

int digits( int x ) { 
    return ( (bool) x * (int) log10( abs( x ) ) + 1 );
}

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