BigInteger.gcd()是Java计算任意精度整数最大公约数的标准方法,基于Stein算法,自动取绝对值,支持零输入(a.gcd(0)返回|a|,0.gcd(0)返回0),要求全程使用BigInteger类型构造,禁止转为long等基本类型以防溢出。

BigInteger.gcd() 能直接算超大整数的 GCD,但必须确保两个数都不为零
BigInteger.gcd() 是唯一推荐用于任意精度整数求 GCD 的标准方法,它内部使用二进制 GCD 算法(Stein 算法),不依赖除法,对 BigInteger 这种不可变、无符号的大数类型非常友好。但注意:gcd() 对零的处理是定义明确的——new BigInteger("0").gcd(b) 返回 |b|,而 a.gcd(new BigInteger("0")) 返回 |a|;但如果两个都是零,结果仍是 0(数学上未定义,但 Java 明确返回 0)。
常见错误现象:NullPointerException 不会出现(因为 gcd() 不接受 null 参数,编译不过),但若传入字符串构造时格式错误(如含空格、字母),会在构造阶段抛 NumberFormatException,不是 gcd() 本身的问题。
- 务必用
new BigInteger(String)或BigInteger.valueOf(long)构造输入,别用new BigInteger(byte[])除非你清楚字节序和符号位 - 如果原始数据来自用户输入或文件,先用
String.trim()去首尾空格,再校验是否为空或全由非数字字符组成 - 负数没问题:
gcd()自动取绝对值计算,new BigInteger("-12").gcd(new BigInteger("-18"))返回6
别用 int/long 中转,否则会 silently 溢出
有人试图把大数先转成 long 再用欧几里得递归,这是典型陷阱。比如 "9223372036854775808"(即 2^63)已超出 long 正范围,BigInteger.valueOf(Long.parseLong(s)) 会直接抛异常;而用 Long.parseUnsignedLong(s) 又只支持到 2^64-1,且无法处理更大的数(如 100 位十进制数)。
正确做法只有一条路:全程保持 BigInteger 类型。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 禁止出现
long l = bigNum.longValue(); gcd(l, other)这类中转 - 不要用
intValue()/longValueExact()做“试探”,它们失败时抛异常,不是返回 false - 如果必须兼容小整数场景,统一用
BigInteger构造:哪怕数值是42,也写BigInteger.valueOf(42),而非new BigInteger("42")(后者多一次字符串解析)
性能敏感时注意:gcd() 不缓存中间结果,重复调用要自己缓存
gcd() 每次都重新计算,不记忆化。如果你在循环中反复对同一对数调用(比如在分数约分循环里),或者在递归算法中频繁复用相同子问题(如扩展 GCD 的中间步骤),就会重复劳动。
这不是 bug,是设计使然:因为 BigInteger 不可变,且 gcd() 无状态,JVM 无法安全地自动缓存。
- 若确定参数组合有限(如预设的模数集合),可用
Map<pair>, BigInteger></pair>手动缓存,注意用Pair要保证 key 不变(推荐用AbstractMap.SimpleImmutableEntry或自定义不可变 pair) - 避免用
toString()拼接做 key,开销大且易错(正负号、前导零) - 对单次调用无需优化——
gcd()在万位以内数字上通常
和 Math.gcd() 完全无关,别混淆包路径和语义
Java 9+ 引入了 Math.gcd(int,int) 和 Math.gcd(long,long),但它们属于 java.lang.Math,只处理基本类型,且对负数返回正值(符合数学定义),但完全不适用于大数。有人误以为 “既然有 Math.gcd,那 BigInteger.gcd 应该类似”,其实二者实现、接口、用途毫无关系。
错误示例:Math.gcd(a.intValue(), b.intValue()) —— 一旦 a 或 b 超出 int 范围,结果就错得离谱。
- 记牢:涉及字符串、文件读入、密码学、大素数运算等场景,只认
java.math.BigInteger.gcd() - IDE 自动导入时留意包名,别选错成
Math的静态方法 - 单元测试里故意用
new BigInteger("1000000000000000000000000")这类明显溢出long的数来验证路径是否走对
String a = request.getParameter("a"),直接丢给 new BigInteger(a),却没检查 a == null || a.isEmpty(),导致运行时报 NumberFormatException: null,而不是更友好的提示。这个点不在算法里,但在真实系统里高频发生。

















