① 前端 js(java - double 類型 )數字精度詳解
在數字計算中,我們常會遇到一些詭異的現象,尤其是在前端JavaScript和後端Java的double類型數字計算時。這往往源於兩種語言對數字的存儲方式——使用IEEE 754標準的雙精度64位浮點數。這就意味著我們常規的十進制計算在轉換成二進制後進行計算,再轉回十進制時,可能會出現精度丟失的現象。接下來,我們將探討數字從十進制轉換為二進制的過程,以及為什麼在進行十進制與二進制之間的轉換時會丟失精度。
首先,我們來看整數的二進制轉換。以數字17為例,計算過程如下:17除以2得到商8餘1;8除以2得到商4餘0;以此類推,直到商為1。將得到的余數從低位到高位排列,得到二進制數10001。如果數字為100,計算過程類似,最終得到的二進制數為1100100。
對於整數二進制轉換為十進制的過程,我們只需將二進制數從右到左進行2的冪次方運算,然後將結果相加。例如,二進制數0010011轉換為十進制,逆序排列後得到0010011,計算過程為:0*2^0 + 0*2^0 + 1*2^2 + 0*2^0 + 0*2^0 + 1*2^5 + 1*2^6 = 100。
接著,我們討論小數的轉換。小數轉換為二進制時,將小數乘以2,取整數部分作為二進製表示的第1位,將小數部分繼續乘以2,得到的整數部分作為二進製表示的第2位,以此類推。如果小數部分出現循環,無法停止,那麼在編程語言中表示小數時就可能出現誤差。以0.1為例,計算過程如下:0.1*2得到0.2,取整得到0;0.2*2得到0.4,取整得到0;繼續計算直至小數部分為0,最終得到二進制數0001001001001001……,如果是2.1,則為10.0001001001001……
為什麼數字轉換會出現不精確的情況呢?這與JavaScript中數字的存儲方式有關。JavaScript中的數字採用IEEE 754標準的雙精度64位浮點數來存儲,表示格式為:(s) * (m) * (2 ^ e),其中s表示符號位,m表示尾數,佔52位,e表示指數,佔11位。根據ECMAScript 5規范,e的范圍是[-1074, 971],最大表示值為1 * (2^53 - 1) * (2^971) = 1.7976931348623157e+308,最小表示值為1 * 1 * (2 ^ -1074) = 5e-324。因此,JavaScript能夠表示的最大整數是2^53 - 1,即9007199254740991,最小的正數為5e-324,最大值為1.7976931348623157e+308。
在進行十進制與二進制之間的轉換時,由於數值的存儲和表示方式的限制,可能會導致精度丟失。例如,當我們進行十進制的0.1和0.2相加時,最終結果可能會是0.30000000000000004,這是因為浮點數在轉換和計算過程中可能會產生極小的誤差。
解決這個問題的方法之一是將數字轉換為字元串進行處理,這樣可以避免浮點數的精度問題。在實際應用中,後端處理數據時,最好將數字轉換為字元串格式傳遞給前端,以避免精度丟失。對於在JavaScript內部進行安全范圍內的計算,保持精度,可以使用庫類如bignumber,提供高精度的數學計算功能。
總結來說,數字轉換過程中出現不精確的現象,主要源於計算機對數字的存儲方式以及計算方式的限制。理解並掌握數字轉換的基本原理和解決方法,對於提升編程能力和開發質量至關重要。
② 挖一挖:PostgreSQL Java里的double類型存儲到varchar精度丟失問題
前言
在使用Java JDBC將double類型數據插入到PostgreSQL資料庫的表中時,發現不同版本的PostgreSQL(11與12及後續版本)插入的數據結果不一致。本文將探討此問題的可能原因和解決方法。
分析
在Java代碼中,使用的是相同的JDBC驅動。問題可能出在驅動層根據伺服器端不同版本發送的數據不同,或伺服器端對於客戶端傳入的數據處理方式不同。為了尋找答案,我們查看了SQL日誌。
通過修改`postgresql.conf`文件,將`log_statement`設置為`all`,我們得以查看詳細的SQL日誌。結果表明,在伺服器端綁定參數值時,數據在PG11與PG12版本中發生了變化。進一步,檢查JDBC客戶端驅動層日誌,發現了關鍵信息。
在PG12的日誌中,我們注意到當`extra_float_digits`參數設置為3時,數據出現精度損失。而在PG11中,相同參數設置下,數據保留了較高的精度。這揭示了問題的根源在於伺服器端處理浮點數的方式在不同版本間存在差異。
總結與模擬重現
綜合分析,驅動層發送給伺服器端的指令在不同PostgreSQL版本間並未發生變化,問題在於伺服器端對於`extra_float_digits`參數值為3時,處理浮點數轉為`float8`(double precision)的機制不同。在PG11版本中,數據在轉換過程中保留了較高的精度,而在PG12及後續版本中,則出現了精度損失。
了解`extra_float_digits`參數用於控制浮點數值的顯示位數,對於理解問題的產生至關重要。該參數調整用於文本輸出浮點值的位數,不同設置影響了輸出的精度和易讀性。通過對比不同版本的處理方式,我們確認了問題原因在於伺服器端在處理浮點數時的精度控制不同。
總結,通過對比分析兩端的日誌信息,可以深入挖掘並解決此類問題。同時,通過簡單的SQL片段可以重現問題,有助於進一步驗證和理解問題的根源。
參考資源
本文基於以下資源撰寫:
enterprisedb.com/blog/j...
jdbc.postgresql.org/doc...
postgresqlco.nf/doc/zh/...