2016-02-29 28 views
12

某些API(如paypal API在JSON中使用字符串類型來表示十進制數)。因此"7.47"而不是7.47爲什麼要在JSON中使用字符串來表示十進制數

爲什麼/何時這是使用json數值類型的好主意? AFAIK數值類型允許無限精度以及科學記數法。

+2

因爲使用貨幣浮動只會導致錯誤的道路上。浮動不能用於表示像金錢這樣的真實世界值 - 反正不可靠。例如轉換爲浮點時,7.47實際上可能是7.4699999923423423423。一個簡單的系統,簡單地截斷額外的數字將導致7.46,現在你已經失去了一分錢...超人II(我?)的陰影。 –

+2

@MarcB我熟悉你爲什麼不使用浮動貨幣,但JSON數字實際上是浮動嗎?據我所知,這是一個獨立於語言的編號,如果傾向於使用任何語言,您可以將JSON編號直接解析爲Java BigDecmial或其他任意精度格式。 – kag0

+0

取決於它是如何在貝寶的系統開始。 json是單片文本字符串和JS數據結構之間的1:1映射。如果「數字」在json字符串中存儲爲「...」字符串,那麼它是原始數據結構中的字符串,或者是映射到字符串的字符串。 –

回答

14

將JSON中的數值作爲字符串傳輸的主要原因是爲了消除傳輸中精度或模糊性的任何損失。

的確,JSON規範沒有爲數值指定精度。這並不意味着JSON數字具有無限精度。這意味着沒有指定數字精度,這意味着JSON實現可以自由選擇任何數字精度對於其實現或目標都很方便。如果您的應用程序具有特定的精度要求,這種變化可能會很痛苦。

精度損失通常在數值的JSON編碼中不明顯(1.7很好且簡潔),但在接收端的JSON解析和中間表示中顯示。一個JSON解析函數會將1.7合理地解析爲一個IEEE雙精度浮點數。然而,有限長度/有限精度表示總是會遇到無法精確表示的數字。無理數(如pi和e)永遠無法在有限系統中準確表示。 1.7在十進制(基數爲10)中有一個有限的表示法,但在二進制(基數爲2)中,它是一個無理數 - 無限的一系列數字。

因此,將1.7解析爲內存中的浮點數,然後打印出數字可能會返回類似1.69的值 - 而不是1.7。

JSON 1.7值的使用者可以使用更復雜的技術來解析和保留內存中的值,例如使用定點數據類型或具有任意精度的「string int」數據類型,但這不會完全消除某些數字轉換過程中精度損失的幽靈。實際情況是,很少有JSON解析器會對這種極端措施感到困擾,因爲大多數情況下的好處很低,內存和CPU成本很高。

所以,如果你想發送一個精確的數字值給消費者,你不希望自動將該值轉換爲典型的內部數字表示,那麼最好的辦法是將數字值作爲字符串發送出去,告訴消費者究竟應該如何處理字符串,以及何時需要對其進行數字操作。

例如:在一些JSON生成器(JRuby,一個)中,BigInteger值會自動輸出爲JSON作爲字符串,這很大程度上是因爲BigInteger的範圍和精度比IEEE雙精度浮點數大得多。爲了輸出爲JSON數字,將BigInteger值減少一倍將經常丟失有效數字。

此外,JSON規範(http://www.json.org/)明確指出NaN和Infinities(INF)對JSON數值無效。如果您需要表達這些附帶元素,則不能使用JSON編號。你必須使用一個字符串或對象結構。

最後,還有一個方面可以導致選擇將數字數據作爲字符串發送:控制顯示格式。前導零和尾隨零對數值無關緊要。如果您發送JSON號碼值2.10或004,在轉換爲內部數字形式後,它們將顯示爲2.1和4。

如果您發送的數據將直接顯示給用戶,您可能希望您的錢數字在屏幕上排列良好,十進制對齊。一種方法是讓客戶負責格式化數據以供顯示。另一種方法是讓服務器格式化數據以供顯示。客戶端可能更簡單地在屏幕上顯示內容,但如果客戶端還需要對這些值進行計算,則這可以使得從字符串中提取數值變得困難。

+0

不要低估無理數的意義 - 有理數更多的無理數!兩者都是無限的集合,但非理性的尺度大於理性的尺度。詢問你當地的數學教授。帶上咖啡。 :> – dthorpe

+1

您可以舉出一些客戶端編碼失去精度的例子嗎?例如,Java中的傑克遜會很高興地將一個json小數轉換爲一個BigDecimal,而不會丟失任何精度。 讓一個人的API不那麼準確(這不是一個字符串,它是一個數字,這是json支持的),這是令人沮喪的,因爲一些未命名的客戶端在給定json號碼時正在做我認爲是「錯誤的事情」。 –

0

彙總版本

從@ dthorpe的回答只是引用,我覺得這是最重要的一點:

此外,JSON規範(http://www.json.org/)明確規定,NaN和無窮大(INF中)對於JSON數字值無效。如果您需要表達這些附帶元素,則不能使用JSON編號。你必須使用一個字符串或對象結構。

相關問題