開啟章節選單
浮點數運算
常見浮點數表達方式
之前大家應該有在前面的章節看到過 float
和 double
,這兩個資料型態都是拿來存浮點數的!那要如何表達一個浮點數呢?以下以 double
為例:
double a = 0.0025;
以數學寫法表示是一種方法,而另外一種則是科學記號:
double a = 2.5e-3;
大數也可以用科學記號,之後用各種演算法的時候常常會需要訂一個常數作為最大值,這時候就可以用科學記號,會比打很多個零之後還要慢慢算有幾個零還要快很多。但是要注意科學符號表示法的資料型態是浮點數,要用 int
強制轉型,要不然拿來宣告陣列長度之類的會出事。
const int N = 1e6; // 1000000
除法要注意
浮點數的加、減、乘法都跟整數一樣,但是除法好像不太一樣?!
cout << 5 / 2 << '\n'; cout << 5.0 / 2.0 << '\n';
這兩個輸出看起來似乎沒有差別,但是執行後會發現一個是 2
,一個是 2.5
,這是因為整數運算中 /
的答案會被自動無條件捨去,但浮點數運算則會保留小數點。
輸出的位數
有的時候題目會指定你輸出某個小數到小數點第 2 位之類的,那要怎麼辦呢? C++ 有一個函式叫做 setprecision()
:
cout << fixed << setprecision(2) << 4.0 / 3.0; //1.33
其中,後面括號放的是要保留的位數(以上面的例子來說就是保留 2 位),這個設定會持續到後面的每一筆輸出,所以如果要改的話要重新設定。
那 fixed
是幹什麼的呢?在一些情況下,C++ 會輸出包含科學記號的數字,這時候 fixed
就是用來關閉科學記號的。
浮點數誤差
當你嘗試將上面舉的例子多輸出幾位時你會發現一些奇怪的事:
cout << fixed << setprecision(20) << 4.0 / 3.0;
你會發現輸出是 1.33333333333333325932
而不是 1.33333333333333333333
,這是因為浮點數的精度有限,所以在計算的時候會有一點誤差,關於電腦裡儲存浮點數的方式有興趣的可以參考 這篇文章。而 double
和 float
的差別正是 double
能存的精準位數比較多。
那要怎麼解決呢?
- 想辦法避掉浮點數:這個方法能用的範圍有點有限,要題目條件剛好能用才行,好比說這題,所有小數皆包含個位數 0 及到小數點後第 9 位,這代表這些小數真正有差的只有小數部份,而解題過程會用到的運算也不需要真的把所有數字都當作小數處理,所以我們可以把他們的小數部分當作一般數字看待就好 ( 例如 0.000000012 當 12 ),可以完美避開浮點數加法帶來的誤差。
- 分數:有點複雜,但保證精準。好比說像這題看似解題要算斜率,絕對不要真的把斜率算出來然後弄出一個直線方程式,應該一個一個點慢慢用分數算 x, y 比例 ( 其實就是斜率 )。
- 非用不可的時候:使用誤差容忍值( eps ),要判斷相等的時候,只要
b - eps < a && a < b + eps
就可以了,比大小同理可證。
前面教過的一些數學函式如 pow
、sqrt
等也都牽涉浮點數運算,所以也要處理誤差!
小測驗
程式 cout << 1.0 + 2.0;
會輸出什麼結果?