当前位置:首页 > 文章列表 > Golang > Go问答 > Go GJSON 大整数使用 Float 后为什么丢失精度

Go GJSON 大整数使用 Float 后为什么丢失精度

来源:17golang原创 2026-10-13 16:07:40 0浏览 收藏

用 GJSON 读取订单号、用户 ID 或其他大整数时,直接调用 Float() 可能看到末尾数字变化。原因不是 GJSON 把 JSON 文本随机改写了,而是 Float() 返回的是 float64,大于 2^53 的整数无法全部用 IEEE-754 双精度浮点数精确表示。

官方地址:https://github.com/tidwall/gjson

如果字段是用于计算且能接受浮点语义,可以使用 Float();如果它是必须保真的编号,优先保留 Raw 或使用 String(),再按业务需要选择 Int() 或 Uint()。不要用浮点结果反推大整数原文。

先区分原始数字和浮点结果

GJSON 的 Result 同时保留了原始片段和数值字段。官方实现中,Raw 是原始 JSON 值的文本,Num 的类型是 float64;Float() 返回的正是这个浮点字段。于是同一个 JSON 数字会同时拥有“原文”和“数值近似”两条读取路径。

成员用途对大整数的含义
Raw保留 JSON 中的原始值文本适合继续做精确文本解析或记录
NumResult 内部的浮点数值受 float64 可表示精度限制
Float()返回浮点数与 Num 使用同一套精度边界
String()返回字符串表示整数原文保持数字字符时可保留原样
GJSON 原始 JSON 数字、Result Raw、Result Num、Float 和 2^53 精度边界的关系图
图1:GJSON 大整数从原始数字到 float64 的关系说明图,不是运行截图。

为什么 2^53 附近容易出现误差

float64 的有效整数精度边界通常用 2^53 表示。小于这个范围时,常见整数可以逐个表示;超过这个范围后,可表示的整数间隔会变大,两个相邻的十进制整数可能映射到同一个浮点值。

因此,下面这种现象并不矛盾:Result.Raw 仍然是原 JSON 中的数字文本,但 Result.Num 和 Float() 已经只能提供一个浮点近似值。精度损失发生在“把原文解析成浮点数”这一层,而不是发生在 JSON 字段定位上。

package main

import (
    "fmt"

    "github.com/tidwall/gjson"
)

func main() {
    jsonText := `{"order_id":9007199254740993}`
    result := gjson.Get(jsonText, "order_id")

    // Float 返回 float64;超过 2^53 的整数不能保证逐位精确。
    fmt.Printf("float=%v\n", result.Float())
    // Raw 保留 JSON 中的原始数字片段,适合继续做精确解析。
    fmt.Printf("raw=%s\n", result.Raw)
    // 整数形态的 String 可以作为不经过浮点格式化的文本读取入口。
    fmt.Printf("text=%s\n", result.String())
}

这里的重点不是某一台机器打印出什么具体末尾,而是读取 API 的语义不同:Float() 明确选择了浮点值,Raw 和整数形态的 String() 则能让后续逻辑继续接触数字文本。需要精确性时,应该把字段类型和读取方式一起设计。

用最小示例定位真正发生变化的路径

排查时可以把同一个 Result 的三种输出并列记录,不要只打印 Float():

func inspectNumber(jsonText string) {
    result := gjson.Get(jsonText, "order_id")

    // Type 用来确认 GJSON 识别到的是 Number,而不是字符串或 null。
    fmt.Println("type:", result.Type)
    // Raw 用来观察原始 JSON 数字,避免只看浮点格式化结果。
    fmt.Println("raw:", result.Raw)
    // Float 用来观察业务是否主动选择了 float64 语义。
    fmt.Println("float:", result.Float())
}

如果 Raw 中的十进制数字与 Float() 的输出不同,优先检查调用方是否把编号当成了测量值或比例值。订单号、雪花 ID、时间戳分位和外部系统主键通常不需要小数运算,使用浮点数只会增加转换风险。

按用途选择 Float、Int、Uint 与 Raw/String

GJSON 提供多个便捷方法,但它们不是同一个精度承诺。可以按字段用途做选择:

字段用途优先选择理由
展示或转发原始编号Raw 或 String()先保留数字字符,不主动经过浮点格式化
需要有符号整数运算Int()让 GJSON 按整数结果读取,并处理转换失败的边界
明确是非负计数Uint()表达无符号语义,避免把 ID 当作小数
金额比例、测量值或允许近似Float()字段本身需要浮点运算时再使用
GJSON 业务 ID 经过 Raw、Num 后选择 String、Int、Uint 或 Float 的关系图
图2:GJSON 大整数读取方式的选择关系说明图,不是运行截图。

如果业务要求比 int64 或 uint64 更大的整数范围,Raw 或 String() 只是保留文本,后续仍需交给合适的高精度整数库解析。这样可以把“JSON 定位”和“数值精度策略”分成两层,避免依赖 Float() 的近似结果。

大整数字段的选择清单

  1. 先确认字段是编号、计数,还是确实需要小数运算的测量值。
  2. 编号和主键优先观察 Raw,不要只记录 Float()。
  3. 需要整数运算时选择 Int() 或 Uint(),并处理转换边界。
  4. 需要保留原文时选择 String(),同时确认它确实是数字或字符串类型。
  5. 把大整数样例放进接口测试,比较原文与最终写回值,避免精度问题在下游才暴露。

常见问题

Float() 一定会把所有大整数改掉吗?

不一定。某些大整数恰好仍可表示,但不能把这种偶然结果当作通用保证。超过 2^53 后,应按字段需求选择精确文本或整数读取。

Raw 和 String() 有什么区别?

Raw 是 GJSON 结果里保存的原始 JSON 片段;String() 是便捷的字符串表示。对整数数字,GJSON 当前实现可以直接返回原始数字文本;如果字段类型复杂,仍要结合 Type 判断。

把大整数写成 JSON 字符串就不会丢精度吗?

字符串可以避开 JSON 数字到 float64 的转换,但它会改变接口字段类型。生产接口应先确认上下游约定,再决定使用字符串传输、整数解码还是保留原始数字文本。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go GJSON 数组条件中的单个匹配与全部匹配有什么区别Go GJSON 数组条件中的单个匹配与全部匹配有什么区别
上一篇
Go GJSON 数组条件中的单个匹配与全部匹配有什么区别
Go SJSON 怎么用 SetRaw 替换完整根 JSON
下一篇
Go SJSON 怎么用 SetRaw 替换完整根 JSON
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    460次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    521次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    539次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    488次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    307次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码