C++ - Floating-Point Precision,float,double (C++軟體開發 - 浮點數精度 概念與實例)

◎基本概念 

關於浮點數的規範必須先了解IEEE 754,float與double皆遵守IEEE 754,常見的有單精度float(32bits)和雙精度double (64bits)。

 ◎簡述IEEE754概念 



1.將要表示的數正規化  

10進位正規化範例  :



2進位正規化範例 : 
小數點前必只有一個一個1


2.將正規化後的數放入下面格式內

單精度float(32bits),雙精度double(64bits),bits數分配 :
 


各格式表示 :


(-1)sign  x  (1+ .fraction)  x  2 exponent - exponent bias

 

Sign : 正負
正為0,負為1
Exponent : 指數部分,正規化後的次方數

為達到快速比較指數大小(不用考慮正負)的目的,exponent採用數偏移值表示法(biased notation)
exponent bias= 2e-1 - 1(e =  exponent Bit數)
以單精準度(single precision)來說,32bit ,exponent Bit數 = 8 ,所以exponent bias =  127。
以雙精準度(doubleprecision)來說,64bit ,exponent Bit數 = 11 ,所以exponent bias =  1023。

32bits ,exponent 數值所表示的指數如下表 :

0000 0000最小,1111 1111最大。


10進位
exponent值
實際
表示指數

0
0000 0000
-127
 X
例外
1
0000 0001
-126

2
0000 0010
-125

.

.

127
0111 1111
0
bias
128
1000 0000
+1

.

.

254
1111 1110
+127

255
1111 1111
+128
X
例外


例 :

 -0.75

 =
(-1)sign  x  (1+ .fraction)  x  2 exponent - exponent bias

=


(-1)1 x (1+ .1 ) x 2126-127

 內容是 :




Fraction : 有效數(小數位)

如上例,放置小數點後的數值。

3.例外



 

表示
exponent
fraction
0
0
0
非正規數
0
0
正規數
1 ~ 2e - 2
任意
無限大
2e - 1
0
NaN(not a number)
2e - 1
0

當exponent = 0 ,fraction為非0時IEEE允許有些數值以非正規形式的浮點數表示,比正規化更接近於0 。

32bit非正規形式
=  
(-1)sign  x  (0.fraction)  x  2 -126



Single precision
double precision
表示
exponent
fraction
exponent
fraction

0
0
0
0
±0
0
任意非0
0
任意非0
非正規化數
1 ~ 254
任意
0~2046
任意
正規化數
255
0
2047
0
無限大
255
任意非0
2047
任意非0
NaN


正規化最小

Sign  exponent                                  fraction
0
0000 0001
000 0000 0000 0000 0000 0000

= 1.0 x 2-126
1.18 x 10-38

正規化最大
Sign  exponent                                  fraction
0
1111 1110
111 1111 1111 1111 1111 1111
= 1.1111 1111 1111 1111 1111 111 x 2127
≈3.4 x 1038

非正規化最小
Sign  exponent                                  fraction
0
0000 0000
000 0000 0000 0000 0000 0001
= 0.0000 0000 0000 0000 0000 001 x 2-126
= 1.0 x 2-149
1.4 x 10-45

非正規化最大
Sign  exponent                                  fraction
0
0000 0000
1111 1111 1111 1111 1111 111
= 0.11111111111111111111111 x 2-126
≈1.18 x 10-38
 

◎精準度


精準度是看fraction存幾個bits。

float : 23 mantissa bits + 1 hidden bit :
轉為十進位


log224 = 7.2247198 digits
 

double : 52 mantissa bits + 1 hidden bit :
轉為十進位


log253 = 15.954589 digits
 
◎結論

類型
bit
有效數
float
32
6~7
double
64
15~16
 

不論是單精度還是雙精度,它可以表示的小數還是有限的。每個 Compiler 提供之浮點數規格可能不盡相同,如果寫浮點數運算是要非常小心的。 

了解一下下面程式碼的結果
#include "stdafx.h"
#include <iostream>
#include <limits>  
#include <iomanip>

using namespace std;

int main() {

    // a = b
    //float a = 1.12345678f;
    //float b = 1.12345679f;

    //a < b
    //float a = 1.1234567f;
    //float b = 1.1234568f;

    //a = b
    //double a = 1.1234567890123456;
    //double b = 1.1234567890123457;

    //a < b
    //double a = 1.123456789012344;
    //double b = 1.123456789012345;

    //a < b
    //double a = 1.12345678;
    //double b = 1.12345679;

    if (a > b) {
        cout << "a > b" << endl;
    }

    else if (a == b) {
        cout << "a == b" << endl;
    }
    else {
        cout << "a < b" << endl;
    }

    return 0;
}


留言