std::stod解析JSON浮点会丢精度,因double类型固有精度限制(仅约15–17位十进制有效数字),原始字符串如"1.0000000000000001"转double即丢失信息;应改用jsoncons等支持延迟解析的库,将高精度数字作为字符串保留,再按需用高精度库处理。

为什么 std::stod 解析 JSON 浮点会丢精度?
JSON 规范本身不限制浮点精度,但 C++ 标准库的字符串转浮点函数(如 std::stod)在解析时依赖本地 C 库实现,可能在中间转换环节引入舍入误差。更关键的是:**原始 JSON 字符串中的数字(如 "1.0000000000000001")一旦被转成 double,就已丢失超出 IEEE 754 双精度有效位数(约 15–17 十进制位)的信息——这不是解析器的问题,而是 double 类型的固有限制。**
用 jsoncons 保留高精度字符串再按需解析
若业务要求精确还原或做等值比对(比如金融金额、科学计算校验),不能依赖自动转 double。推荐用支持“延迟解析”的库,例如 jsoncons:
- 将浮点字段声明为
jsoncons::json::string_value或直接读取为std::string,跳过自动数值转换 - 需要计算时,再用高精度库(如
boost::multiprecision::cpp_dec_float_50)从字符串构造 - 避免用
json.get<double>()</double>,改用json.as_string()获取原始字面量
示例:
jsoncons::json j = jsoncons::json::parse(R"({"price": "123.4567890123456789"})");<br>std::string price_str = j["price"].as_string(); // 保留全部字符<br>// 后续用 boost::multiprecision 处理 price_str
用 nlohmann/json 的 get_ref 避免隐式类型擦除
nlohmann/json 默认把数字全转成 double,但可通过引用方式绕过:
立即学习“C++免费学习笔记(深入)”;
- 使用
j["x"].get_ref<const json::string_t>()</const>强制读取底层存储——前提是该值确实是字符串类型(即 JSON 中写了引号) - 更稳妥的做法是预处理:让上游 JSON 生成方对需高精度字段加引号,明确标记为字符串
- 若无法修改输入源,可用正则先提取原始数字字面量(如匹配
(?),但需小心科学计数法和边界
浮点比较别用 ==,用 std::abs(a - b)
即使你用了 double,也绝不能直接比较相等:
- JSON 中的
0.1 + 0.2和0.3在double下不等——这是二进制浮点本质决定的 - 设置容差时,
epsilon要根据量级调整:1e-9对1e-10级数值过大,对1e6级又太小;建议用相对误差:std::abs(a - b) - 若涉及序列化回 JSON,注意
nlohmann/json默认输出 17 位有效数字(足够 round-trip),但std::setprecision(17)才能保证输出不失真
真正棘手的不是怎么解析,而是得想清楚:这个浮点数在你的业务里到底代表“近似测量值”还是“精确十进制量”。前者用 double 加容差,后者必须全程走字符串或十进制类型。


















