将 JSON 中的数值作为字符串传输的主要原因是为了消除传输过程中的任何精度损失或歧义。
确实,JSON 规范没有指定数值的精度。这并不意味着 JSON 数字具有无限精度。这意味着未指定数字精度,这意味着 JSON 实现可以自由选择对其实现或目标方便的任何数字精度。如果您的应用有特定的精度要求,这种可变性可能会带来麻烦。
精度损失通常在数值的 JSON 编码中并不明显(1.7 很好且简洁),但在接收端的 JSON 解析和中间表示中表现出来。 JSON 解析函数可以相当合理地将 1.7 解析为 IEEE 双精度浮点数。然而,有限长度/有限精度十进制表示总是会遇到其十进制扩展不能表示为有限数字序列的数字:
无理数(如 pi 和 e)
1.7 在基数 10 表示法中具有有限表示,但在二进制(基数 2)表示法中,1.7 无法精确编码。即使有接近无限数量的二进制数字,您也只能接近 1.7,但永远无法精确地达到 1.7。
因此,将 1.7 解析为内存中的浮点数,然后打印该数字可能会返回类似 1.69 的值,而不是 1.7。
JSON 1.7 值的使用者可以使用更复杂的技术来解析值并将其保留在内存中,例如使用定点数据类型或任意精度的“string int”数据类型,但这并不能完全消除某些数字的转换精度损失。事实上,很少有 JSON 解析器会采用这种极端的措施,因为大多数情况下的好处很低,而且内存和 CPU 成本很高。
因此,如果您想向消费者发送精确的数值,并且不希望将该值自动转换为典型的内部数字表示形式,那么最好的选择是将数值作为字符串发送出去,并准确地告诉消费者如果需要对字符串执行数字运算,则应如何处理该字符串。
例如:在一些 JSON 生成器(JRuby 等)中,BigInteger 值会自动以字符串形式输出到 JSON,这主要是因为 BigInteger 的范围和精度比 IEEE 双精度浮点数大得多。将 BigInteger 值减少为双倍以便作为 JSON 数字输出通常会丢失有效数字。
另外,JSON 规范 (http://www.json.org/ http://www.json.org/) 明确指出 NaN 和无穷大 (INF) 对于 JSON 数值无效。如果需要表达这些边缘元素,就不能使用JSON数字。您必须使用字符串或对象结构。
最后,还有另一个方面可能导致选择将数字数据作为字符串发送:显示格式的控制。前导零和尾随零对于数值来说无关紧要。如果发送 JSON 数值 2.10 或 004,转换为内部数字形式后,它们将显示为 2.1 和 4。
如果您发送的数据将直接显示给用户,您可能希望您的金钱数字在屏幕上很好地排列,小数点对齐。一种方法是让客户端负责格式化数据以供显示。另一种方法是让服务器格式化数据以供显示。对于客户端来说,在屏幕上显示内容可能更简单,但是如果客户端还需要对值进行计算,这可能会使从字符串中提取数值变得困难。