最近在編寫單元測試的時候,我需要一個將浮點數「四捨六入五成雙」的函式。一開始我想:這很容易:只要把整數部分和小數部分用 modf
分開,再寫一些判斷式就可以了。modf
的函式原型如下:
double modf(double input, double* integral_part);
不過寫到一半覺得要判斷的條件很多(必須考慮正負數、整數部分的奇偶判斷),我就在想:libm 應該要有「四捨六入五成雙」的函式才對呀。
四捨五入:round
接著我就看到 round
函式:
double round(double input);
然而我仍然無法通過單元測試。仔細檢查後,我發現 libm 的 round
函式是「四捨五入(遠離零)」。換句話說:round(2.5)
的回傳值是 3.0
而不是我想要的 2.0
。
四捨六入五成雙:rint
最後我才看到 rint
函式:
double rint(double input);
這個函式會根據 Rounding Mode 回傳與 input 對應的整數。如果 Rounding Mode 是 FE_TONEAREST
,rint
函式就會是「四捨六入五成雙」。
另外,Rounding Mode 是全域變數,需要透過 fegetround
函式與 fesetround
函式存取。
範例程式碼如下:
#include <fenv.h>
#include <math.h>
#include <stdio.h>
int main() {
fesetround(FE_TONEAREST);
for (double val = -2.0; val <= 2.0; val += 0.25) {
printf("input=%.2f round=%.2f rint=%.2f\n",
val, round(val), rint(val));
}
}
輸出結果:
input=-2.00 round=-2.00 rint=-2.00
input=-1.75 round=-2.00 rint=-2.00
input=-1.50 round=-2.00 rint=-2.00
input=-1.25 round=-1.00 rint=-1.00
input=-1.00 round=-1.00 rint=-1.00
input=-0.75 round=-1.00 rint=-1.00
input=-0.50 round=-1.00 rint=-0.00
input=-0.25 round=-0.00 rint=-0.00
input=0.00 round=0.00 rint=0.00
input=0.25 round=0.00 rint=0.00
input=0.50 round=1.00 rint=0.00
input=0.75 round=1.00 rint=1.00
input=1.00 round=1.00 rint=1.00
input=1.25 round=1.00 rint=1.00
input=1.50 round=2.00 rint=2.00
input=1.75 round=2.00 rint=2.00
input=2.00 round=2.00 rint=2.00
附錄:modf/round/rint 的變型
libm 的 modf
、round
與 rint
依照參數型別,各自有給 float
型別的 f
變型與給 long double
型別的 l
變型(後綴):
參數型別 | modf | round | rint |
---|---|---|---|
double |
modf |
round |
rint |
float |
modff |
roundf |
rintf |
long double |
modfl |
roundl |
rintl |
round
與 rint
依照回傳型別,各自有給 long
型別的 l
變型與給 long long
型別的 ll
變型(前綴):
參數型別 | 回傳型別 | round | rint |
---|---|---|---|
double |
double |
round |
rint |
long |
lround |
lrint |
|
long long |
llround |
llrint |
|
float |
float |
roundf |
rintf |
long |
lroundf |
lrintf |
|
long long |
llroundf |
llrintf |
|
long double |
long double |
roundl |
rintl |
long |
lroundl |
lrintl |
|
long long |
llroundl |
llrintl |
參考資料
- cppreference.com, std::round
- cppreference.com, std::rint
- cppreference.com, std::nearbyint