018二进制GCD(Stein算法)- 用位运算代替除法的最大公因数

二进制GCD(Stein算法)- 用位运算代替除法的最大公因数

两种算法的故事:一种更快的求最大公约数的方法

5W1H 发明者故事

Who(何人)- 发明者是谁?

发明者 :Josef Stein(生卒年不详)
背景

  • Stein 是以色列计算机科学家,1960年代在以色列理工学院(Technion)从事研究
  • 他注意到,在二进制计算机上,除法运算远比加减法和位移运算慢,因此寻找一种只用这些快速运算就能计算 GCD 的方法
  • Donald E. Knuth 在《计算机程序设计艺术》第二卷 4.4.1节系统分析了该算法的性质

相关背景人物

  • Euclid(欧几里得,约前 300 年):发明了经典欧几里得 GCD 算法,依赖整除运算
  • Stein 的工作本质上是对欧几里得算法的"二进制硬件友好化"改造

当时的处境:1960 年代早期,计算机硬件除法(尤其是大整数除法)是一个相对昂贵的操作。Stein 希望找到一种适合二进制机器的 GCD 算法。

When(何时)- 什么时候发明的?

时间 :1967 年,Stein 在《Journal of Computational and Applied Mathematics》上发表
时代背景

  • IBM 360 系列正在普及,整数除法需要数十个时钟周期
  • 位移操作(左移、右移)只需 1 个时钟周期
  • RISC 架构思想(简化指令集)开始萌芽,算法对硬件指令的适配变得重要
  • 密码学和数论算法开始走进计算机科学主流

Where(何地)- 在哪里发明的?

地点 :以色列,以色列理工学院(Technion - Israel Institute of Technology),位于海法
环境

  • 以色列 1960 年代的技术发展期,大学计算机科学系刚刚建立
  • 以色列数学和计算机科学传统强大,后来发展成为"初创国家"的技术根基
  • 中东地区第一批计算机之一安装于 Technion,Stein 有机会直接接触早期硬件

What(何事)- 发明了什么?

算法 :二进制 GCD 算法(Binary GCD Algorithm / Stein's Algorithm)
核心概念:利用以下数学性质,完全避免除法,只使用位移、减法和奇偶判断:

复制代码
性质1:gcd(0, n) = n,gcd(m, 0) = m
性质2:gcd(2m, 2n) = 2 × gcd(m, n)          [都是偶数]
性质3:gcd(2m, n)  = gcd(m, n)  (n为奇数)  [只有一个偶数]
性质4:gcd(m, n)   = gcd(|m-n|, min(m,n))   (m,n都是奇数)[两个奇数]

关键突破

  • 完全消除了除法运算
  • n & 1(测试最低位)代替 n % 2
  • n >> 1(右移一位)代替 n / 2
  • 在支持位运算的处理器上比欧几里得算法更快

Why(何因)- 为什么发明?

要解决的问题

  1. 除法代价高:在早期计算机和嵌入式系统中,整数除法需要多个时钟周期
  2. 硬件适配:二进制计算机天然支持位运算,而欧几里得算法依赖取模(即除法)
  3. 大整数 GCD:在多精度算术中,除法的代价尤为昂贵

当时的挑战

  • 需要证明算法终止性和正确性
  • 四种情形的递归/迭代处理需要仔细验证
  • 实际上,现代 CPU 的除法已经很快,Stein 算法的优势主要体现在嵌入式和大整数场景

动机:Stein 在使用早期计算机进行数论计算时,发现欧几里得算法在大数上花费大量时间在除法运算,于是寻找只依赖减法和位移的替代方案。

How(何果)- 如何实现?有什么影响?

迭代实现(伪代码)

复制代码
binary_gcd(m, n):
  若 m==0,返回 n;若 n==0,返回 m
  k = 0
  // 提取公因子 2^k
  while m 和 n 都是偶数:
    m >>= 1; n >>= 1; k++
  // 消除 m 中的因子 2
  while m 是偶数: m >>= 1
  loop:
    while n 是偶数: n >>= 1  // 消除 n 中的因子 2
    若 m > n: swap(m, n)
    n = n - m
    若 n == 0: 返回 m * 2^k

历史影响

  • 成为嵌入式系统和密码学大整数库中的标准 GCD 算法
  • GNU libgmp 在特定情形下使用 Stein 算法的变体
  • OpenSSL 的 BN_gcd(大整数GCD)中有类似实现
  • 在不支持硬件除法的 CPU(如某些微控制器)上,Stein 算法是唯一实用选择

名言:Knuth 在 TAOCP 中写道:"Stein 算法的美在于它把欧几里得算法的核心思想重新表述为一种二进制机器更'自然'的语言。"


自然语言需求定义

需求名称:实现二进制 GCD(Stein 算法),不使用除法,结果与欧几里得算法完全一致

功能需求(用精确的中文描述)

  1. 欧几里得 GCD(参照实现):用于正确性验证

    • 输入:两个非负整数
    • 操作:辗转相除法
    • 输出:最大公因数
  2. 二进制 GCD(Stein 算法):主实现

    • 输入:两个非负整数
    • 操作:仅使用位运算、减法、比较;按四种情形递推
    • 输出:最大公因数
  3. 正确性验证:对多组输入,两种方法结果相同

    • 输入:测试用例集合
    • 操作:对每组 (m, n) 分别调用两种算法,比较结果
    • 输出:一致返回 true

约束条件

  • 不使用除法运算符 / 和取模运算符 %(仅 binary_gcd 函数)
  • 支持 0 作为输入(边界情形)
  • 输入为 unsigned int 类型

验收标准(必须可验证)

编号 测试场景(自然语言描述) 预期结果 验证方式
1 gcd(12, 8) 4 直接验证
2 gcd(0, 5) 5(零的处理) 直接验证
3 gcd(17, 13)(两个奇素数) 1 直接验证
4 gcd(1024, 256)(2的幂) 256 直接验证
5 gcd(m, m)(相等) m 本身 验证 gcd(100,100)=100
6 与欧几里得结果一致(1000组随机测试) 所有结果相同 循环比较
7 gcd(1, 任意数) 1 gcd(1, 999999)=1

AI 生成提示

复制代码
基于以上需求和验收标准,用标准C语言实现二进制GCD(Stein算法)。

要求:
1. 使用标准C99
2. 主函数 binary_gcd(m, n) 内部只使用 >>、<<、&、|、- 和比较,不使用 / 和 %
3. 参照实现 euclidean_gcd(m, n) 用于验证
4. 在main中实现全部7个验收标准
5. 测试通过输出 "✓ 测试X通过",失败输出 "✗ 测试X失败"

核心函数:
- binary_gcd(m, n) - Stein算法,只用位运算和减法
- euclidean_gcd(m, n) - 欧几里得参照实现

C语言实现文件

对应文件 : binary_gcd.c

编译运行:

bash 复制代码
gcc -std=c99 -Wall -o binary_gcd_test binary_gcd.c
./binary_gcd_test

核心函数:

  • binary_gcd(m, n) - Stein 二进制 GCD,不使用除法
  • euclidean_gcd(m, n) - 欧几里得参照实现(验证用)
相关推荐
kkeeper~5 小时前
0基础C语言积跬步之数据在内存中的存储
c语言·数据结构·算法
2401_868534785 小时前
论企业网络设计
数据结构
wabs6666 小时前
关于贪心算法的一些自我总结【力扣45.跳跃游戏II】【灵感来源:代码随想录】
算法·贪心算法·复盘
2401_876964136 小时前
【湖北专升本】2026湖北专升本真题PDF+备考资料汇总
数据结构·人工智能·经验分享·深度学习·算法·计算机视觉
嗝o゚7 小时前
CANN GE 算子融合——融合算法与调度策略
算法·昇腾·cann·ge
小江的记录本7 小时前
【JVM虚拟机】垃圾回收GC:垃圾回收算法:标记-清除、标记-复制、标记-整理、分代收集(附《思维导图》+《面试高频考点清单》)
java·jvm·后端·python·算法·安全·面试
Ulyanov8 小时前
用声明式语法重新定义Python桌面UI:QML+PySide6现代开发入门(一)
开发语言·python·算法·ui·系统仿真·雷达电子对抗仿真
数据科学小丫8 小时前
特征工程处理
人工智能·算法·机器学习
z落落9 小时前
C#参数区别
java·算法·c#
c2385610 小时前
vector(下)
数据结构·算法