最稳的求位数方法是循环除10:先特判0返回1,再将n转为unsigned int处理负数(含INT_MIN),然后while(n>0){n/=10;count++;},避免log10的浮点误差、未定义行为及溢出风险。

用 log10 求位数会出错,别信网上抄的“一行解”
直接对 abs(n) 调用 log10 再加 1,看似简洁,但遇到 0、负数边界(如 INT_MIN)、浮点精度误差时全崩。比如 log10(1000) 理论返回 3,实际可能算出 2.9999999,floor 后变 2,结果少一位。
-
0必须单独处理——log10(0)是未定义行为,运行时崩溃或返回-inf - 负数取
abs有风险:INT_MIN取反溢出(如 32 位系统中abs(-2147483648)仍是 -2147483648) -
log10是浮点运算,依赖<cmath></cmath>,还引入额外链接和精度不确定性
最稳的写法:循环除 10,兼容所有 int 值
不依赖数学库、不碰浮点、不假设正负,只用整数除法,逻辑清晰且无死角。
- 先特判
0→ 位数为 1 - 用
unsigned int处理负数:把n强转成unsigned int,再取绝对值(static_cast<unsigned int>(n)</unsigned>对INT_MIN是明确定义的,按位解释,不会溢出) - 循环
while (n > 0) { n /= 10; count++; },比字符串转换快一个数量级,也省内存
示例:
int digit_count(int n) {
if (n == 0) return 1;
unsigned int u = static_cast<unsigned int>(n);
if (n < 0) u = -u; // 注意:这里 -u 在 unsigned 下是模运算,等价于 2^32 + n(对 INT_MIN 正确)
int count = 0;
while (u > 0) {
++count;
u /= 10;
}
return count;
}
想用字符串?std::to_string 简单但有隐性开销
适合调试或低频调用,不适合热循环。它会动态分配内存、构造 std::string 对象,还涉及 locale 和格式化逻辑。
立即学习“C++免费学习笔记(深入)”;
- 对
INT_MIN安全,因为std::to_string明确支持全范围int - 返回字符串含负号,所以得用
s[0] == '-' ? s.length() - 1 : s.length() - 性能比除法慢 5–10 倍(实测 clang 15 / x86-64),且触发堆分配
仅建议这样写:
int digit_count_str(int n) {
auto s = std::to_string(n);
return s[0] == '-' ? s.length() - 1 : s.length();
}
模板函数支持 long long?小心 /= 10 的类型匹配
如果想泛化到更大整型,别直接套用 int 版本。比如传入 long long,但循环里用 int 计数或中间变量,可能截断。
- 计数变量必须和输入同宽或更宽(如用
int足够,因为最多 20 位,但显式用unsigned更稳妥) - 除法操作要保持类型一致:
auto u = static_cast<unsigned long>(n)</unsigned>,否则u /= 10可能隐式降级 - 不要用
sizeof(T)估算最大位数——不同平台long long都是至少 64 位,但位数上限固定(19 或 20),硬编码反而更准
C++ 里求 int 位数这事,表面简单,实际卡点全在边界:0、负最小值、类型转换语义、浮点不可靠。选循环除法不是因为它“原始”,而是它把所有不确定因素都关在整数算术的确定世界里。










