文章目錄
- 一、引例
- 二、浮點數表示
- 1、IEEE 754
- 2、單精度和雙精度
- 3、單精度浮點數表示法
- 4、舉例說明
- 5、代碼測驗
- 三、浮點數判定
- 1、精度定義
- 2、相等判定
- 3、不相等判定
- 4、大于等于判定
- 5、小于等于判定
- 6、小于判定
- 7、大于判定
一、引例
- 看下下面這段代碼,會輸出什么結果呢?
double x = 0;
for (int i = 0; i < 10; ++i) {
x += 0.1;
}
printf("%d\n", x == 1);
- 輸出如下:
0
- 引起這種反差的原因就是浮點誤差,浮點數在存盤的時候是有精度誤差的,所以進行浮點數等于判定的時候不能用 ‘==’,那么接下來我們看下浮點數的表示;
二、浮點數表示
1、IEEE 754
- IEEE二進制浮點數算術標準(IEEE 754)是20世紀80年代以來最廣泛使用的浮點數運算標準,為許多CPU與浮點運算器所采用,這個標準定義了表示浮點數的格式(包括負零 -0)與反常值),一些特殊數值(無窮(Inf)與非數值(NaN)),以及這些數值的“浮點數運算子”,
- 基于這個規定,任何浮點數都可以表示成如下形式:
( V a l u e ) 2 = S i g n ? F r a c t i o n ? E x p o n e n t (Value)_2 = Sign * Fraction * {Exponent} (Value)2?=Sign?Fraction?Exponent
Sign 表示符號位,代表正數還是負數;
Faction 代表尾數,用科學計數法表示,一定是以1開頭,例如: 1.010100111;
Exponent 代表指數,1001 實際上是 2 9 2^9 29 的意思;
2、單精度和雙精度
- C++ 中兩種浮點數, f l o a t float float 和 d o u b l e double double,分別代表單精度和雙精度;
- 單精度尾數占23個位元位,指數占8個位元位;雙精度尾數占52個位元位,指數占11個位元位;
- 由于結構相同,這里只介紹單精度浮點數;
3、單精度浮點數表示法
- 如圖為 32位 的浮點數的二進制表示,總共 32 個位元位(取值 0 或 1);

- 1)S 在最高位,代表符號,負數為1,正數為0;
- 2)E 為從高到低的第 30 - 23 位,總共 8 位,代表指數偏移,存盤的是加上了 127 以后的值(原因是指數有可能是負數);
- 3)F 代表二進制科學計數法的尾數,總共 23 位,因為是科學計數法,所以開頭一定是 “1.” 開頭,所以尾數有效位數為 24 位;
4、舉例說明
【示例】 對于 ? 18.375 -18.375 ?18.375 這個浮點數,求出它的二進制存盤格式;
- 1)首先去掉符號,最后在二進制表示的最高位置1就行,那么接下來就是求 18.375 的實際二進制表示;
- 2)整數部分 18 的二進制為: 18 = 16 + 2 = 2 4 + 2 1 = ( 10010 ) 2 18 = 16 + 2 = 2^4 + 2^1 = (10010)_2 18=16+2=24+21=(10010)2?
- 3)小數部分 0.375 的二進制表示為: 0.375 = 0.125 + 0.25 = 2 ? 3 + 2 ? 2 = ( . 011 ) 2 0.375 = 0.125 + 0.25 = 2^{-3} + 2^{-2} = (.011)_2 0.375=0.125+0.25=2?3+2?2=(.011)2?
- 4)整合整數和小數部分后,得到: ( 18.375 ) 10 = ( 10010.011 ) 2 (18.375)_{10} = (10010.011)_2 (18.375)10?=(10010.011)2?
- 5)表示成科學計數法得到: ( 18.375 ) 10 = ( 1.0010011 ) 2 ? ( 100 ) 2 (18.375)_{10} = (1.0010011)_2 * (100)_2 (18.375)10?=(1.0010011)2??(100)2?
- 6)于是得到尾數 F = 0010011 F = 0010011 F=0010011(舍棄掉科學計數法中的 “1.”),后面用 0 補齊;階數需要加上127,, E = ( 100 + 1111111 ) 2 = ( 10000011 ) 2 E = (100 + 1111111)_2 = (10000011)_2 E=(100+1111111)2?=(10000011)2?;符號位 S = 1 S = 1 S=1;
S: 1
E: 10000011
F: 00100110000000000000000
- 7)填充到二進制中得到:
SEF = 11000001 10010011 00000000 00000000
5、代碼測驗
- C/C++ 中可以用如下代碼對浮點數取地址轉換成整型后輸出整數的二進制表示;
float a = -18.375;
unsigned int v = *((unsigned int *)&a);
三、浮點數判定
1、精度定義
- 在 C++ 中, 1 e ? 6 1e-6 1e?6 代表 1 0 ? 6 10^{-6} 10?6,即 0.000001 0.000001 0.000001,是一個比較合適的精度值;
#define eps 1e-6
2、相等判定
- 介于浮點數的表示方式,不能用 ‘==’ 進行相等判定,必須將兩數相減,取絕對值以后,根據結果是否小于某個精度來判定兩者是否相等;
bool EQ(double a, double b) { // EQual
return fabs(a - b) < eps;
}
3、不相等判定
- ‘不相等’ 就是 ‘相等’ 的 ‘非’(取反);
bool NEQ(double a, double b) { // NotEQual
return !EQ(a, b);
}
4、大于等于判定
- ‘大于等于’ 就是 ‘大于 或 等于’ 的意思,需要拆分成如下形式:
bool GET(double a, double b) { // GreaterEqualThan
return a > b || EQ(a, b);
}
5、小于等于判定
- ‘小于等于’ 就是 ‘小于 或 等于’ 的意思,需要拆分成如下形式:
bool SET(double a, double b) { // SmallerEqualThan
return a < b || EQ(a, b);
}
6、小于判定
- ‘小于’ 就是 ‘大于等于’ 的 ‘非’,需要拆分成如下形式:
- 注意:千萬不能直接用 a < b a < b a<b;
bool ST(double a, double b) { // SmallerThan
return a < b && NEQ(a, b);
}
7、大于判定
- ‘大于’ 就是 ‘小于等于’ 的 ‘非’,需要拆分成如下形式:
- 注意:千萬不能直接用 a > b a > b a>b;
bool GT(double a, double b) { // GreaterThan
return a > b && NEQ(a, b);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/231541.html
標籤:其他
上一篇:對于跨域問題的新認識
