big.int.div 是向零截断的整除运算,返回 *big.int 类型商,不支持浮点除法;负数除法如 -7/3 得 -2;需用 divmod 同时获取商和满足 x=q×y+r 的余数。

big.Int.Div 是整除,不是浮点除法
Go 的 big.Int 没有提供浮点型大数除法,Div 方法只做向零截断的整除(类似 / 运算符对 int),结果仍是 *big.Int。如果你期望得到小数或商的精度值,它不会给你——直接 panic 或静默出错都不是它的行为,而是逻辑上不支持。
常见误用场景:想算 100 / 3 ≈ 33.333...,却调用 a.Div(a, b),结果得到 33 并丢失余数信息。
-
Div修改接收者,返回自身指针,典型写法:q := new(big.Int).Div(x, y) - 若
y.IsInt64() && y.Int64() == 0,会 panic:panic: integer divide by zero - 负数除法向零截断:比如
big.NewInt(-7).Div(big.NewInt(-7), big.NewInt(3))得-2(不是 -3)
big.Int.Rem 和 DivMod 一起用才能拿到完整余数
单独用 Rem 容易出错:它不检查除数是否为零,也不保证符号一致性;更稳妥的方式是用 DivMod 一次性获取商和余数,且余数满足数学定义:x = q × y + r,其中 0 ≤ |r| ,且 <code>r 与 x 同号(Go 默认行为)。
-
DivMod(q, r, x, y)要求q和r都是非 nil 的*big.Int,可复用已有变量避免频繁分配 - 若只需余数,仍建议用
DivMod而非Rem,因为Rem在 y 为负时行为不易预测(例如5.Rem(5, big.NewInt(-3))返回2,而非 -1) - 判断是否整除?看
r.Sign() == 0(即r.Cmp(big.NewInt(0)) == 0),不要用r.Int64() == 0——大数可能超出 int64 范围
余数为零的判断别用 == 0 比较
big.Int 是结构体指针,不能用 == 判断值是否为零;而且即使你解引用,r.Int64() 在 |r| ≥ 2⁶³ 时会溢出,返回错误值。
- 正确判断余数是否为零:
r.Sign() == 0(Sign()返回 0 表示零值,-1 表示负,+1 表示正) - 等价但稍慢写法:
r.Cmp(big.NewInt(0)) == 0 - 错误示范:
r.Int64() == 0(大数时未定义)、r == big.NewInt(0)(比较地址)
需要高精度小数商?得自己实现或换库
标准库不提供 big.Float 以外的大数小数除法接口,而 big.Float 是近似计算,有精度设置(Accuracies)和舍入模式。如果业务要求“精确到小数点后 N 位的整数倍表示”,比如把 a/b 表示为 (a * 10^N) / b 再取整,那仍可用 big.Int 手动缩放。
- 例如算 2 位小数:先
tmp := new(big.Int).Mul(a, big.NewInt(100)),再q := new(big.Int).Div(tmp, b),最后手动插入小数点 - 注意中间结果可能极大,要评估内存和性能;
big.Float更适合科学计算类需求,但要注意其SetPrec设置影响结果可靠性 - 没有银弹:任意精度小数除法本质是无限位问题,必须明确“你需要多少位”和“如何处理余数/截断”
实际写业务时,最容易被忽略的是余数符号规则和零值判断方式——这两处一错,整除判断就全偏了。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











