1. 前言
在現實生活中,很少需要看到很長的小數「尾巴」。例如計算商品價格、薪資、平均分數或房間面積時,通常只需要小數點後一兩位,而不是 15 位。
例如,除法結果:
double x = 10.0 / 3.0;
System.out.println(x); // 3.3333333333333335
使用者看到這樣的結果可能會嚇一跳,以為程式出錯了。因此我們常需要對數字進行四捨五入——到最近的整數、到小數點後兩位,等等。
在 Java 中有數種方便的工具可用。
2. 方法 Math.round():四捨五入到最接近的整數
最簡單的方式是使用 Math.round() 方法。它接受浮點數(可為 float 或 double),並回傳最接近的整數。
Math.round 的工作原理
- 如果小數部分小於 0.5,則向下取整。
- 如果小數部分為 0.5 或更大,則向上取整。
範例:
System.out.println(Math.round(2.3)); // 2
System.out.println(Math.round(2.7)); // 3
System.out.println(Math.round(2.5)); // 3
System.out.println(Math.round(-2.5)); // -2
回傳型別
- 若傳入 float,會回傳 int。
- 若傳入 double,會回傳 long。
float f = 5.8f;
int roundedF = Math.round(f); // 6
double d = 5.8;
long roundedD = Math.round(d); // 6
請注意:這有時會令人驚訝——對 double 四捨五入卻得到 long!如果你需要 int,就必須做顯式轉型:
int rounded = (int) Math.round(5.6); // 6
3. 四捨五入到指定位數的小數
常見需求不是取整,而是例如保留到小數點後兩位(用於金額、百分比等)。
在 Java 中並沒有像 Math.roundTo2Digits() 這樣的「魔法」方法,但可以手動完成。
方法 1:乘除的數學小技巧
- 先將數字乘以 100(如果需要兩位小數)。
- 用 Math.round 取整。
- 再除回 100。
範例:
double value = 3.14159;
double rounded = Math.round(value * 100.0) / 100.0;
System.out.println(rounded); // 3.14
運作方式:
- 3.14159 * 100 = 314.159
- Math.round(314.159) = 314
- 314 / 100.0 = 3.14
4. 數值格式化:類別 DecimalFormat
有時不僅要四捨五入,還要輸出得更美觀——指定小數位數、前導零、千分位分隔等。為此,Java 提供 java.text 套件中的 DecimalFormat 類別。
DecimalFormat 怎麼用
- 以需要的樣式字串建立物件。
- 呼叫它的 format(...) 方法。
import java.text.DecimalFormat;
double value = 3.14159;
DecimalFormat df = new DecimalFormat("0.00");
System.out.println(df.format(value)); // 3.14
樣式字串的規則
- "0.00" —— 總是顯示兩位小數(即便是整數)。
- "0.###" —— 最多三位小數,多餘的 0 不輸出。
- "#,##0.00" —— 加上千分位分隔(例如 "1,234.56")。
不同樣式的範例:
| 樣式 | 數值 | 結果 |
|---|---|---|
|
2 | 2.00 |
|
2.5 | 2.50 |
|
2.567 | 2.57 |
|
2.567 | 2.567 |
|
2.5 | 2.5 |
|
12345.678 | 12,345.68 |
千分位分隔符範例
DecimalFormat df = new DecimalFormat("#,##0.00");
System.out.println(df.format(1234567.89)); // 1,234,567.89
範例:去除多餘的結尾 0
DecimalFormat df = new DecimalFormat("0.##");
System.out.println(df.format(3.1)); // 3.1
System.out.println(df.format(3.141)); // 3.14
System.out.println(df.format(3.145)); // 3.15
5. 使用 String.format 進行格式化
在簡單情況下,使用 String.format 很方便——它類似其他語言的 printf。
double value = 3.14159;
System.out.println(String.format("%.2f", value)); // 3.14
這裡的 "%.2f" 表示「輸出小數點後兩位」。
方法比較:
- DecimalFormat —— 更強大,支援樣式與在地化,適合處理千分位分隔。
- String.format —— 較簡單,適合只需指定小數位數的情境。
6. 各種取整方法:Math.floor、Math.ceil、Math.rint
- Math.floor(x) —— 向下取整(朝較小的方向),對負數也會往更小的值。
- Math.ceil(x) —— 向上取整(朝較大的方向)。
- Math.rint(x) —— 四捨五入到最接近的整數,但回傳 double。
範例:
System.out.println(Math.floor(2.7)); // 2.0
System.out.println(Math.ceil(2.1)); // 3.0
System.out.println(Math.rint(2.5)); // 2.0 (沒錯,不是筆誤!)
System.out.println(Math.rint(3.5)); // 4.0
注意:Math.rint 有時會採用「就近偶數」的規則(亦即所謂的 banker's rounding),這能減少大量運算時的誤差累積。
7. 實用細節
視覺化:取整對照表
| 數值 | Math.round | Math.floor | Math.ceil | Math.rint |
|---|---|---|---|---|
| 2.3 | 2 | 2.0 | 3.0 | 2.0 |
| 2.5 | 3 | 2.0 | 3.0 | 2.0 |
| 3.5 | 4 | 3.0 | 4.0 | 4.0 |
| -2.3 | -2 | -3.0 | -2.0 | -2.0 |
| -2.5 | -2 | -3.0 | -2.0 | -2.0 |
四捨五入不等於格式化!
務必要理解 四捨五入 與 格式化 之間的差異。
- 四捨五入 —— 改變數值本身(例如 2.718 → 2.72)。
- 格式化 —— 改變輸出時的顯示方式(例如 2.718 → 在畫面上顯示 "2.72",但記憶體內仍是 2.718)。
double x = 2.718;
System.out.println(String.format("%.2f", x)); // 2.72
System.out.println(x); // 2.718
如果你要在後續運算中使用四捨五入後的值——請用數學方式進行四捨五入!如果只是為了輸出——使用格式化即可。
8. 四捨五入與格式化的常見錯誤
錯誤 1:只在輸出時四捨五入,後續仍使用「長尾」小數。
很常見的情況是:在畫面上輸出漂亮的格式化數值,接著在計算中卻使用原始的「長」小數。對於金額、分數與總計——請先四捨五入(例如使用 Math.round 或乘除技巧),然後再儲存/傳給使用者。
錯誤 2:以為 Math.round(x) 會回傳帶有兩位小數的 double。
Math.round() 總是取到最接近的整數:對 float 回傳 int,對 double 則回傳 long。若要保留兩位小數,請使用乘除法或格式化。
錯誤 3:用 DecimalFormat 來做運算。
DecimalFormat.format() 會回傳字串。不能把它拿去做算術:否則會發生編譯錯誤,或在轉回數值時丟出 NumberFormatException。
錯誤 4:DecimalFormat 的樣式字串不正確。
樣式必須符合預期:"0.00" 會固定顯示兩位(例如 "2.00"),而 "0.##" 會去除多餘的 0(可能是 "2"、"2.1"、"2.12")。
錯誤 5:以 100 做整數除法造成精度損失。
如果你用 int 除以 int,結果也是 int!
int a = 5;
System.out.println(a / 2); // 2,而不是 2.5!
若要做「浮點」除法,至少有一個運算元要是 double:
int a = 5;
System.out.println(a / 2.0); // 2.5
GO TO FULL VERSION