一直很奇怪C#的預約義數據類型中爲何加了一個decimal,有float和double不就夠了嗎?今天來挖一挖。html
浮點型安全
Nameapp |
CTS Type性能 |
Description測試 |
Significant Figuresui |
Range (approximate)spa |
---|---|---|---|---|
float.net |
System.Singleunix |
32-bit single-precision floating pointhtm |
7 |
±1.5 × 10?45 to ±3.4 × 1038 |
double |
System.Double |
64-bit double-precision floating point |
15/16 |
±5.0 × 10 ?324 to ±1.7 × 10308 |
若是咱們在代碼中寫一個12.3,編譯器會自動認爲這個數是個double型。因此若是咱們想指定12.3爲float類型,那麼你必須在數字後面加上F/f:
float f = 12.3F;
decimal類型
做爲補充,decimal類型用來表示高精度的浮點數
Name |
CTS Type |
Description |
Significant Figures |
Range (approximate) |
---|---|---|---|---|
decimal |
System.Decimal |
128-bit high precision decimal notation |
28 |
±1.0 × 10?28 to ±7.9 × 1028 |
從上表能夠看出,decimal的有效位數很大,達到了28位,可是表示的數據範圍卻比float和double類型小。decimal類型並非C#中的基礎類型,因此使用的時候會對計算時的性能有影響。
咱們能夠像以下的方式定義一個decimal類型的浮點數:
decimal d = 12.30M;
對decimal、float、double錯誤的認識
在精確計算中使用浮點數是很是危險的,儘管C#在浮點數運算時採起了不少措施使得浮點數運算的結果看起來是很是正常的。但實際上若是不清楚浮點數的特性而貿然使用的話,將形成很是嚴重的隱患。
考慮下面的語句:
double dd = 10000000000000000000000d;
dd += 1;
Console.WriteLine ( "{0:G50}", dd );
輸出是什麼?誰知道?
輸出是:1000000000000000000000000
這就是浮點數精度損失的問題,最重要的是,在精度損失的時候,不會報告任何的錯誤,也不會有任何的異常產生。
浮點數的精度損失可能在不少地方出現,例如d * g / g 不必定等於d,d / g * g也不必定等於d。
還有兩個很是危險的錯誤認識!!
一、decimal不是浮點型、decimal不存在精度損失。
下面有段程序你們能夠去看看結果是什麼。記住!全部的浮點型變量都存在精度損失的問題,而decimal是一個徹徹底底的浮點型,不論它精度有多高,精度損失依然存在!
decimal dd = 10000000000000000000000000000m;
dd += 0.1m;
Console.WriteLine ( "{0:G50}", dd );
二、decimal所能儲存的數比double大,從double到decimal的類型轉換不會出現任何問題。
微軟在decimal的幫助上真的要好好檢討了。實際上只有從整形到decimal的轉換纔是擴大轉換,decimal的精度比double大,但所能儲存的最大數卻比double要小。
「decimal 類型是適合財務和貨幣計算的 128 位數據類型。」
固然,decimal在大多數狀況下是安全的,但浮點數在理論上是不安全的。
至於精度偏差形成的顯示問題,則是很容易修補的。浮點數會帶來的問題以及整型能避免的問題就是一個:
譬如說從A賬戶轉帳到B賬戶,經計算得出結果是3.788888888888888元,那麼咱們從A賬戶扣除這麼多錢,B賬戶增長這麼多錢,但事實上A賬戶不必定會扣除準確的數值,例如A賬戶的金額在100000000000,那麼這個時候100000000000 - 3.788888888888888運算結果頗有多是99999999996.211111111111112。而這個時候B賬戶的金額爲0則頗有可能加上準確的數值,如3.788888888888888,這樣一來,0.011111111111112元錢就會不見了,日積月累的,差額就會愈來愈大。
double是64位的,比single-32位精度高
decimal128位高精度浮點數,經常使用於金融運算,不會出現浮點數計算的偏差
,decimal 類型具備更高的精度和更小的範圍,這使它適合於財務和貨幣計算。
早上剛到辦公室,就被中試室打來電話叫去,原來軟件在測試過程當中發現了個小問題:軟件讀出來的數據比設備LCD上顯示數據小了 0.01 。
怎麼會這樣呢,數據類型我已經用了 double 型了整個數據長度也就6位,double型的數據有效數據位爲7位,也夠了阿,不明白。因而回來下斷點跟蹤。
前面double型在算的時候,是沒問題的,數據是66.24,但是當我把66.24 乘上100後的處理結果就不對了:66.24*100.0d = 6623.9999…91,問題就出在這裏了。查了msdn,Double型的數據:Double 值類型表示一個值介於 -1.79769313486232e308 和 +1.79769313486232e308 之間的雙精度 64 位數字,浮點數只能近似於十進制數字,浮點數的精度決定了浮點數近似於十進制數字的精確程度。默認狀況下,Double 值的精度是 15 個十進制位,但內部維護的最大精度是 17 位。因此就出現了乘上一百後,精度就不夠了。又因爲咱們在處理數據時,是不容許四捨五入的,因此,通過單位轉換後,軟件中最終顯示的數據爲 66.23 ,比LCD上顯示的66.24 小了 0.01。
所以,這以後就想到了應該用更高精度的 decimal 型。
類型 |
大體範圍 |
精度 |
.NET Framework 類型 |
decimal |
±1.0 × 10e?28 至 ±7.9 × 10e28 |
28 到 29 位有效位 |
System.Decimal |
在聲明decimal類型數據時,能夠 a: decimal myData = 100,此時編譯器隱式轉換整型數100爲 100.0m;固然也能夠b: decimal myData = 100.0m,可是 若是是 decimal myData = 100.0d或者decimal myData = 100.0f,就不行了,由於100.0d或者100.0f,編譯器認爲是浮點數,而浮點數和decimal 類型之間不存在隱式轉換;所以,必須使用強制轉換在這兩種類型之間進行轉換。This is the important,不然編譯器便報錯。因此通常的財務軟件在處理時,都會用decimal 類型。
好了,改用decimal 型以後,就OK 了,結果就完完整整地顯示爲 66.24 了。