.Net 避免 float 轉 double 丟失精度的辦法

第一部分:float 轉 double 丟失精度

類型 精度 位寬 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 進行計算或顯示。

相關文章
相關標籤/搜索