GESP 5级
任意进制转换
5级 · 基础算法与数据类型
📖 什么是进制转换?
在日常生活中,我们最熟悉的数字系统是十进制(逢十进一),用 0~9 这十个数字来表示所有数。但计算机底层只认二进制(逢二进一),只用 0 和 1 两个数字。此外,还有八进制(0~7)、十六进制(0~9 和 A~F)等。
进制转换,就是把一个数从"一种计数方式"翻译成"另一种计数方式"。比如数字 255,在十进制里写作 255,在十六进制里写作 FF,在二进制里写作 11111111——它们表示的是同一个数量。
🌟 为什么重要?
- 考试高频考点:GESP 5级几乎每次都会考进制转换相关题目,尤其是十进制转二进制/十六进制。
- 计算机基础:理解二进制是理解计算机如何存储数据的关键。颜色值 #FF0000(红色)就是十六进制。
- 编程实用:网络编程中 IP 地址的子网掩码就是二进制运算;调试时经常需要看十六进制的内存数据。
- 竞赛基础:很多竞赛题涉及位运算,而位运算的基础就是理解二进制表示。
📋 前置知识
- ✅ 基本的数学除法和取余运算(
%运算符) - ✅ 简单的循环结构(
while/for) - ✅ 字符串的基本操作(拼接、拼到头部)
- ✅ 了解什么是二进制(0和1组成的数)
💡 如果你还不熟悉二进制的含义,建议先看 GESP 4级相关知识点。
🔢 理解不同进制
先来看看同一个数在不同进制下的写法:
十进制 255
二进制:11111111(8个1)
八进制:377
十六进制:FF
二进制:11111111(8个1)
八进制:377
十六进制:FF
核心思想:不同进制只是同一个数字的不同"写法",就像"中国"和"China"指的是同一个国家。
每种进制的"位权"不同:
十进制:从右往左,每一位的权重是 1, 10, 100, 1000...
例如:123 = 1×100 + 2×10 + 3×1
二进制:从右往左,每一位的权重是 1, 2, 4, 8, 16...
例如:101 = 1×4 + 0×2 + 1×1 = 5(十进制)
十六进制:从右往左,每一位的权重是 1, 16, 256, 4096...
例如:1A = 1×16 + 10×1 = 26(十进制)
例如:123 = 1×100 + 2×10 + 3×1
二进制:从右往左,每一位的权重是 1, 2, 4, 8, 16...
例如:101 = 1×4 + 0×2 + 1×1 = 5(十进制)
十六进制:从右往左,每一位的权重是 1, 16, 256, 4096...
例如:1A = 1×16 + 10×1 = 26(十进制)
记忆技巧:N进制的每一位,从右往左分别是 N⁰, N¹, N², N³... 位置越往左,价值越高。
🔄 十进制 → N进制:除N取余法
方法:把十进制数不断除以目标进制 N,每次取余数,最后把余数倒着拼起来。
就像"拆包裹"一样,每次拆出最低位,最后倒序排列。
📐 核心公式 / 关键要点
步骤:
1. n % base → 得到最低位的数字
2. n /= base → 去掉已取出的最低位
3. 重复直到 n == 0
4. 把收集到的余数倒序排列就是答案
1. n % base → 得到最低位的数字
2. n /= base → 去掉已取出的最低位
3. 重复直到 n == 0
4. 把收集到的余数倒序排列就是答案
手算示例:十进制 25 → 二进制
25 ÷ 2 = 12 ... 余 1 ← 最低位
12 ÷ 2 = 6 ... 余 0
6 ÷ 2 = 3 ... 余 0
3 ÷ 2 = 1 ... 余 1
1 ÷ 2 = 0 ... 余 1 ← 最高位
余数倒序排列:11001
验证:1×16 + 1×8 + 0×4 + 0×2 + 1×1 = 25 ✅
12 ÷ 2 = 6 ... 余 0
6 ÷ 2 = 3 ... 余 0
3 ÷ 2 = 1 ... 余 1
1 ÷ 2 = 0 ... 余 1 ← 最高位
余数倒序排列:11001
验证:1×16 + 1×8 + 0×4 + 0×2 + 1×1 = 25 ✅
手算示例:十进制 255 → 十六进制
255 ÷ 16 = 15 ... 余 15 → 用 F 表示
15 ÷ 16 = 0 ... 余 15 → 用 F 表示
余数倒序:FF
验证:15×16 + 15×1 = 255 ✅
15 ÷ 16 = 0 ... 余 15 → 用 F 表示
余数倒序:FF
验证:15×16 + 15×1 = 255 ✅
💻 代码示例:十进制转任意进制
#include <iostream>
#include <string>
using namespace std;
// 十进制整数 n 转换为 base 进制的字符串
// base 可以是 2(二进制)、8(八进制)、16(十六进制)等
string toBase(int n, int base) {
// 特殊情况:如果 n 就是 0,直接返回 "0"
if (n == 0) return "0";
string res = ""; // 用来存放结果字符串
while (n > 0) { // 只要 n 还不为 0,就继续除
int r = n % base; // r 是当前最低位的数字(余数)
// 余数 0~9 直接转成字符 '0'~'9'
// 余数 10~15 转成字符 'A'~'F'(十六进制需要)
if (r < 10) {
res = char('0' + r) + res; // 拼到字符串前面(倒序)
} else {
res = char('A' + r - 10) + res;
}
n /= base; // 去掉已取出的最低位,准备取下一位
}
return res;
}
int main() {
cout << toBase(255, 16) << endl; // 输出: FF
cout << toBase(255, 2) << endl; // 输出: 11111111
cout << toBase(255, 8) << endl; // 输出: 377
cout << toBase(42, 2) << endl; // 输出: 101010
cout << toBase(0, 16) << endl; // 输出: 0
return 0;
}
🔢 N进制 → 十进制:按权展开法
方法:从右往左,第 i 位数字乘以 base 的 i 次方,然后全部加起来。
就像"拆红包"一样,每个位置的价值不同,全部加起来就是总价值。
📐 核心公式 / 关键要点
公式:结果 = Σ (digit[i] × base^i),其中 i 从 0 开始(从右往左)
简单记法:
"每一位数字 × 对应位权,全部相加"
位权从右往左依次是 1, base, base², base³...
简单记法:
"每一位数字 × 对应位权,全部相加"
位权从右往左依次是 1, base, base², base³...
手算示例:二进制 11001 → 十进制
1 × 2⁴ = 1 × 16 = 16
1 × 2³ = 1 × 8 = 8
0 × 2² = 0 × 4 = 0
0 × 2¹ = 0 × 2 = 0
1 × 2⁰ = 1 × 1 = 1
─────────────
合计 = 16 + 8 + 0 + 0 + 1 = 25 ✅
1 × 2³ = 1 × 8 = 8
0 × 2² = 0 × 4 = 0
0 × 2¹ = 0 × 2 = 0
1 × 2⁰ = 1 × 1 = 1
─────────────
合计 = 16 + 8 + 0 + 0 + 1 = 25 ✅
💻 代码示例:N进制转十进制
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
// base 进制的字符串 str 转换为十进制整数
int fromBase(string str, int base) {
int result = 0; // 累加结果
int power = 1; // 当前位的权重:1, base, base², ...
// 从字符串的最后一个字符开始,从右往左处理
for (int i = str.size() - 1; i >= 0; i--) {
int digit; // 当前位的数值
if (str[i] >= '0' && str[i] <= '9') {
digit = str[i] - '0'; // 字符 '0'~'9' → 数字 0~9
} else {
digit = str[i] - 'A' + 10; // 字符 'A'~'F' → 数字 10~15
}
result += digit * power; // 数字 × 位权,加到结果上
power *= base; // 位权乘以 base,移到下一位
}
return result;
}
int main() {
cout << fromBase("FF", 16) << endl; // 输出: 255
cout << fromBase("11111111", 2) << endl; // 输出: 255
cout << fromBase("11001", 2) << endl; // 输出: 25
cout << fromBase("377", 8) << endl; // 输出: 255
return 0;
}
⚠️ 易错点
🚨 常见错误
- 忘记倒序:除N取余法得到的余数是从低位到高位的,必须倒序拼接才是正确答案。很多人把余数正序拼起来就交了,结果反了。
- n=0 的情况没处理:如果输入是 0,while 循环不会执行,返回空字符串。记得特判:
if (n == 0) return "0"; - 十六进制大写字母:10~15 对应 A~F,别忘了处理。同时注意 10 对应 'A' 不是 'a'(题目通常要求大写)。
- 逆向转换时字符转数字:从 N进制转十进制时,字符 'A' 到数字要用
str[i] - 'A' + 10,别搞错偏移量。 - 用 pow() 计算位权的精度问题:浮点数的 pow() 可能有精度误差,用
power *= base的方式更可靠。 - 混淆除法和取余:
/是整数除法(取商),%是取余数。这两个配合使用是进制转换的关键。
📝 练习建议
💡 怎么练?
- 先手算验证:在纸上手动做几次转换,比如 13 → 二进制、26 → 十六进制,再和程序结果对比。
- 常见数值要熟记:
10 → A 11 → B 12 → C 13 → D 14 → E 15 → F
16 → 10 32 → 20 64 → 40 128 → 80 255 → FF - 练习双向转换:写程序先转过去再转回来,看是否回到原数(round-trip 验证)。
- 尝试用不同进制:尝试转五进制、七进制等不常见的进制,加深理解。
- 推荐练习题:洛谷 P1143(进制转换)、蓝桥杯进制相关真题。