程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> .Net業務平台的數值精度陷阱與解決方法

.Net業務平台的數值精度陷阱與解決方法

編輯:關於.NET

最近公司的實施人員反映,數量小數位保留3位精度不夠,需要保留6位才行,回 想起這個問題,公司開發上線的ERP系統,數量,金額,成本的計算方式反反復復都 修改過好多次,以前都沒有對這個業務規則進行計算封裝,和統一指定規則,修改 就成了一件多而繁瑣的的事情了;現在深刻體會這些業務細節將會對業務系統的 運行是非常重要的,而業務系統規則的明晰和好的系統業務架構是對其的保證。

修改過程是一個漸進的過程,希望有過次這方面經驗的朋友提提建議,也希 望沒有注意到這些細節的朋友少走彎路,簡單歸納了下,產生錯誤地方有3個方 面:

最先意識到的是計算精度丟失,主要是這幾個原因引起的:

1、查看後台代碼的發現代碼裡有有變量是用的float或double類型,這樣精度 在計算的時候就會有精度轉換誤差,這個比較容易解決,都改為decimal 類型就可 以了;

2、是發現有很多計算的精度丟失是因為使用到中間變量的原因,而在中間變 量有保留小數位!現在修改方式第一種方式是中間變量的精度盡可能長,第二方式 是直接用原始變量來計算最終結果。

3、有部分計算是js來計算的,因為js裡沒有decimal類型的變量,這種常常會 產生精度丟失,需要最後ToFix()下保留精度。

第二方面是存儲的數值的精度丟失,是因為數字類型未設置正確, 如設置成 float ,double 類型都可能有轉換精度丟失,decimal類型沒有暫時沒有在系統中 使用過。也有種情況是中間小數位精度不夠長,數值如果用於再次計算的時候, 也將出現精度不夠的情況。我們現在一般都需要設置數字類型為numerice,數量 保留6位小數,顯示金額保留2位,計算成本保留8位小數。

第三方面是顯示的問題,在某些特定的地方,需要顯示小數位去除多余的0, 一般存在於是報表的顯示,和頁面顯示比較擁擠的地方。在報表裡最簡便的方法 是,利用公式字段去除顯示多余的0。

設置方法如下:

選擇需要格式化的字段, 選“自定義樣式”,在“四捨五 入”裡選擇0.0001,然後點“十位”後面的按鈕,輸入以下公 式:

if   Right   (ToText   ({命令_4.PartNum},   6),   6) =   "000000"   then   0   else
if Right (ToText ({命令_4.PartNum}, 6), 5) = "00000" then 1 else
if Right (ToText ({命令_4.PartNum}, 6), 4) = "0000" then 2 else
if Right (ToText ({命令_4.PartNum}, 6), 3) = "000" then 3 else
if Right (ToText ({命令_4.PartNum}, 6), 2) = "00" then 4 else
if Right (ToText ({命令_4.PartNum}, 6), 1) = "0" then 5 else 6

可以實現數字保留6位精度,如果數值有0 的地方自動去除掉多余的0

設置步驟如下圖(裡面公式稍稍有不一樣,但是都可以實現結果):

也可以用修改Sql的方式去除多余的小數位0。

SELECT
col,
col_convert = CASE
WHEN CHARINDEX('.', col) = 0
THEN col
WHEN RIGHT(col, PATINDEX('%[^0]%', REVERSE(col))) LIKE '.%'
THEN LEFT(col, LEN(col) - PATINDEX('%[^0]%', REVERSE(col)))
ELSE LEFT(col, LEN(col) - PATINDEX('%[^0]%', REVERSE(col)) + 1)
END
FROM(
SELECT col = '100' UNION ALL
SELECT col = NULL UNION ALL
SELECT col = '.100' UNION ALL
SELECT col = '.100100' UNION ALL
SELECT col = '0.' UNION ALL
SELECT col = '0' UNION ALL
SELECT col = '100.1010' UNION ALL
SELECT col = '100.0000'
)A

可以簡單對這個sql封裝成函數來實現;

最後還值得注意的有3點:

1、很多數值不正確是因為計算公式或邏輯不明確引起的,有些代碼是沒有真 正理解清楚就開始在開發了;ERP系統的開發對業務的邏輯理解是非常重要 的;

2、後台顯示去除0的方法也有一種是,在程序裡直接double.Parse()下就可 以去除掉小數位多余的0,再ToString()為字符顯示,double類型有個問題,如果數 字為連續的5位小數0,就會顯示為自動縮變為科學計算法,如果是後台顯示的地 方,可以先double.parse()下,轉為string,再轉為decimal類型就會去除掉多 余的小數位0了。

3、最先我們把數量保留3位精度,金額保留2位,和成本保留4精度,後來發現 實際業務計算的時候是不夠的,應該早考慮這方面的業務規則定義和計算,可以 使用Excel或類似的工具來早與客戶,架構師,程序員,測試員之間溝通;

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved