压缩比计算失真主因是输入字节数被float64解析污染,而非公式本身;应确保分子分母均为int64整数,优先用os.Stat().Size()或json.Number安全解析。

压缩比本身是数学比值,不是浮点数精度问题的重灾区;真正出问题的是你用 float64 去算它时,输入数据(比如文件大小)已经被 JSON 或其他方式悄悄“污染”了。
为什么压缩比计算会失真?
常见错误不是压缩比公式本身错,而是参与计算的原始字节数不准。比如:
- 从 HTTP 响应头或 JSON API 拿到的
"compressed_size": 12345678901234567890,Go 默认解析成float64,最后几位就丢了 → 后续除法结果必然偏差 - 用
os.Stat().Size()是安全的(返回int64),但若你中间转了一次json.Unmarshal到map[string]interface{},再取值强制转int64,大概率 panic 或得错值 -
float64能精确表示的整数上限是2^53 - 1(约 9e15),而一个 10GB 文件是10^10字节,还在安全范围内;但 10TB 级别(1e13)+ 高频累加/乘除后,误差就开始肉眼可见
怎么安全拿到原始字节数?
关键不是改压缩比公式,而是确保分子分母都是“干净”的整数。优先级如下:
- 如果数据来自本地文件系统:直接用
os.Stat().Size(),返回int64,零风险 - 如果来自 JSON API,且字段可能超
2^53:结构体字段声明为json.Number,例如CompressedSize json.Number `json:"compressed_size"`,再调.Int64();失败则 fallback 到.String()+strconv.ParseInt() - 如果必须用
map[string]interface{}(如泛化解析):先dec.UseNumber(),再断言为json.Number,严禁直接value.(float64) - 前端必须配合发字符串:
{"compressed_size": "12345678901234567890"},Go 结构体对应字段加,string标签:CompressedSize string `json:"compressed_size,string"`
压缩比公式要不要用 decimal?
一般不用。压缩比常用于日志、监控、阈值判断(比如“压缩比 int64,用 float64(float64(orig)/float64(compressed)) 完全够用。
立即学习“go语言免费学习笔记(深入)”;
- 只有当你需要把压缩比存进财务级账单、做累计加权平均、或参与金额类运算时,才值得上
decimal - 上
decimal的代价:所有中间值必须用decimal.NewFromInt()初始化,漏一步(比如decimal.NewFromFloat(float64(x)))就前功尽弃 - 示例(不推荐日常用):
decimal.NewFromInt(orig).Div(decimal.NewFromInt(compressed)).Round(4)
最易被忽略的一点:很多人查了半天 gzip 库源码,以为要调参数,其实问题根本不在压缩逻辑里——在你喂给它的那个数字,早就不是原来的数字了。


















