我們先看一段代碼,可以在控制台程序中執行看看結果
{ double d = 500; double d1 = 233.84; double d2 = d - d1; //d2=266.15999999999997 } { double d = 0.4; double d1 = d + d + d; //d1=1.2000000000000002 double d2 = d * 3; //d2=1.2000000000000002 } { double d = 1.2; double d1 = d / 0.4; //d1=2.9999999999999996 }
看到結果,你可能驚訝或者不驚訝,認為計算機計算出現這種精度問題很正常,但是當你做判斷時,發現1.2!=0.4*3或者3!=1.2/0.4,你就會懵逼了
bool b1 = 1.2 == 0.4 * 3;//false bool b2 = 3 == 1.2 / 0.4;//false
更有甚者,將計算出來的double類型直接保存在數據庫,那保存的也是上面那一堆的小數,后來者看到這個也是奔潰的!
更大的影響是在做金額運算時,我們一般都是精確到分,但是有時會計會發現自己計算出來的數據和我們系統中的對不上,我們的第一感覺也是精度問題,往往會做一個四舍五入,向上取值,向下取值等等操作,那么更大的問題來了,比如向下取值,你會發現1.2/0.4向下取整等於2!
double b = Math.Floor(1.2 / 0.4);//b=2
心中一萬只草泥馬奔騰而過!
float、double和decimal
float、double和decimal是C#中表示浮點數的類型
類型 | 名稱 | bit | 有效數字 | 數值范圍 | 是否基礎類型 |
float | 單精度浮點數 | 32 | 7 | ±1.5×10E−45 ~ ±3.4×10E38 | 是 |
double | 雙精度浮點數 | 64 | 15/16 | ±5.0×10E−324 ~ ±1.7×10E308 | 是 |
decimal | 高精度浮點數 | 128 | 28 | ±1.0×10E−28 ~ ±7.9×10E28 | 否 |
float和double都是基礎類型,區別就是表示的數值范圍和精度不一樣,而decimal是C#作為補充加上來的一個類型,不是基礎類型,它擁有更高的精度,但是表示的數值范圍卻小多了,而且計算速度相對來說要慢一些,但是也足夠一般的業務需求了,比如上面的例子,如果把double都換成decimal就不會出現問題了。
float、double和decimal都有精度丟失問題,只不過他們在丟失時的精度條件不一樣,而且精度丟失了還不報異常。
個人建議
1、在項目中盡可能的使用decimal,雖然decimal也會出現精度丟失問題,但是一般業務需求是沒問題的。
2、當方法返回浮點類型時,或者返回的實體包含有浮點類型,那么在返回時一定要考慮要不要處理精度問題。
3、在對外輸出或者存儲時,如保存到數據庫,一定要根據自己的需求做個精度處理。
4、當基礎類型在不同類型之間轉換時,盡可能的使用Convert類中的方法,少用強制轉換。
5、盡量避免使用浮點數做比較,如果愣是比較,可以先做精度處理或者先轉換成整型再比較。