知识卡片

JSON/XML对数值编码的模糊性在大整数场景下暴露精度问题

普通读书笔记卡

内容

JSON、XML、CSV作为文本格式广受欢迎,但在数值编码上都有微妙的模糊性。XML和CSV根本 不区分数字和字符串(除非引用外部模式);JSON区分了字符串和数值,但不区分整数和 浮点数,也无法指定精度。这个问题在处理大数值时会真正暴露出来:大于2^53的整数无法 用IEEE 754双精度浮点数精确表示,而很多语言(如JavaScript)在解析JSON数值时统一用 浮点数处理,导致这类大整数被静默地丢失精度。Twitter的真实案例:推特用64位整数作为 每条推文的ID,这类ID经常超过2^53,Twitter API的应对方式是在返回的JSON里对同一个 ID提供两种表示——一种是JSON原生数值类型,一种是十进制字符串——让开发者可以选用 字符串版本来避免JavaScript程序解析出错误数值。这个案例的通用启示是:一个编码格式 声称”支持数值”,不等于它能无损地表示所有你实际需要的数值范围和精度;在设计跨语言、 跨系统的数据交换格式或API时,遇到可能超出常见数值精度边界(如2^53)的字段,需要 显式考虑是否要用字符串或其他方式规避精度丢失,而不能想当然地假设”JSON数值等于 我程序里的数值”。

参考来源

- 位置:《数据密集型应用系统设计》第四章《编码与演化》"JSON,XML和二进制变体" (源文件:_epub-src/ch4_split_000.html) - 结论依据:原文说明XML/CSV不区分数字与字符串、JSON不区分整数和浮点数且无法指定 精度,大于2^53的整数在使用浮点数的语言(如JavaScript)中会不准确,并举Twitter API同时返回JSON数值和十进制字符串两种推特ID表示来规避该问题的真实案例,直接 支撑本卡片结论。 - 原始内容:JSON虽然区分字符串与数值,但不区分整数和浮点数,而且不能指定精度…… 大于2^53的整数无法使用IEEE 754双精度浮点数精确表示……Twitter API返回的JSON 包含了两种推特ID,一种是JSON数值,另一种是十进制字符串,以避免JavaScript程序 无法正确解析数字的问题。