類型 | 精度 | 位寬 | C# 後綴 | 能夠表示的數值範圍 | .Net 類名 |
float | 7 位 | 32bit | F | -3.4 × 10^38 ~ +3.4 × 10^38 | System.Single |
double | 15~16 位 | 64bit | D | ±5.0 × 10^−324 ~ ±1.7 × 10^308 | System.Double |
decimal | 28~29 位 | 128bit | M | (-7.9 x 10^28 ~ +7.9 x 10^28) / (10^0 ~ 28) | System.Decimal |
3 種類型,相互間的轉換有 6 種:測試
轉換 | C# 代碼 | 精度 | 結果 |
float 轉 double | (double) 10.45F | 丟失 | 10.449999809265137D |
float 轉 decimal | (decimal) 10.45F | 正常 | 10.45M |
double 轉 float | (float) 10.45D | 正常 | 10.45F |
double 轉 decimal | (decimal) 10.45D | 正常 | 10.45M |
decimal 轉 float | (float) 10.45M | 正常 | 10.45F |
decimal 轉 double | (double) 10.45M | 正常 | 10.45D |
能夠看到只有 float 轉 double 纔會產生丟失精度的問題,可是 .Net 有個很神奇的表現是,若是把從 float 轉 double 丟失精度的結果再轉回 float,精度會被補回來,甚至中間用 decimal 多轉了一次也會補回來:this
C# 代碼 | 精度 | 結果 |
(float) 10.449999809265137D | 修正 | 10.45F |
(float) (decimal) 10.449999809265137D | 修正 | 10.45F |
因此若是在 float → double → float 或者 float → double → decimal → float 的過程當中,若是中間過程只是臨時狀態(好比存儲,傳輸)並不參與實際計算的話,那麼並不須要手動修正精度。spa
若是對於轉換後的精度有要求(好比顯示,計算,轉換爲更高精度),那麼能夠手動對轉換進行精度修正,解決方法有兩個:code
1. 用 decimal 搭橋:ci
public class SingleToDoubleHelper { public static double SingleToDouble(this float numberF) => (double)(decimal)numberF; }
2. 轉字符串後解析:字符串
public class SingleToDoubleHelper { public static double SingleToDouble(this float numberF) => double.Parse(numberF.ToString()); }
第一部分測試採用的數值比較正常,可是在帶有一大串小數的浮點數互轉的時候也會丟失精度:get
轉換 | C# 代碼 | 精度 | 結果 / 指望結果 |
float 轉 double | (double) 10.4499941F | 丟失 | 10.449994087219238D 10.4499941D |
float 轉 decimal | (decimal) 10.4499941F | 丟失 | 10.44999M 10.4499941M |
double 轉 float | (float) 10.449999809265137D | 修正 | 10.45F - |
double 轉 decimal | (decimal) 10.449999809265137D | 丟失 | 10.4499998092651M 10.449999809265137M |
decimal 轉 float | (float) 10.449999809265137448940651631M | 修正 | 10.45F - |
decimal 轉 double | (double) 10.449999809265137448940651631M | 丟失 | 10.449999809265139D - |
能夠看到具備多位小數的浮點數在互轉的時候多會發生精度丟失的問題。it
在 double 和 decimal 轉 float 的時候,結果都被給予了修正,至於這個修正是否是指望的結果要看具體應用場景。table
而由低精度浮點數向高精度浮點數轉換的時候,指望結果應該是能夠不丟失精度的(高精度浮點數能夠準確表示低精度浮點數描述的數值),可是結果倒是發生了精度丟失。對於這種狀況若是但願轉換後保留完整精度的話,就只能採用 parse 字符串的方式來處理了,由於即便使用 decimal 搭橋也會丟失精度。class
因而可知,用 decimal 搭橋完成 float 轉 double 的方法僅適用於小數位數很少的狀況,其中一個很常見的應用場景就是用 float 表示金額,可是由於某種需求要轉換到 double 進行計算或顯示。