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) - 欧几里得参照实现(验证用)
相关推荐
月疯2 小时前
卡尔曼滤波的数学计算流程
算法
黎阳之光2 小时前
黎阳之光:深耕视频孪生核心领域 构筑数字孪生全域数智新标杆
大数据·人工智能·算法·安全·数字孪生
sbjdhjd2 小时前
2026年第十七届蓝桥杯大赛软件赛省赛 Python 大学 B 组 A-F 题 完整题解(小白友好版)
python·算法·职场和发展·蓝桥杯·pycharm·开源·动态规划
nlpming2 小时前
Superpowers 项目全面解析
算法
无限进步_2 小时前
【C++】红黑树完全解析:从概念到插入与平衡维护
java·c语言·开发语言·数据结构·c++·后端·算法
DaMu2 小时前
基于后天九宫八卦阵驱动的AI具身智能体联合协同指挥防御系统:架构与实现
人工智能·算法·架构
悲伤小伞2 小时前
素数筛-试除法 埃氏筛 线性筛
数据结构·算法
Chase_______3 小时前
LeetCode 2379 & 2841 题解:一文掌握定长滑动窗口的两类变体——简单计数与 HashMap 去重
算法·leetcode·职场和发展
无限进步_3 小时前
简单聊聊 C++ 中的 unordered_map 和 unordered_set
c语言·开发语言·数据结构·c++·windows·哈希算法·散列表