Created
March 7, 2026 07:31
-
-
Save liquidhelium/68226a052d1a496aabb76bb720eaa0ec to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #set page(width: auto, height: auto) | |
| #set text(font: ("Libertinus Serif", "Noto Serif CJK SC")) | |
| #set text(12pt) | |
| #let binary-div(n) = { | |
| let val = n | |
| let rows = () | |
| // 循环计算直到商为 0 | |
| while val > 0 { | |
| let remainder = calc.rem(val, 2) | |
| // 使用 int() 确保除法结果向下取整 | |
| let next_val = int(val / 2) | |
| // 使用 += 将这三个元素拼接到 rows 数组中 | |
| rows += ( | |
| $2$, | |
| table.cell( | |
| stroke: (left: 1pt, bottom: 1pt), | |
| align: right, | |
| [#val], | |
| ), | |
| align(left)[#remainder], | |
| ) | |
| val = next_val | |
| } | |
| // 添加最后的商 0 | |
| rows += ( | |
| "", | |
| align(right)[0], | |
| "", | |
| ) | |
| block(stack( | |
| dir: ltr, | |
| spacing: 1em, | |
| // 渲染表格 | |
| table( | |
| columns: (2em, 3em, 3em), | |
| stroke: none, | |
| align: center + horizon, | |
| ..rows | |
| ), | |
| )) | |
| } | |
| // // 使用示例 | |
| // // #set page(width: auto, height: auto, margin: 1cm) | |
| // #binary-div(3) | |
| // $(3)_10 = (11)_2$ | |
| #let frac-to-binary-math(num, max-digits: 10) = { | |
| let val = num | |
| let steps = ($num$,) | |
| let result = "" | |
| for i in range(max-digits) { | |
| if val == 0 { break } | |
| let product = val * 2 | |
| let int-part = int(product) | |
| let next-val = product - int-part | |
| // 构造每一行的数学内容:times 2 &= 剩余小数 + & 整数位 | |
| // 这里使用 calc.round 避免浮点数精度带来的微小误差(如 0.0000000001) | |
| steps.push( | |
| $times 2 &= #calc.round(next-val, digits: 10) + &#int-part$, | |
| ) | |
| result += str(int-part) | |
| val = next-val | |
| } | |
| // 将所有行用换行符 \ 连接 | |
| let formula = steps.join($ \ $) | |
| block[ | |
| #math.equation(block: true, formula) | |
| $(#num)_(10) = (0.#result)_(2)$ | |
| ] | |
| } | |
| // #frac-to-binary-math(0.215, max-digits: 6) | |
| // $(3.215)_10 = (11.001101)_2$ | |
| #let bin-to-dec-math(bin-str) = { | |
| // 处理输入,识别整数和小数部分 | |
| let parts = str(bin-str).split(".") | |
| let int-part = parts.at(0) | |
| let frac-part = if parts.len() > 1 { parts.at(1) } else { "" } | |
| let terms = () | |
| let total-val = 0.0 | |
| // 1. 处理整数部分 (从右往左,幂次从 0 开始) | |
| let int-len = int-part.len() | |
| for i in range(int-len) { | |
| let digit = int-part.at(int-len - 1 - i) | |
| let val = int(digit) | |
| if val != 0 { | |
| terms.push($#digit times 2^#i$) | |
| total-val += val * calc.pow(2, i) | |
| } else { | |
| terms.push($#digit times 2^#i$) | |
| } | |
| } | |
| // 翻转整数项,使其符合书写习惯 (从高位到低位) | |
| terms = terms.rev() | |
| // 2. 处理小数部分 (从左往右,幂次从 -1 开始) | |
| for i in range(frac-part.len()) { | |
| let digit = frac-part.at(i) | |
| let val = int(digit) | |
| let power = -(i + 1) | |
| if val != 0 { | |
| terms.push($#digit times 2^#power$) | |
| total-val += val * calc.pow(2, power) | |
| } else { | |
| terms.push($#digit times 2^#power$) | |
| } | |
| } | |
| // 将所有项用 + 连接 | |
| let expansion = terms.join($ + $) | |
| block[ | |
| $ | |
| (#bin-str)_2 & = #expansion \ | |
| & = #total-val | |
| $ | |
| $ (#bin-str)_2 = (#total-val)_(10) $ | |
| ] | |
| } | |
| // #bin-to-dec-math("0.10011101") | |
| #let dec-to-hex-int(n) = { | |
| let val = n | |
| let rows = () | |
| let hex-digits = "0123456789ABCDEF" | |
| let result = "" | |
| while val > 0 { | |
| let rem = calc.rem(val, 16) | |
| let hex-char = hex-digits.at(rem) | |
| let next_val = int(val / 16) | |
| rows += ( | |
| $16$, | |
| table.cell( | |
| stroke: (left: 1pt, bottom: 1pt), | |
| align: right, | |
| [#val], | |
| ), | |
| // 如果余数 >= 10,同时显示数字和字母 | |
| align(left)[$dots.c$ #rem #if rem >= 10 [(#hex-char)]], | |
| ) | |
| result = hex-char + result | |
| val = next_val | |
| } | |
| rows += ("", align(right)[0], "") | |
| block(stack( | |
| spacing: 2em, | |
| table(columns: (2em, 4em, 5em), stroke: none, align: center + horizon, ..rows), | |
| [ | |
| $ (#n)_(10) = (#result)_(16) $ | |
| ], | |
| )) | |
| } | |
| #let hex-to-dec-math(hex-str) = { | |
| let hex-str = str(hex-str) | |
| let hex-map = ( | |
| "0": 0, | |
| "1": 1, | |
| "2": 2, | |
| "3": 3, | |
| "4": 4, | |
| "5": 5, | |
| "6": 6, | |
| "7": 7, | |
| "8": 8, | |
| "9": 9, | |
| "A": 10, | |
| "B": 11, | |
| "C": 12, | |
| "D": 13, | |
| "E": 14, | |
| "F": 15, | |
| ) | |
| // 处理输入,识别整数和小数部分 | |
| let parts = hex-str.split(".") | |
| let int-part = parts.at(0) | |
| let frac-part = if parts.len() > 1 { parts.at(1) } else { "" } | |
| let terms = () | |
| let total-val = 0.0 | |
| // 1. 处理整数部分 (从高位到低位) | |
| let int-len = int-part.len() | |
| for i in range(int-len) { | |
| let char = int-part.at(i) | |
| let val = hex-map.at(char) | |
| let power = int-len - 1 - i | |
| // 构造数学项,如果原字符是 A-F,在展开中显示其数值 | |
| let display-val = if "ABCDEF".contains(char) { | |
| $#val (#char)$ | |
| } else { | |
| $#val$ | |
| } | |
| terms.push($#display-val times 16^#power$) | |
| total-val += val * calc.pow(16, power) | |
| } | |
| // 2. 处理小数部分 (从左往右,幂次从 -1 开始) | |
| for i in range(frac-part.len()) { | |
| let char = frac-part.at(i) | |
| let val = hex-map.at(char) | |
| let power = -(i + 1) | |
| let display-val = if "ABCDEF".contains(char) { | |
| $#val (#char)$ | |
| } else { | |
| $#val$ | |
| } | |
| terms.push($#display-val times 16^#power$) | |
| total-val += val * calc.pow(16, power) | |
| } | |
| let expansion = terms.join($ + $) | |
| block[ | |
| $ | |
| (#hex-str)_(16) & = #expansion \ | |
| & = #total-val | |
| $ | |
| $ (#hex-str)_(16) = (#total-val)_(10) $ | |
| ] | |
| } | |
| #let bin-to-oct-math(bin-str) = { | |
| let s = str(bin-str) | |
| // 1. 自动补齐前导 0,使其长度为 3 的倍数 | |
| let pad-len = calc.rem(3 - calc.rem(s.len(), 3), 3) | |
| let padded-s = "0" * pad-len + s | |
| let groups = () | |
| let oct-digits = () | |
| // 2. 按照 3 位一组进行切分和计算 | |
| for i in range(0, padded-s.len(), step: 3) { | |
| let group = padded-s.slice(i, i + 3) | |
| let b2 = int(group.at(0)) * 4 | |
| let b1 = int(group.at(1)) * 2 | |
| let b0 = int(group.at(2)) * 1 | |
| let oct-val = b2 + b1 + b0 | |
| groups.push(group) | |
| oct-digits.push(str(oct-val)) | |
| } | |
| let result = oct-digits.join("") | |
| block[ | |
| // 第一行:展示分组 | |
| $ | |
| underbrace(#groups.at(0), #oct-digits.at(0)) | |
| #for i in range(1, groups.len()) { [ $#underbrace(groups.at(i), oct-digits.at(i))$ ] } | |
| $ | |
| // 第二行:最终结论 | |
| $ (#bin-str)_2 = (#result)_8 $ | |
| ] | |
| } | |
| // 二进制转八进制 (三位一组) | |
| // #bin-to-oct-math("1101") | |
| // #bin-to-oct-math("1000110110101") | |
| #let hex-to-oct-math(hex-str) = { | |
| let hex-str = str(hex-str) | |
| let hex-map = ( | |
| "0": "0000", | |
| "1": "0001", | |
| "2": "0010", | |
| "3": "0011", | |
| "4": "0100", | |
| "5": "0101", | |
| "6": "0110", | |
| "7": "0111", | |
| "8": "1000", | |
| "9": "1001", | |
| "A": "1010", | |
| "B": "1011", | |
| "C": "1100", | |
| "D": "1101", | |
| "E": "1110", | |
| "F": "1111", | |
| ) | |
| // 1. 十六进制转二进制 (4-bit chunks) | |
| let bin-full = "" | |
| let hex-steps = () | |
| for char in hex-str { | |
| let b = hex-map.at(char) | |
| bin-full += b | |
| hex-steps.push($underbrace(#b, #char)$) | |
| } | |
| // 2. 二进制转八进制 (3-bit chunks) | |
| // 去掉前导 0 以便重新分组 | |
| let bin-clean = bin-full.replace(regex("^0+"), "") | |
| if bin-clean == "" { bin-clean = "0" } | |
| // 补足 3 的倍数 | |
| let pad-len = calc.rem(3 - calc.rem(bin-clean.len(), 3), 3) | |
| let padded-bin = "0" * pad-len + bin-clean | |
| let oct-steps = () | |
| let oct-digits = "" | |
| for i in range(0, padded-bin.len(), step: 3) { | |
| let group = padded-bin.slice(i, i + 3) | |
| let val = int(group.at(0)) * 4 + int(group.at(1)) * 2 + int(group.at(2)) * 1 | |
| oct-steps.push($underbrace(group, str(val))$) | |
| oct-digits += str(val) | |
| } | |
| block[ | |
| // 第一步:Hex -> Bin | |
| $ (#hex-str)_(16) = #hex-steps.join([ ]) $ | |
| #v(1em) | |
| // 第二步:Bin -> Oct | |
| $ #oct-steps.join([ ]) = (#oct-digits)_8 $ | |
| #v(1em) | |
| // 结论 | |
| $ (#hex-str)_(16) = (#oct-digits)_8 $ | |
| ] | |
| } | |
| #let dec-to-18-int(n) = { | |
| let val = n | |
| let base = 18 | |
| let rows = () | |
| // 扩展映射表:10-17 对应 A-H | |
| let digits-map = "0123456789ABCDEFGH" | |
| let result = "" | |
| // 处理输入为 0 的特殊情况 | |
| if val == 0 { | |
| result = "0" | |
| } | |
| while val > 0 { | |
| let rem = calc.rem(val, base) | |
| let char = digits-map.at(rem) | |
| let next_val = int(val / base) | |
| rows += ( | |
| [#base], | |
| table.cell( | |
| stroke: (left: 1pt, bottom: 1pt), | |
| align: right, | |
| [#val], | |
| ), | |
| // 标注余数,如果超过 10 则显示字母对应关系 | |
| align(left)[$dots.c$ #rem #if rem >= 10 [(#char)]], | |
| ) | |
| result = char + result | |
| val = next_val | |
| } | |
| // 补上最后的商 0 | |
| rows += ("", align(right)[0], "") | |
| block(stack( | |
| spacing: 2em, | |
| table( | |
| columns: (2.5em, 5em, 5em), | |
| stroke: none, | |
| align: center + horizon, | |
| ..rows | |
| ), | |
| [ | |
| // 从下往上读 $arrow.t$ \ | |
| $ (#n)_(10) = (#result)_(18) $ | |
| ], | |
| )) | |
| } | |
| #let base13-to-dec(hex-str) = { | |
| let s = str(hex-str) | |
| // 自定义映射表:X=10, Y=11, Z=12 | |
| let map = ( | |
| "0": 0, | |
| "1": 1, | |
| "2": 2, | |
| "3": 3, | |
| "4": 4, | |
| "5": 5, | |
| "6": 6, | |
| "7": 7, | |
| "8": 8, | |
| "9": 9, | |
| "X": 10, | |
| "Y": 11, | |
| "Z": 12, | |
| ) | |
| let terms = () | |
| let total = 0 | |
| let len = s.len() | |
| for i in range(len) { | |
| let char = s.at(i) | |
| let val = map.at(char) | |
| let power = len - 1 - i | |
| // 构造展示项:例如 10(X) * 13^1 | |
| let display = if "XYZ".contains(char) { $#val (#char)$ } else { [#val] } | |
| terms.push($#display times 13^#power$) | |
| total += val * calc.pow(13, power) | |
| } | |
| $ | |
| (#hex-str)_(13) & = #terms.join($ + $) \ | |
| & = #total | |
| $ | |
| } | |
| #let complement-steps(num, bits: 16) = { | |
| // 辅助函数:将整数转为固定位数的二进制字符串 | |
| let to-bin-str(n, width) = { | |
| let s = str(calc.abs(n), base: 2) | |
| let padded = "0" * (width - s.len()) + s | |
| // 每 4 位加一个空格 | |
| let formatted = "" | |
| for i in range(width) { | |
| formatted += padded.at(i) | |
| if calc.rem(i + 1, 4) == 0 and i + 1 != width { formatted += " " } | |
| } | |
| return formatted | |
| } | |
| // 1. 数值列 | |
| let col-val = [#num] | |
| // 2. 绝对值的二进制表示列 | |
| let abs-bin = str(calc.abs(num), base: 2) | |
| let col-abs = [#abs-bin(绝对值)] | |
| // 3. 原码列 | |
| let raw-bin = to-bin-str(num, bits) | |
| let col-raw = [#raw-bin] | |
| // 4. 补码计算过程列 | |
| let col-comp = if num >= 0 { | |
| raw-bin | |
| } else { | |
| // 负数计算逻辑 | |
| let abs-val = calc.abs(num) | |
| // 反码:原码每一位取反(针对原码字符串,保持空格) | |
| let inverse-str = "" | |
| for char in raw-bin { | |
| if char == "0" { inverse-str += "1" } else if char == "1" { inverse-str += "0" } else { inverse-str += char } | |
| } | |
| // 补码:计算结果 | |
| let comp-val = calc.pow(2, bits) - abs-val | |
| let comp-str = to-bin-str(comp-val, bits) | |
| // 模拟图片中的加 1 竖式 | |
| align(right)[ | |
| #inverse-str \ | |
| $+$ #h(1fr) $1$ \ | |
| #line(length: 100%, stroke: 0.5pt) | |
| #text(red)[#comp-str] | |
| ] | |
| } | |
| // 返回表格行数据 | |
| return (col-val, col-abs, col-raw, col-comp) | |
| } | |
| // 主绘图表格函数 | |
| #let complement-table(numbers, bits: 16) = { | |
| table( | |
| columns: (auto, auto, auto, auto), | |
| inset: 10pt, | |
| align: horizon + center, | |
| stroke: (x, y) => if y == 0 { (bottom: 1pt + black) } else { (bottom: 0.5pt + black) }, | |
| // 表头 | |
| [*数值*], [*绝对值的二进制表示*], [*原码*], [*补码*], | |
| // 填充数据行 | |
| ..numbers.map(n => complement-steps(n, bits: bits)).flatten(), | |
| ) | |
| } | |
| #let bin-complement-to-dec(bin-strs, bits: 16) = { | |
| // 1. 辅助函数:手动实现二进制字符串转十进制 | |
| let bin-to-int(s) = { | |
| let val = 0 | |
| let clean = s.replace(" ", "") | |
| let char-list = clean.clusters() | |
| let len = char-list.len() | |
| for i in range(len) { | |
| if char-list.at(i) == "1" { | |
| val += calc.pow(2, len - 1 - i) | |
| } | |
| } | |
| return val | |
| } | |
| // 2. 辅助函数:格式化显示(每 4 位加空格) | |
| let format-bin(s) = { | |
| let clean = s.replace(" ", "").replace("-", "") | |
| let res = "" | |
| let chars = clean.clusters() | |
| for i in range(chars.len()) { | |
| res += chars.at(i) | |
| if calc.rem(i + 1, 4) == 0 and i + 1 != chars.len() { res += " " } | |
| } | |
| res | |
| } | |
| // 3. 辅助函数:手动补齐长度 (替代不规范的 pad) | |
| let pad-left(s, target-len) = { | |
| let current-len = s.len() | |
| if current-len < target-len { | |
| return "0" * (target-len - current-len) + s | |
| } | |
| return s | |
| } | |
| let rows = () | |
| for b-str in bin-strs { | |
| let clean-b = b-str.replace(" ", "").replace("-", "") | |
| // 补码最高位为 1 则为负数 (假设长度对齐) | |
| let is-negative = clean-b.clusters().at(0) == "1" | |
| // 1. 补码列 | |
| let col-comp = format-bin(clean-b) | |
| // 2. 转换步骤列 | |
| let col-steps = if not is-negative { | |
| [正数:直接转换] | |
| } else { | |
| let val = bin-to-int(clean-b) | |
| // 模拟 -1 操作 | |
| let minus-one-val = val - 1 | |
| let minus-one-str = pad-left(str(minus-one-val, base: 2), bits) | |
| // 模拟 取反 操作 | |
| let inverse-str = "" | |
| for char in minus-one-str.clusters() { | |
| if char == "0" { inverse-str += "1" } else if char == "1" { inverse-str += "0" } | |
| } | |
| align(right)[ | |
| #format-bin(clean-b) (补码) \ | |
| $-$ #h(1fr) $1$ \ | |
| #line(length: 100%, stroke: 0.5pt) | |
| #format-bin(minus-one-str) (反码) \ | |
| #v(0.5em) | |
| 取反后:#format-bin(inverse-str) (原码) | |
| ] | |
| } | |
| // 3. 绝对值与最终数值 | |
| let total-val = bin-to-int(clean-b) | |
| let final-abs = 0 | |
| let final-dec = 0 | |
| if is-negative { | |
| final-abs = calc.pow(2, bits) - total-val | |
| final-dec = -final-abs | |
| } else { | |
| final-abs = total-val | |
| final-dec = total-val | |
| } | |
| rows += (col-comp, col-steps, [#final-abs], [*#final-dec*]) | |
| } | |
| table( | |
| columns: (auto, auto, auto, auto), | |
| inset: 10pt, | |
| align: horizon + center, | |
| stroke: (x, y) => if y == 0 { (bottom: 1pt + rgb("#e4007f")) } else { (bottom: 0.5pt + gray) }, | |
| // 修正了 bits-bit 的变量名错误 | |
| [*补码 (#bits bit)*], [*转换步骤 (-1, 取反)*], [*绝对值*], [*十进制*], | |
| ..rows, | |
| ) | |
| } | |
| #bin-complement-to-dec(("1101 1011",), bits: 8) | |
| #complement-table((-37,), bits: 8) | |
| == 13 \~ 10 | |
| #base13-to-dec("X1Y2Z3") | |
| == 16 \~ 8 | |
| #hex-to-oct-math("BC4A8F") | |
| == 16 \~ 10 | |
| #dec-to-hex-int(2912) | |
| == 10 \~ 16 | |
| #dec-to-hex-int(1145) | |
| == 2 \~ 10 | |
| #bin-to-dec-math("101.101") | |
| == 10 \~ 2 | |
| #binary-div(10) | |
| == 10 \~ 18 | |
| #dec-to-18-int(1145) | |
| == 10(小数) | |
| #frac-to-binary-math(0.625) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment