big.newint不能直接写超int64范围字面量,因其参数类型限定为int64,超限字面量会在编译期静默截断;正确方式是new(big.int).setstring("12345678901234567890", 10)并检查返回的ok值。

Go 的 math/big 不是“更高精度的 float64”,而是完全不同的数值模型——它不依赖二进制浮点表示,因此没有 IEEE 754 的舍入误差;但它的“精度”必须显式声明、手动管理,否则结果可能看似正确实则无效。
big.Int 初始化时为什么不能直接写 big.NewInt(12345678901234567890)?
因为 big.NewInt 只接受 int64 参数,而 12345678901234567890 在编译期就被 Go 当作字面量处理,超出 int64 上限(9223372036854775807)后会静默截断,导致值错误。
- 错误写法:
big.NewInt(12345678901234567890)→ 实际传入的是截断后的int64值 - 正确写法:
new(big.Int).SetString("12345678901234567890", 10) - 字符串解析失败不 panic,但返回
ok == false,必须检查:if _, ok := x.SetString(s, 10); !ok { /* 处理错误 */ } - 用户输入、JSON 字段、配置文件中的大数,一律走
SetString,别试图用strconv.ParseInt中转
big.Float 的 SetPrec(10) 是什么意思?不是保留 10 位小数
SetPrec 的单位是**二进制位(bits)**,不是十进制小数位。设成 10 意味着最多约 3 位有效十进制数字(因为 log₁₀(2¹⁰) ≈ 3.01),远低于常见业务需求。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 默认精度是 0,行为未定义,必须显式调用
SetPrec - 模拟
float64精度:用SetPrec(53)(IEEE 754 double 的尾数位) - 金融或高精度场景建议
SetPrec(256)或更高 -
Text('g', 20)的 20 是“最大有效数字位数”,不是小数位;要固定小数位,得先用Round或外部四舍五入逻辑 - 从
float64赋值(如SetFloat64(0.1))会带入原始二进制误差,应优先用字符串:SetString("0.1", 10)
为什么 a.Add(a, b) 之后 a 就变了?
*big.Int 所有算术方法(Add、Mul、Div 等)都是就地修改,第一个参数是目标变量,不是“返回新对象”。这设计是为了避免频繁堆分配,但极易误用。
-
a.Add(a, b)→ 把a + b写回a,原a值丢失 - 想保留原值?必须显式拷贝:
copy := new(big.Int).Set(a) - 链式调用不可靠:
a.Add(b, c).Mul(d, e)会失败,因为Mul不接受*big.Int返回值当接收者 - 高频循环中,反复
new(big.Int)比复用一个实例慢 3–5 倍;推荐预分配:tmp := new(big.Int),然后循环内用tmp.SetInt64(0)或tmp.Set(nil)重置
big.Int 和 big.Float 之间能直接转换吗?
不能。二者语义不同:整数无精度损失,浮点数本质是近似表示;强行互转会掩盖溢出、截断或精度坍塌问题。
- 没有
Int.ToFloat()或Float.ToInt()方法 - 从
*big.Int到*big.Float:用SetInt,但要注意目标Float的精度是否足够容纳该整数(否则低位丢失) - 从
*big.Float到*big.Int:用Int方法(向下取整)或Round后再转,必须明确取整策略 - 最危险的误用:
big.NewFloat(x.Int64()).SetPrec(256)—— 先转成int64再升精度,已丢失高位信息
真正难的不是写对一行 SetString,而是记住:每个 *big.Int 都是可变状态容器,每个 *big.Float 都自带独立精度上下文,它们不共享、不隐式转换、不自动清理——所有“意外”都源于忘了手动控制这两件事。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










