天天看點

C#中decimal, double, float的差別

        一直很奇怪C#的預定義資料類型中為什麼加了一個decimal,有float和double不就夠了嗎?今天來挖一挖。

浮點型
Name CTS Type Description Significant Figures Range (approximate)
float System.Single 32-bit single-precision floating point 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。

        還有兩個非常危險的錯誤認識!!

 1、decimal不是浮點型、decimal不存在精度損失。
 下面有段程式大家可以去看看結果是什麼。記住!所有的浮點型變量都存在精度損失的問題,而decimal是一個不折不扣的浮點型,不論它精度有多高,精度損失依然存在!
decimal dd = 10000000000000000000000000000m;
dd += 0.1m;
Console.WriteLine ( "{0:G50}", dd );
2、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 型。

        在聲明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 了。

轉自http://lj.soft.blog.163.com/blog/static/79402481201032210173381/