淺析 Easy C++,C++ 浮點數類型
浮點數
浮點數是C++的第二組基本類型,它能夠表示帶小數部分的數字。不僅如此,浮點數的范圍也比int更大,可以表示更大范圍的數字。
我們都知道在計算機當中,所有數據本質上都是轉化成二進制存儲的。整數很簡單,存儲的就是轉化成二進制之后的01串,那么浮點數又是如何存儲的呢?
很容易猜到的是浮點數存儲的結果也是二進制,但相比于整型直接轉化成二進制要復雜一些。它需要先表示成下面這行式子:
這里的n即我們要存儲的浮點數,s表示符號位,m是尾數,而e則是階數。
符號位很好理解,它和整型當中的符號位一樣,0表示正數,1表示負數。m表示尾數,。我們這么看很抽象,來看一個例子,比如3.0,轉化成二進制是,相當于。那么,。
我們了解了浮點數的表示方式,那么它又是如何存儲在計算機當中的呢?這需要我們進一步地剖析其中的細節。
關于m
首先是m,m被定義成一個大于等于1,小于2的小數。我們可以簡單寫成1.xx,其中xx表示的就是小數的部分。
既然它總是大于等于1,小于2的,那么它的個位一定是1,我們就可以將它省略,僅僅看之后小數的部分。小數的部分,我們同樣使用二進制來逼近。比如0.625,可以表示成0.5 + 0.125,即,表示成二進制就是,只不過這里它的最高位是從-1開始的。
以32位的浮點數為例,除去1位表示符號,8位表示階數之后,還有23位留給m。由于我們舍掉了小數點之前的1,所以我們的階數是從-1開始的,理論上等價于24個二進制位。
關于e
在浮點數存儲當中,e是一個無符號整數。以32位浮點數為例,e一共有8位,可以表示0-255。
但e是可以為負數的,根據IEEE 754的規定,e的真實值必須再減去一個中間數。對于8位的e,它的中間數是127。比如e的實際值是10,但是存儲的時候需要存儲成127+10=137。
除此之外,e還有另外三種情況:
- e不全為0,或全為1時,采用上述的規則表示
- e全為0時,e等于1-127,有效數字m不再默認加上1,這樣是為了還原0.xxx的小數,以及接近于0的數
- e全為1時,如果有效數字m全為0,表示無窮大,如果m不全為0,表示nan(not a number)
關于e的規則看起來有些復雜,初看覺得有些難以理解,為什么要用減去中間值的設計,而不用符號位?后來仔細思考了一下才發現,如果引入符號位很難區分0.xxx以及e就是等于0的情況,雖然也可以特判處理,但就沒有現在這樣優雅了。
覺得上文看不懂的小伙伴可以直接略過這段,畢竟這個是浮點數的實現原理,算是很底層的內容了,C++ primer上對于這部分也沒有過多闡述。
浮點數的使用
C++當中有兩種浮點數的書寫方式,第一種是使用常規的小數點表示法:
- double a = 1.23;
- float b = 3.43;
另外一種寫法是科學記數法,寫成:
- double a = 2.45e8;
- double b = 1e-7;
2.45e8表示,e之后可以跟正數也可以跟負數,但數字當中不能有空格。
浮點數類型
和C語言一樣,C++也有三種浮點數類型:float,double和long double。和整型一樣,這三種類型都是浮點數,只不過表示的范圍不同。
浮點數的范圍有兩個部分綜合決定,一個部分是有效數字。比如14179是5位有效數字,而14000只有兩位,因為后面三個0都是填充位,有效數字的位數不依賴小數點的位置。C++當中要求,float至少表示32位有效數字,double至少48位,而long double至少和double一樣。
另外,它們能夠表達的指數范圍至少是-37到37。一般來說,float一共是4個字節32位,而double是8個字節64位,當然這也取決于具體的運行環境。
注意事項
關于浮點數的使用有幾點注意事項,千萬要注意。
cout輸出浮點數會刪除結尾的0
書寫浮點數常量時默認為double類型,如果需要強制表示為float類型,請在結尾加上后綴f或者F,如:2.34f
由于浮點數有精度,不能直接判斷兩個浮點數是否相等,很有可能得不到預期結果,正確的做法是判斷精度范圍,如:
- double epsilon = 1e-8;
- // 判斷a是否和b相等
- if (abs(a - b) < epsilon) {
- // todo
- }
判斷兩個浮點數a和b是否相等,等價于兩者的差的絕對值小于某一個精度。
范圍問題,如運行下列代碼將得到錯誤的結果:
- float a = 2.3e22f;
- float b = a + 1.0f;
- cout << b - a << endl;
輸出的結果將是0,因為2.3e22是一個小數點左邊有23位的數字,加上1之后,就是在第23位加上1。但是float類型只能表示數字中的前6位或者前7位,表示不了這么高的精度,因此這個+1的操作完全沒有生效。
這個問題是一個大坑,一不小心就會中招,千萬要小心。
本文轉載自微信公眾號「Coder梁」,可以通過以下二維碼關注。轉載本文請聯系Coder梁公眾號。