资讯动态

进制转换核心方法:除基取余、乘基取整与位权原理

发布时间:2026/10/13 4:40:55 来源:尧图企业网站定制
1. 先解决一个疑惑进制转换到底卡住了多少人前阵子帮一位刚入行的同事排查一段位运算相关的代码他一脸困惑地问我明明程序里写的是0x3F为什么注释里说是“六个引脚同时拉高”我让他自己把0x3F换算成二进制看看他拿着计算器按了半天最后告诉我“等于63啊”。看他这个样子我大概明白了——他对十六进制、二进制之间的换算根本没有形成直觉纯粹是查表查出来的。这个场面其实挺常见。进制转换在计算机基础里算是最入门的一课但很多人学的时候靠的是“背”背二进制的权值、背十六进制的字母表甚至背几个常见数字的转换结果。一旦遇到一个没背过的数字立刻卡壳。我在带新人和给同事做技术分享时最常强调的就是进制转换不是记忆题而是一套可以重复使用的计算方法。把方法掌握了别说 97、255 这种常见数字给你一个 1024 或者 0.8125你也能在两分钟内写出对应的二进制、八进制、十六进制。这篇文章就专门把这套方法摊开讲。你会看到整数怎么转、小数怎么转、二进制和八进制/十六进制之间为什么能“三位一组”“四位一组”直接互转以及这套东西在写代码、调程序、配寄存器时到底用在哪儿。适合刚学编程的学生、准备笔试面试的求职者还有那些用了很多年hex()但从没自己手算过一次的程序员朋友。我的建议是别跳过原理直接看方法。方法五分钟能学会但原理不理解的话换一个不常见的数字、加一个小数点你可能又懵了。我们一件件事说清楚。2. 整数转换的主干方法除基取余余数结果要倒着读2.1 先搞懂“位权”是怎么回事不管几进制一个数字之所以有意义是因为每个位置都携带了一个“权重”。十进制的 123实际含义是1×10² 2×10¹ 3×10⁰ 100 20 3。这里的 10²、10¹、10⁰ 就是位权10 是十进制的基础也叫基数。把这个逻辑搬到二进制上基数是 2所以一个二进制数从右往左每一位的权重分别是 2⁰、2¹、2²、2³……也就是 1、2、4、8、16、32、64、128。比如二进制 1100001展开来看是 1×2⁶ 1×2⁵ 0×2⁴ 0×2³ 0×2² 0×2¹ 1×2⁰ 64 32 1 97。为什么要先讲位权因为后面的“除基取余法”本质上就是在不停地回答一个问题这个数里包含了多少个最高位的权重、余下的部分又分别包含了多少下一个权重的值。理解了位权你就理解了为什么转换过程是那样一步步做下去的。2.2 十进制转二进制除以2余数从下往上排把十进制整数转换成二进制标准动作是“除基取余”。基数是 2那就一直除以 2每次记下余数一直除到商变成 0然后把所有余数从下往上排列。我拿 97 举例完整演算一遍97 ÷ 2 48余 148 ÷ 2 24余 024 ÷ 2 12余 012 ÷ 2 6余 06 ÷ 2 3余 03 ÷ 2 1余 11 ÷ 2 0余 1把余数倒过来读1100001。所以十进制的 97 就是二进制的 1100001。验证一遍64 32 1 97完全正确。这里有一个很多人第一次学时最容易踩的坑第一个算出来的余数其实是最低位最后一个余数才是最高位。你顺着除法往下写的时候余数是按“低到高”出现的结果却必须“从下往上”读所以笔算时我建议把余数单独列一列不要混在商里否则最后倒序的时候非常容易抄错。2.3 换成八进制同样的流程只是除数变成 8如果把目标进制换成八进制数学逻辑完全一样只是把除数从 2 换成 8。因为八进制每一位只能是 0 到 7所以余数的取值范围也必然是 0 到 7。继续用 97 举例97 ÷ 8 12余 112 ÷ 8 1余 41 ÷ 8 0余 1倒序读取141。八进制下的 97 就写作 141。验算1×8² 4×8¹ 1×8⁰ 64 32 1 97跟二进制结果 1100001 对应的是同一个值。注意八进制的每一位只有 3 个二进制位的信息量所以换算结果一般比二进制短很多手写时不容易眼花。这也是早期计算机系统喜欢用八进制的原因之一——它比二进制好读又比十进制好算。2.4 转十六进制注意10到15要用字母表示十六进制和之前唯一的实质区别是基数变成了 16余数范围变成 0 到 15。十进制里没有单独表示 10、11、12、13、14、15 的符号于是借用了 A、B、C、D、E、F 六个字母。这个对应关系是唯一需要“硬记”的。还是那个 9797 ÷ 16 6余 16 ÷ 16 0余 6倒序读取61。所以十进制的 97 转成十六进制是 61不需要任何字母。换个更经典的例子255 转十六进制。255 ÷ 16 15余 15记作 F15 ÷ 16 0余 15记作 F结果就是 FF。这里的 F 等价于十进制的 15两个 F 并排表示高位的 15×16 低位的 15×1 240 15 255。记住下面这个对照表转十六进制时会顺手很多十进制0123456789101112131415十六进制0123456789ABCDEF二进制01101110010111011110001001101010111100110111101111为什么 97、255 这样的数字总是出现在教科书里因为它们正好落在 7 位二进制、8 位二进制的边界附近非常便于演示。但你自己练习的时候不要只练这几个随便抽几个日常数字比如 37、150、512、1000每个都转一遍直到不用思考就能写出除法和余数为止。2.5 除基取余法为什么对任何进制都成立观察前面三个例子你可能会发现方法一模一样只有基数不同。这不是巧合而是进制本质决定的。任何一个整数 N在目标进制 base 下都可以写成这样的形式N q × base r其中 r 是 N 除以 base 的余数q 是商。这个 r 必然小于 base所以它天然就是目标进制下的一个合法数字。接下来 q 继续用同样的方式拆解到最后 q 变成 0。于是整个数就被拆成了一串余数而这些余数刚好按照“从低位到高位”的顺序出现倒过来就是完整的进制表示。理解这一点之后你以后遇到什么三进制、五进制、甚至二十进制都不会再害怕——反正除基取余倒序排列即可。3. 小数部分要换策略乘基取整顺着往下读3.1 小数的位权藏在小数点右边很多人整数转换没问题一遇到小数就懵。其实小数的逻辑跟整数对称只是把除法换成乘法。小数的位权是负指数。十进制的 0.625 意思是 6×10⁻¹ 2×10⁻² 5×10⁻³。二进制的小数 0.101 意思是 1×2⁻¹ 0×2⁻² 1×2⁻³ 0.5 0.125 0.625。你会发现二进制的 0.101 恰好等于十进制的 0.625这是一个可以拿来做验证的漂亮例子。小数转换的标准方法是“乘基取整”小数部分乘以目标进制取结果的整数部分作为当前小数位然后把剩下的小数部分继续乘下去直到小数部分变为 0或者达到你需要的精度为止。和整数不同小数的结果要从上往下读——先算出来的整数位是小数点后的第一位。3.2 一个能整除的例子0.625 转二进制拿 0.625 演算0.625 × 2 1.25取整数 1剩小数 0.250.25 × 2 0.5取整数 0剩小数 0.50.5 × 2 1.0取整数 1剩小数 0过程结束。结果就是 0.101。你说巧不巧正好跟 3.1 里的例子对上。再看一个带整数的混合数13.25 转二进制。整数部分 13 用除基取余法13÷26余16÷23余03÷21余11÷20余1倒序是 1101。小数部分 0.250.25×20.5取00.5×21.0取1结果是 0.01。合并后就是 1101.01。整个过程就是整数和小数各算各的最后拼起来。3.3 一个转不完的例子0.1 转二进制与浮点误差的真相但是不是所有小数都能恰好转换干净。试着转 0.10.1 × 2 0.2取 0剩 0.20.2 × 2 0.4取 0剩 0.40.4 × 2 0.8取 0剩 0.80.8 × 2 1.6取 1剩 0.60.6 × 2 1.2取 1剩 0.20.2 × 2 0.4取 0剩 0.4发现了吗从 0.2 开始刚才的序列开始循环了。这说明十进制的 0.1 在二进制里是一个无限循环小数永远不可能用有限位二进制精确表示。计算机的浮点数只能存储有限位数所以必然产生舍入误差。很多写代码的新人问过我为什么0.1 0.2不等于0.3答案就在这里。这不是程序 Bug而是二进制表示本身就装不下 0.1。理解了这个原理你以后处理金额计算时就会主动用整数分、或者使用专门的高精度小数运算库而不是傻乎乎地拿浮点数直接相加。3.4 小数转换的精度控制别九九归一要见好就收既然小数可能无限循环实际工作中就要定一个精度目标。比如二进制保留 8 位小数、十六进制保留 4 位小数算到那个位数就停止。取的时候要注意停止位置的后一位如果产生了进位要考虑四舍五入。不过在计算机基础的手算练习里一般默认截断到目标精度不必过度纠结。我个人的建议是手算小数时至少把计算过程写到小数部分清零为止如果明显看到循环了就停并标注“循环”。这样既保证练习意义也避免在做题时浪费时间。4. 省力捷径二进制与八进制、十六进制的分组互转4.1 二进制的三位、四位对应关系是数学必然纯用“除基取余法”当然能把十进制转成任何进制但在实战里很少人会真的用 97 去反复除以 8 或 16。更常用的做法是先把十进制转成二进制再按三位一组或四位一组快速得到八进制和十六进制。为什么可以这样干因为 2³ 82⁴ 16。二进制的一位是 2 的幂八进制的一位是 2³十六进制的一位是 2⁴。所以一位八进制数恰好等于三位二进制数一位十六进制数恰好等于四位二进制数。这个关系是可逆的、一一对应的没有任何信息丢失。4.2 二进制转八进制从右往左三位一组把二进制 1100001 转成八进制。从最右边的低位开始每三位分成一组1100001 → 001 100 001。最左边一组如果不足三位就补前导零这里补成了 001。然后每一组单独转换成八进制数字001 1100 4001 1。所以结果就是 141跟上文用除基取余法得到的结果一模一样。熟练之后三位二进制的转换表要能脱口而出00000011010201131004101511061117。一共 8 种组合其实就是在背八进制的 0 到 7。4.3 二进制转十六进制四位一组字母别写错同样拿 1100001 转十六进制。这次是四位一组1100001 → 0110 0001。左侧补一个 0凑成两组。0110 60001 1。结果就是 61跟除基取余法得到的结果完全一致。如果遇到三组以上的情况比如一个 16 位二进制数 1010111100001101分组是 1010 1111 0000 1101对应 A F 0 D写出来就是 0xAF0D。这种写法在寄存器配置、位掩码场景里非常常见因为一个字节8 位二进制恰好对应两位十六进制肉眼可读性远高于一长串 0 和 1。4.4 反向转换八进制、十六进制每一位展开成二进制反过来也一样。八进制 141 转二进制就是把每一位拆成三位1→0014→1001→001拼接得到 001100001去掉前导零就是 1100001。十六进制 61 转二进制把每一位拆成四位6→01101→0001拼接后去掉前导零得到 1100001。十六进制 0xAF0D 拆开A→1010F→11110→0000D→1101得到 1010111100001101。这个“展开-拼接-去零”的操作用熟了以后完全可以心算。我在调试串口日志时经常要快速判断某个十六进制字节的某些位是不是 1用的就是这个基本功。比如看到 0x3F立刻想到低 6 位是 1高 2 位是 0。4.5 什么时候该走捷径什么时候该老实除我的实践经验是如果是十进制直接转八进制或十六进制且数字比较大可以直接除基取余如果数字不大或者你还得在二进制、八进制、十六进制之间来回切换那就先转二进制再分组效率更高。还有一个小技巧转二进制时如果数字特别大可以先用位权心算拆解。比如 200 128 64 8对应二进制第 7 位、第 6 位、第 3 位为 1其他位为 0立刻写出 11001000。这个方法练熟之后比一步步除 2 快得多而且不容易出错。5. 常见错误与验算转完不知道怎么检查等于白转5.1 四个高频错误我几乎每天都能在初学者代码里看到第一个错误余数顺序读反。这是除基取余法里最经典的错误。97 转二进制算出来余数按顺序是 1、0、0、0、0、1、1直接把顺序抄成 1000011结果变成 67错得离谱。解决办法只有一个写完以后倒序再念一遍或者先在草稿上把除法竖式写得工整最后统一从下往上抄。第二个错误十六进制字母写错。有人把 C 和 E 混着写有人把 A 写成 10。转换结果本身没错抄写时却搞错了符号。我的习惯是转完立刻验算如果发现结果很奇怪先别急着怀疑算法先检查字母部分。第三个错误小数乘基取整时把整数部分和小数部分混在一起。0.625 × 2 1.25有人会把这一步的 1 当作十位上的 1 写进二进制结果里然后继续拿 1.25 去乘以 2。正确做法是只取整数 1剩下的小数 0.25 才继续乘。每一步的整数位只取一个数字。第四个错误二进制转八进制时分组方向搞反。必须从右往左分组不是从左往右。1100001 如果从左往右三位一组就是 110 000 1组合出来的结果是 601明显是错的。方向错了补零的位置也会跟着错。5.2 最实用的验算方法位权展开回加法转换完成之后务必用位权展开法反向验证。比如二进制 1100001你把它展开成 1×64 1×32 0×16 0×8 0×4 0×2 1×1等于 97那结果就一定是正确的。八进制 141 展开成 1×64 4×8 1等于 97十六进制 61 展开成 6×16 1也等于 97。这套验算不仅给你信心还能锻炼你对位权的感觉。练久了以后看到一个二进制位串你心里能自动估算出它大概是多少。这种“数字直觉”在排查问题时非常有价值。5.3 编程语言里的现成工具用可以别当不会手算的理由实际开发中当然不必每次手算。各语言都提供了现成方法语言/环境十进制转二进制十进制转八进制十进制转十六进制Pythonbin(n)oct(n)hex(n)C/Cprintf(%b, n)部分环境支持printf(%o, n)printf(%x, n)JavaScriptn.toString(2)n.toString(8)n.toString(16)JavaInteger.toBinaryString(n)Integer.toOctalString(n)Integer.toHexString(n)但我的态度很明确工具是加快效率用的不是替代理解用的。笔试题、期末考试、技术面试手写代码时经常要求你手动实现一个转换函数这时候如果你只会调库就会非常被动。而且很多面试官问进制转换考察的其实是你对位权和除基取余的理解而不是你背没背下 API。我自己在带人时会让对方先把原理讲给我听再手写一个二进制转换函数最后才允许用hex()之类的系统函数。这三步走完才算真正过关。6. 在实际开发里的几个应用场景学完真的用得上6.1 位运算与权限标记二进制比十进制直观得多最常见的场景是用二进制来表示一组开关状态。比如 Linux 风格的文件权限读 4二进制 100写 2二进制 010执行 1二进制 001。777 这个数字之所以代表“所有人全部权限”是因为 7 111三个位全是 1。再比如一个软件里要给用户分配几种权限最常见的设计是定义READ 1 0、WRITE 1 1、EXECUTE 1 2然后用按位或来组合、按位与来检查。这种写法背后全是二进制的位运算逻辑。如果你看不懂这些运算符和进制的关系代码看着就是天书。6.2 寄存器配置和内存地址十六进制是嵌入式调试的语言做嵌入式开发或者底层驱动的人天天跟寄存器打交道。芯片手册上写的是P0MDOUT | 0x0F意思是把端口低 4 位配置为推挽输出。你一看到0x0F脑子里应该立刻浮现二进制0000 1111知道高 4 位没动、低 4 位全是 1。调试器里显示的内存地址、栈指针、寄存器值几乎全都是十六进制。一个字节是 0x00 到 0xFF两位一个字节100 个字节正好是 200 个十六进制字符高效且紧凑。相比之下如果用二进制表示内存地址动辄三四十个字符看着就头晕。6.3 颜色值和哈希字符串十六进制的存在感无处不在网页开发中常见的颜色值#FF4500其实就是三个字节的十六进制红 0xFF 255绿 0x45 69蓝 0x00 0。你要调色时如果知道0xFF是全量、0x80是 50% 强度就能在不打开取色器的情况下估算出一个颜色大致长什么样。哈希函数的输出也几乎一律采用十六进制字符串。MD5 生成 32 位十六进制字符SHA-256 生成 64 位字符。没事谁会去把那段字符串转成二进制看但反过来如果你想从二进制字节流里判断某个位置是不是一个哈希值知道一字节等于两位十六进制马上就能数出来。6.4 网络协议里的掩码计算顺便送你一个实用案例拿 IPv4 的子网掩码来说常见值如255.255.255.0二进制其实是一长串连续的 1 加连续的 0。为什么叫“CIDR 前缀长度”呢因为255.255.255.0就是 24 个 1 再加 8 个 0记成/24。如果你能心算出25511111111000000000那么遇到192.168.1.0/26这类表达就能立刻算出掩码是255.255.255.192因为 26 24 2最后一个字节是前 2 位为 1即11000000 192。这类换算不需要什么高深技巧就是二进制、十进制之间的快速转换但用熟了以后排查网络问题、配置防火墙规则时会顺手非常多。7. 我的学习建议从一个你实际会遇到的数值开始练文章最后聊点实际的。我发现很多人学进制转换练的都是书上的例子练完就忘。我的经验是挑几个你日常工作中真的会遇到的数字来练习记得特别牢。比如你在做网页开发那就练 0xFF、0x80、0x40、0x0F 这些颜色和掩码常用值你在做嵌入式就练寄存器手册里那一串 0x2A、0x80 之类的配置值你是纯粹学编程就把ASCII表里常用字符的编码值比如大写 A 是 65、a 是 97拿来做二进制和十六进制转换练习。这样每次看到类似的数值你的脑子里都会自动做一遍推理而不是每次依赖计算器。另外一个很管用的习惯是写代码时遇到十六进制字面量随手在注释里写上它的十进制值和二进制位模式。比如#define PIN_MASK 0x3F // 0b00111111 63。这种习惯一开始会觉得多余但几个月后回头看代码你会发现自己的阅读速度快了很多因为大脑已经形成了进制之间的条件反射。进制转换不是一道单独的计算题它是计算机世界底层规律的一部分。把除基取余、乘基取整、三位分组、四位分组这套基本功练熟你以后学习位运算、编码规范、协议分析都会顺畅得多。别嫌它基础真正的基础往往是拉开差距的地方。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑