6.10隨筆(關於C語言float和double類型的精度問題)

先看下面的代碼以及輸出:

int main()
{
    double a = 80.845;
    float b = 80.845;
    printf("%.2lf %.2f\n", a, b);

    double c = 2.005;
    float d = 2.005;
    printf("%.2lf %.2f\n", c, d);

    double e = 2.05;
    float f = 2.05;
    printf("%.1lf %.1f\n", e, f);
    return 0;
}
Output:
80.84 80.85
2.00 2.01
2.0 2.0

衆所周知,doublefloat都是浮點數,他們的輸入輸出格式分別對應%lf%f
由於計算機內部都是用0011存儲數據,所以存儲整數的時候不會存在精度問題,但是存儲小數就會有問題了,因爲21=0.52^{-1}=0.522=0.25......2^{-2}=0.25 ... ...,如果我們要存儲的數爲0.70.7,我們是無法準確的對其進行存儲的。
另外,double的精度比float高,再加上輸出會默認四捨五入,結合上面的輸出,我們可以猜想:2.005以double的形式存儲的時候真實值小於2.005,以float的形式存的時候,其真實值略大

實際上,用代碼也可以很直觀的看出來:

int main()
{
    double a = 2.005;
    float b = 2.005;
    printf("%.20lf\n%.20f\n", a, b);
    return 0;
}
Output:
2.00499999999999989342
2.00500011444091796875

考慮到精度問題,接下來是圍繞精度問題的一個問題:四捨五入

在以%f或者%lf輸出的時候,程序會默認四捨五入,但是遇到了像上面的情況怎麼辦呢?
很簡單,在後面加上一個略小的數即可,但是這個數也不是隨便加的。我覺得,如果要保留n位小數,那麼加上0.000…001(小數點後面n+2/3/4個0的位置)比較合適。這個值絕對不能太大,不然本來不進位的進位了,也不能十分小,不然沒效果。

另外一種是模擬進位,使用int強轉,捨棄小數部分的原理

兩種方法:

int main()
{
    double a = 1.00000005;  //保留七位小數
    printf("%.7f\n", a);    //不處理精度會出錯
    printf("%.7f\n", a + 0.0000000001); //方法一
    printf("%.7f\n", int(a * 10000000 + 0.5) / 10000000.0); //方法二
    return 0;
}
Output:
1.0000000
1.0000001
1.0000001
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章