cosmos 位运算系列:十进制转二进制(base 10 → base 2)的商余法原理与多语言实现指南
2026/9/23 5:24:22 网站建设 项目流程
  • 教程
  • 示例工程

【免费下载链接】cosmos

World's largest Contributor driven code dataset | Used in Quark Search Engine, @OpenGenus IQ, OpenGenus Visual Project

项目地址:https://gitcode.com/gh_mirrors/co/cosmos
点击查看免费下载

本指南以 cosmos 仓库中 convert_number_binary 模块文档 为核心,系统讲解如何将一个十进制(base 10)整数转换为二进制(base 2)表示:从"反复除以 2 取余数"的核心算法出发,逐步推导 8 位定长二进制示例,并对照仓库内 Python、C、C++、Java、JavaScript、PHP、Haskell 七种语言的实现与测试用例,揭示模运算、位运算两种等价写法的底层原理与边界处理。读完本文,你将能够徒手完成任意十进制到二进制的转换,并理解固定位宽、负数、零值等边界情况在真实工程代码中的处理方式。

模块定位:把十进制数转换为二进制数

在 cosmos 仓库的位运算(bit manipulation)分类下,convert_number_binary 模块的全部程序只围绕一件事:把 base 10(十进制)的数转换为 base 2(二进制)的数。二进制是现代计算机内部表示数据的唯一形式,因此理解并实现这一转换是理解位运算、内存布局、定点数与哈希函数等一切底层话题的前提。

二进制数只允许出现2种数字:01。下表给出了十进制与二进制的对应关系(摘自模块文档):

Decimal(十进制)Binary(二进制)
00
11
210
311
4100
1610000

从表中可以直观感受到两条规律:二进制逢二进一;一个十进制数n的二进制表示长度约为⌊log₂n⌋ + 1位(例如16 = 10000₂,共 5 位)。

核心算法:反复除以 2 的商余法(mod / quot)

文档中给出的转换思路非常朴素且严谨,每一步只做两件事:

  • mod(取模):用除数2除被除数,只保留余数
  • quot(求商):用除数2除被除数,只保留

设十进制数为n,二进制结果b共有k位(即b = bₖ₋₁ bₖ₋₂ … b₁ b₀,其中bₖ₋₁是最高位 MSB,b₀是最低位 LSB),则算法流程为:

  • step 1n mod 2 = bₖ₋₁(本步的余数成为二进制的最高位),n quot 2 = n₁(商进入下一轮迭代);
  • step 2n₁ mod 2 = bₖ₋₂n₁ quot 2 = n₂
  • …… 持续迭代,直到商为0
  • final stepnₖ₋₁ mod 2 = b₀nₖ₋₁ quot 2 = 0,算法终止。

这一过程在算法上被称为"短除法 / 除 2 取余法":从最低位开始逐位确定二进制结果,先算出的余数应排在最右侧(低位)。值得注意的是,文档将k定义为二进制数b的位数,这意味着算法天然支持"定长输出"——即使商已经变成 0,只要尚未填满k位,就继续用0 mod 2 = 0补足高位(详见下一节示例)。

完整推导示例:把 5 转为 8 位二进制 00000101

文档以n = 5, k = 8为例,演示了完整 8 轮推导过程,整理如下:

轮次被除数mod 2(余数 → 位)quot 2(下一轮被除数)
151→ b₇2
220→ b₆1
311→ b₅0(计算到此已结束)
400→ b₄0
500→ b₃0
600→ b₂0
700→ b₁0
800→ b₀0

b₇ b₆ b₅ b₄ b₃ b₂ b₁ b₀从高位到低位排列,得到:

b = [0, 0, 0, 0, 0, 1, 0, 1] → "00000101"

验证:00000101₂ = 0×2⁷ + 0×2⁶ + 0×2⁵ + 0×2⁴ + 0×2³ + 1×2² + 0×2¹ + 1×2⁰ = 4 + 1 = 5

这个例子透露了三个要点:其一,真正的有效计算只持续到商变为 0(第 3 轮),之后均为补零;其二,第一次算出的余数反而是最低位(这里5 mod 2 = 1对应 b₀ 方向的最近一位,文档写作 b₇ 是因为定长 8 位下它落在最右侧);其三,定长位宽k给了我们显式的补零策略,这在处理有符号数、协议字段等场景中非常实用。

仓库中的七种语言实现与运行方式

模块目录 code/bit_manipulation/src/convert_number_binary 下提供了同一算法的多语言实现,它们在思路上分为"模运算逐位拼接"与"位运算逐位拼接"两大流派。下面逐一解读。

Python:字符串拼接版

convert_number_binary.py:

def intToBinary(i): if i == 0: return "0" s = "" while i: if i % 2 == 1: s = "1" + s else: s = "0" + s i /= 2 return s

逻辑与文档的商余法完全一致:每次取i % 2得到一位余数,通过s = "1" + s把新位前插到字符串头部,天然实现了"先算出的余数放低位、后算出的放高位"的逆序修正;循环条件while i等价于"商不为 0 就继续"。特殊地,0被单独处理为"0"(若走循环则输出空串)。从源码结构看,这里的i /= 2沿用 Python 2 的整除语义,在 Python 3 下建议改写为i //= 2以保证严格的整数除法。运行方式:

python3 code/bit_manipulation/src/convert_number_binary/convert_number_binary.py # 输出 741 的二进制

C:数值累加版(附带 1 计数)

convert_number_binary.c 不使用字符串,而是把二进制结果直接构造成一个十进制外观的long型数值,并顺带统计二进制中1的个数:

while (num > 0) { remainder = num % 2; if (remainder == 1) { no_of_1s++; /* 统计 1 的个数 */ } binary = binary + remainder * base; num = num / 2; base = base * 10; /* 按十进制位权逐位累加 */ }

base每轮乘 10,使binary呈现为101这样的数值形式,配合scanf("%ld")交互输入,并输出"原数、二进制等价形式、二进制中 1 的个数"三项。需要注意:这种以数值模拟字符串的做法在输入较大时存在long溢出风险,工程上更推荐字符串或数组方案。编译运行:

gcc code/bit_manipulation/src/convert_number_binary/convert_number_binary.c -o conv && ./conv

C++:位运算版(含反向转换)

convert_number_binary.cpp 使用位运算替代取模,是理解"模 2 ↔ 与 1、除 2 ↔ 右移 1"等价关系的最佳范例:

string to_binary(int n) { string binary = ""; while (n > 0) { if ((n & 1) == 0) binary = '0' + binary; else binary = '1' + binary; n >>= 1; } return binary; }

这里n & 1取出最低位(等价于n % 2),n >>= 1整体右移一位(等价于n / 2),配合前插字符串即可完成转换。文件还给出了反向函数to_number(string s),用1 << (n - 1 - i)按位权累加二进制串。main中以to_binary(10)(应输出1010)与to_number("111")(应输出7)自测。

Java:位运算版(含反向转换)

convert_number_binary.java 与 C++ 版如出一辙:toBinary(int n)(n & 1)判位、n >>= 1右移,StringBuilder前插拼接;toNumber(String s)1 << (n - 1 - i)还原十进制。main中以toBinary(20)toNumber("10101")验证(应分别输出1010021)。编译运行:

javac code/bit_manipulation/src/convert_number_binary/convert_number_binary.java java -cp code/bit_manipulation/src/convert_number_binary ConvertNumberBinary

JavaScript:内置函数版 + 位运算版

convert_number_binary.js 同时提供了两条路径,是最贴近"实战选型"的实现:

// 内置函数:简洁可靠 function toBinary(val) { return val.toString(2); } function fromBinary(bitString) { return parseInt(bitString, 2); } // 位运算:不依赖内置 API,逻辑透明 function toBinary_B(val) { let out = ""; while (val > 0) { out = (val & 1) + out; val >>= 1; } return out; }

Number.prototype.toString(2)parseInt(bitString, 2)是 ECMAScript 内置的进制转换入口,适合生产环境;toBinary_B/fromBinary_B则完整复刻了商余法与位权累加,便于学习与移植到无内置 API 的环境。

PHP:双向转换 + 内建测试用例

convert_number_binary.php 提供了decimal_to_binarybinary_to_decimal两个方向,且文件底部自带断言式测试数据,可直接作为算法正确性的验证依据:

// decimal_to_binary 测试对(摘自源码) [0, 0], [1, 1], [2, 10], [5, 101], [9, 1001], [10, 1010], [4692, 1001001010100], [4852, 1001011110100]

decimal_to_binary$bin = $bin + ($i * $rem)配合$i *= 10构造数值型二进制结果;binary_to_decimal则把每一位乘以其 2 的幂次累加。运行php code/bit_manipulation/src/convert_number_binary/convert_number_binary.php即可看到每个用例的OK / FAIL输出。

Haskell:定长位宽版(函数式实现)

convert_number_binary.hs 是全部实现中唯一把"定长k位"作为一等参数的版本,与文档n mod 2 = bₖ₋₁的符号体系高度吻合:

convDecToBin :: Int -> Int -> Binary convDecToBin k n | n >= 0 = case convDecToBin' k n "" of Left s -> s Right b -> b | otherwise = negativeNumberNotSupported -- 负数显式拒绝

辅助函数convDecToBin'每次递归把n 'quot' 2n 'mod' 2传入下一层,位串按show r' ++ b前插;当位数耗尽而商仍大于 0 时返回needMoreBits("位数不足"),位数或商为 0 时正常收尾。文件末尾的断言覆盖了定长转换(convDecToBin 3 3 == "011")、大数(convDecToBin 32 32)、位数不足(convDecToBin 2 4报错)与负数(convDecToBin 2 (-4)拒绝)四类场景,可直接用 GHC 运行验证。

位运算视角:为什么n & 1n >>= 1等价于取模与除法

对比 C++/Java/JavaScript 的位运算版与 Python/C/PHP 的模运算版,可以得到一组在整数运算中恒成立的等价关系:

算术写法(文档语义)位运算写法说明
n mod 2n & 12 的二进制是10₂n & 1只保留最低位,恰好是除以 2 的余数
n quot 2n >>= 1二进制右移一位相当于整体除以 2,商即移走最低位后的剩余部分

这正是整个模块被归入 bit_manipulation(位运算)分类的原因:十进制转二进制的本质,就是反复"丢弃最低位(右移)并把丢弃的位记录为结果"。两种写法对非负整数结果完全一致,位运算版本在底层通常映射为单条机器指令,在追求极致性能的场景(如嵌入式、内核代码)中更为常见。需要说明的是,对于有符号负数的右移,不同语言存在算术右移/逻辑右移差异,因此上述等价关系以非负整数为适用前提——Haskell 实现中对负数直接返回错误信息,正是对这一前提的工程化处理。

边界情况与工程注意点

综合文档的定长推导与各语言实现,至少有三类边界值得在工程中处理:

  1. 零值:Python 实现单独返回"0";若走通用循环,0的二进制串会是空串,必须特判。
  2. 负数:文档算法基于非负整数推导;Haskell 版显式返回negativeNumberNotSupported拒绝负数。实际工程中负数通常采用补码表示,需先按符号规则变换,再决定是否使用定长位宽输出。
  3. 位宽不足 / 溢出:Haskell 版当位数k小于实际所需时返回needMoreBits;C 版以数值累加模拟字符串,大数存在long溢出风险;Python 版使用字符串拼接则无此问题。定长输出的需求(如协议字段)应显式补零。

反向转换:二进制转十进制(进制转换的闭环)

模块目录还包含反向实现 binary_to_integer.py,采用"从左到右"的霍纳式累加:

def binary_to_int(binary_input): integer_output = 0 for digit in binary_input: integer_output = integer_output * 2 + int(digit) return integer_output

每次integer_output * 2 + int(digit)等价于把已累加的二进制串整体左移一位并追加新位,循环结束后即为十进制值;C++ 与 Java 实现中的toNumber则按位权1 << (n - 1 - i)累加,PHP 版同样提供binary_to_decimal。正反两个方向共同构成完整的进制转换闭环,也是验证正向转换正确性的天然工具:对任意十进制数nbinary_to_int(intToBinary(n)) == n恒成立。

复杂度分析

设十进制输入为n(非负整数),二进制结果位数为k = ⌊log₂n⌋ + 1

  • 时间复杂度:每次迭代执行一次取模/取位与一次除法/右移,共迭代k轮,每轮 O(1),总体O(log n)
  • 空间复杂度:字符串/数组实现需保存k位结果,为O(log n);以数值累加模拟字符串的 C 版本为 O(1) 额外空间,但以溢出风险为代价。

这也是"短除法"在进制转换场景中被称为最优朴素算法的原因——输出本身就有O(log n)位,任何算法都不可能优于线性于输出规模。

小结

围绕 cosmos 仓库 convert_number_binary 模块文档 的商余法,本文完成了从算法原理、手算推导(5 → 00000101)到七种语言实现的完整拆解:模运算版与位运算版(n & 1/n >>= 1)在非负整数域上严格等价;定长位宽、零值与负数处理是工程落地的关键细节;反向转换(如 binary_to_integer.py)与 PHP 版内建测试用例为正确性提供了闭环验证。读者可将本模块作为位运算入门的第一个自测点:动手运行各语言实现,再尝试为任意十进制数手写出定长二进制表示,即可牢固掌握这一计算机底层语言。

  • 教程
  • 示例工程

【免费下载链接】cosmos

World's largest Contributor driven code dataset | Used in Quark Search Engine, @OpenGenus IQ, OpenGenus Visual Project

项目地址:https://gitcode.com/gh_mirrors/co/cosmos
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询