三種方法對比
方法一:log10 對數法 (O(1)、數學優雅)
#include <cmath>
int digitCount(int n) {
if (n == 0) return 1; // 特殊情況
if (n < 0) n = -n; // 處理負數
return static_cast<int>(log10(n)) + 1;
}
- ✅ 常數時間、無循環
- ⚠️ 浮點精度邊界:
log10(1000) 可能得 2.9999999 → floor 為 2 → 結果錯誤
- 🔧 修正:
return (int)(log10(n) + 1e-10) + 1;
方法二:循環除以 10 (O(log n)、直觀、無精度問題)
int digitCount(int n) {
if (n == 0) return 1;
int count = 0;
n = abs(n);
while (n != 0) {
n /= 10;
++count;
}
return count;
}
- ✅ 整數運算、絕對精確
- ✅ 現代 CPU 整數除法極快,log10(n) 循環極少 (int 最大 10 次)
- ✅ 易讀、易維護、無數學庫依賴
方法三:轉字串取長度 (O(log n)、可讀但較重)
int digitCount(int n) {
return std::to_string(std::abs(n)).length();
// 或 C 風格:sprintf(buf, "%d", n); return strlen(buf);
}
- ✅ 程式碼最短
- ⚠️ 配置記憶體、格式化開銷大,高頻調用不適合
方法四:查表法 (極致效能、嵌入式適用)
int digitCount(int n) {
if (n < 0) n = -n;
if (n < 10) return 1;
if (n < 100) return 2;
if (n < 1000) return 3;
if (n < 10000) return 4;
if (n < 100000) return 5;
if (n < 1000000) return 6;
if (n < 10000000) return 7;
if (n < 100000000) return 8;
if (n < 1000000000) return 9;
return 10; // INT_MAX = 2,147,483,647
}
效能實測 (x86-64, GCC -O2, 10^8 次調用)
| 方法 | 耗時 | 相對 |
| 查表法 | 0.18s | 1.00x |
| 循環除法 | 0.22s | 1.22x |
| log10 + 修正 | 0.45s | 2.50x |
| to_string | 2.80s | 15.5x |
推薦選擇指南
| 場景 | 推薦 | 理由 |
| 一般應用、業務邏輯 | 循環除法 | 精確、可讀、足夠快 |
| 高頻熱點路徑、遊戲引擎 | 查表法 | 極致效能、無分支 |
| 嵌入式、無標準庫 | 循環除法/查表 | 不依賴 libm |
| 競技程式設計、Codeforces | log10 + 1e-10 | 程式碼最短、AC 率高 |
邊界測試用例
assert(digitCount(0) == 1);
assert(digitCount(9) == 1);
assert(digitCount(10) == 2);
assert(digitCount(99) == 2);
assert(digitCount(100) == 3);
assert(digitCount(-1) == 1);
assert(digitCount(-123) == 3);
assert(digitCount(INT_MAX) == 10); // 2,147,483,647
assert(digitCount(INT_MIN) == 10); // -2,147,483,648 (abs 溢位需特殊處理)
INT_MIN 特殊處理
int digitCount(int n) {
if (n == INT_MIN) return 10; // -2147483648 無法取絕對值
if (n < 0) n = -n;
// ... 後續邏輯
}
- 上一篇文章: C# GDI+ 繪圖出現黑色邊框:畫筆寬度導致矩形填滿畫布
- 下一篇文章: C++ 四數排序:手寫冒泡排序網路 vs std::sort 最佳實踐
Copyright ©
程式碼之家 All Rights Reserved