16.4 整數轉成進制字串
反方向:手上有一個整數,要印出它的 K 進制長相。
這次從個位下手。「滿 K 進位」代表個位就是「湊不滿一個 K 的零頭」——也就是 x % K(2.6 的取餘數);而 x / K 是整數除法,恰好把個位丟掉、留下其餘所有位。十進制直覺一秒懂:3072 % 10 是個位 2,3072 / 10 是 307。所以反覆「取個位、去個位」,就能把每一位依序剝下來。拿 26 轉二進制走一遍:
| 回合 | x | 取出 x % 2 |
剩下 x / 2 |
|---|---|---|---|
| 1 | 26 | 0 | 13 |
| 2 | 13 | 1 | 6 |
| 3 | 6 | 0 | 3 |
| 4 | 3 | 1 | 1 |
| 5 | 1 | 1 | 0 |
x 歸零,結束。取出的順序是 0、1、0、1、1——由低位到高位,但人類寫數字是高位在前:答案 (11010)_2 得把取出順序整個顛倒才對。
把取出的位轉回字元是 8.2 加法方向的活:'0' + d;10 以上換字母,'A' + (d - 10):
char digitToChar(int d) {
if (d < 10) return '0' + d;
return 'A' + (d - 10); // 10 -> 'A'、11 -> 'B'……
}
「顛倒」則交給一個新朋友——<algorithm> 函式庫的 reverse:
reverse(ans.begin(), ans.end()); // 把整段內容前後顛倒
它跟 11.4 的 sort 是同鄉,吃一對「範圍」參數(10.5 的 begin/end),把範圍內的東西整個前後翻面,string 與 vector 都能用。不想用它,倒著印也完全可以:
for (int i = (int)ans.size() - 1; i >= 0; i--) cout << ans[i]; // 倒著印
¶方向一:由低位至高位(推薦)
把上面的材料組起來,就是本節的主做法——輸入進制 K 與十進制整數 x,輸出 x 的 K 進制長相:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
// 數值 -> 進制位字元:0~9 用 8.2 的加法,10 以上換字母
char digitToChar(int d) {
if (d < 10) return '0' + d;
return 'A' + (d - 10);
}
int main() {
int K;
long long x;
cin >> K >> x; // 把十進制的 x 轉成 K 進制輸出
if (x == 0) { // 特判:x 是 0 時迴圈一次都不會跑
cout << 0 << '\n';
return 0;
}
string ans;
while (x > 0) {
ans += digitToChar(x % K); // 取出個位,接到字串尾端
x /= K; // 去掉個位
}
reverse(ans.begin(), ans.end()); // 低位先取出來:整串顛倒回正
cout << ans << '\n';
return 0;
}
執行結果(輸入 16 與 3072):
C00
換輸入 2 與 3072 會得到 110000000000——跟 16.2 開頭寫的一致。
¶方向二:由高位至低位
跟上一節一樣,這個方向也有「從高位開始」的版本:先找出最高位的位值 now,再由高位往低位一位一位「數」——x / now 是這一位的數字、x %= now 留下零頭給更低的位:
#include <iostream>
#include <string>
using namespace std;
char digitToChar(int d) {
if (d < 10) return '0' + d;
return 'A' + (d - 10);
}
int main() {
int K;
long long x;
cin >> K >> x;
if (x == 0) { // 一樣要特判 0
cout << 0 << '\n';
return 0;
}
long long now = 1; // now = 最高位的位值
while (now <= x / K) now *= K; // 想寫 now * K <= x,改比 x / K 防止乘法溢位(2.9)
string ans;
while (now > 0) {
ans += digitToChar(x / now); // 這一位的數字:x 裡裝了幾個 now
x %= now; // 拿掉這一位,剩下的留給更低位
now /= K; // 位值降一級
}
cout << ans << '\n';
return 0;
}
輸出順序天生就是高位在前,不用反轉;代價是得先用一個迴圈找 now,而且找的過程要小心溢位——註解裡把 now * K <= x 改寫成 now <= x / K,就是為了讓比較式裡永遠不出現可能爆範圍的乘法。兩版都會用最好,日常推薦方向一:短、直覺、坑少。
動手試試看:解掉進制轉換——給你 A 進制的字串,要求輸出 B 進制。完整路線:先用 16.3 把字串轉成 long long,再用本節把它印成 B 進制。注意 2 \le A, B \le 36(字母會用到 Z,charToDigit/digitToChar 的字母分支本來就管到 35),且數值上看 10^{18}——累積變數務必 long long。