- 1 1. “Cắt Bớt Các Số Thập Phân” Có Nghĩa Gì Trong Java?
- 2 2. Nếu Bạn Chỉ Muốn Một int, Ép Kiểu Hoạt Động (Nhưng Có Một Cạm Bẫy)
- 3 3. Sử Dụng Math.floor / Math.ceil Để Cắt Bỏ Phần Thập Phân Đúng Đắn
- 4 4. Cách Cắt Bỏ Tại Vị Trí Thập Phân Thứ n (Phổ Biến Trong Hiển Thị & Tính Toán)
- 5 5. Cắt bớt với BigDecimal (An toàn nhất cho Tài chính, Hóa đơn và Tỷ lệ)
- 6 6. DecimalFormat / String.format Chỉ Dùng Cho Hiển Thị (Không Dùng Cho Tính Toán)
- 7 7. Best Practices by Use Case (Quick Reference)
- 8 8. Các Sai Lầm Thường Gặp và Cảnh Báo Quan Trọng
- 9 9. Tóm Tắt: Kết Luận Sao Chép Dán
- 9.1 9.1 Nếu Bạn Không Chắc, Hãy Dùng Những Cách Này
- 9.1.1 Trường hợp 1: Chuyển sang int (Chỉ Số Dương)
- 9.1.2 Trường hợp 2: Cắt Bớt Toán Học Bao Gồm Số Âm
- 9.1.3 Trường hợp 3: Cắt Bớt ở n Chữ Số Thập Phân (double, đơn giản)
- 9.1.4 Trường hợp 4: Cắt giảm đáng tin cậy tới n chữ số thập phân (Đề xuất)
- 9.1.5 Trường hợp 5: Chỉ hiển thị (Không bao giờ dùng để tính toán)
- 9.1 9.1 Nếu Bạn Không Chắc, Hãy Dùng Những Cách Này
- 10 Câu hỏi thường gặp
- 10.1 Q1. Cách dễ nhất để cắt giảm phần thập phân trong Java là gì?
- 10.2 Q2. Tại sao (int) cho kết quả không mong muốn với số âm?
- 10.3 Q3. Làm sao để cắt giảm tới hai chữ số thập phân (ví dụ, 1.239 → 1.23)?
- 10.4 Q4. Tại sao Math.floor(x * 100) / 100 đôi khi cho ra giá trị sai?
- 10.5 Q5. Cách đúng để cắt giảm bằng BigDecimal là gì?
- 10.6 Q6. Sự khác nhau giữa RoundingMode.DOWN và FLOOR là gì?
- 10.7 Q7. Tôi có thể cắt giảm phần thập phân bằng DecimalFormat không?
- 10.8 Q8. Khi nào nên áp dụng cắt giảm trong các phép tính?
1. “Cắt Bớt Các Số Thập Phân” Có Nghĩa Gì Trong Java?
Khi mọi người nói “truncate decimals” trong Java, họ thường muốn nói loại bỏ phần thập phân để tạo thành một số nguyên hoặc bỏ các chữ số sau vị trí thập phân thứ n.
Trong thực tế, “truncate” có thể có nhiều nghĩa, vì vậy hãy làm rõ kết luận ngay từ đầu.
1.1 “truncate” có nghĩa là floor? Hay cast? (Thuật ngữ)
Có chủ yếu hai kiểu “cắt bớt”:
- (A) Cắt bớt về phía 0 (truncate) Loại bỏ phần thập phân, nhưng với số âm nó di chuyển “gần hơn tới zero.” Ví dụ:
3.9 → 3,-3.9 → -3→ Trong Java, ép kiểu (int) hoạt động theo cách này - (B) Cắt bớt về phía −∞ (floor) Di chuyển xuống (hướng các giá trị nhỏ hơn) trên trục số Ví dụ:
3.9 → 3,-3.9 → -4→ Trong Java, Math.floor() hoạt động theo cách này
Người mới thường nhầm lẫn vì đối với số dương, (A) và (B) cho ra cùng một kết quả.
Nhưng ngay khi bạn xử lý số âm, kết quả sẽ khác nhau.
1.2 Bài Viết Này Giúp Bạn Làm Gì (Lộ Trình Nhanh Nhất Theo Trường Hợp Sử Dụng)
Người tìm kiếm “java truncate decimals” thường muốn một trong các mục sau:
- Chỉ chuyển thành số nguyên (ví dụ, 3.14 → 3) → Ép kiểu
(int)là nhanh nhất. Nhưng cần cẩn thận với số âm. - Cắt bớt ở 2 chữ số thập phân (ví dụ, 1.239 → 1.23) →
Math.floor(x * 100) / 100có thể hoạt động → Nhưng nếu độ chính xác quan trọng, BigDecimal an toàn hơn - Tiền tệ/hoá đơn/tỷ lệ mà lỗi không chấp nhận được → Dùng BigDecimal + setScale + RoundingMode
Nếu bạn chọn sai phương pháp, nó thường “có vẻ hoạt động” nhưng sẽ phá vỡ sau này.
Đặc biệt, các phép tính dựa trên double có thể gây ra lỗi độ chính xác, vì vậy với logic liên quan tới tiền bạc, an toàn hơn khi thiết kế ngay từ đầu bằng BigDecimal.
1.3 Những Sai Lầm Thường Gặp (Sửa Đầu Tiên)
Ba lỗi phổ biến là:
- Giả định (int) luôn có nghĩa là floor → Thực tế nó làm tròn về phía zero, vì vậy các số âm sẽ khác.
- Dùng Math.floor để cắt bớt thập phân, nhưng nhận được kết quả hơi lệch → Thường do độ chính xác của
double(phụ thuộc vào giá trị/môi trường). - Dùng định dạng (DecimalFormat, v.v.) như thể nó thay đổi giá trị tính toán → Hiển thị có thể thay đổi trong khi giá trị nội bộ vẫn giữ nguyên.
Trước hết hãy xác định con đường ngắn nhất: “Nếu bạn chỉ cần một số nguyên, hãy ép kiểu.” Sau đó hiểu “bẫy số âm”.
Trong phần tiếp theo, chúng ta sẽ giải thích cắt bớt bằng cách ép kiểu (int) với các ví dụ cụ thể.
2. Nếu Bạn Chỉ Muốn Một int, Ép Kiểu Hoạt Động (Nhưng Có Một Cạm Bẫy)
Nếu bạn chỉ muốn loại bỏ phần thập phân và nhận được số nguyên (int), cách nhanh nhất trong Java là ép kiểu (chuyển đổi kiểu).
Nhưng ép kiểu không phải là “cắt bớt toán học (floor).” Nó là làm tròn về phía zero (truncate), điều này quan trọng rất nhiều.
2.1 Cơ Bản: Cắt Bớt Phần Thập Phân Bằng (int)
Khi bạn chuyển một double hoặc float sang int, phần thập phân sẽ bị bỏ đi.
double x = 3.99;
int a = (int) x;
System.out.println(a); // 3
Đây là câu trả lời đơn giản nhất cho mục đích phổ biến “Tôi muốn cắt bớt các số thập phân.”
Các bước thực hiện:
- Xác nhận giá trị là
double/float - Thêm
(int)để ép kiểu thànhint - Kiểm tra kết quả — bao gồm cả các số âm nếu chúng có thể xuất hiện
2.2 Quan Trọng: Ép Kiểu Làm Tròn Về Phía Zero (Số Âm Khác Nhau)
Đây là bẫy số 1 cho người mới.
Ép kiểu không luôn “đánh xuống giá trị nhỏ hơn.”
System.out.println((int) 3.9); // 3
System.out.println((int) -3.9); // -3
-3.9 trở thành -3 (không phải -4) vì ép kiểu chuyển về hướng gần hơn tới zero.
3.9 → 3(về phía zero)-3.9 → -3(về phía zero)
Nếu bạn muốn “cắt bớt toán học (floor),” cần dùng Math.floor(), không phải ép kiểu.
Nếu bỏ qua điều này, bạn có thể gặp lỗi trong các tính toán như P&L, tính phí, hoặc toán học tọa độ, nơi chỉ phía âm bị sai.
2.3 Lỗi Thường Gặp: Giả Định Làm Tròn / Lỗi Với Số Âm
Casting không phải là làm tròn đến gần nhất.
Nếu bạn nghĩ “0.9 trở thành 1,” bạn sẽ sai.
System.out.println((int) 0.9); // 0
System.out.println((int) 1.9); // 1
Ngoài ra, với số âm, có thể cảm thấy giá trị “tăng” hoặc “giảm” một cách bất ngờ.
-3.9 → -3di chuyển theo hướng lớn hơn trên trục số- Nếu bạn mong đợi
-4, đây là lỗi thực sự
Sửa đơn giản:
- Nếu bạn chỉ xử lý giá trị dương → casting là ổn
- Nếu giá trị âm có thể xuất hiện → xem xét
Math.floor() - Nếu cần độ chính xác nghiêm ngặt (tiền bạc, v.v.) → xem xét
BigDecimal
Trong phần tiếp theo, chúng ta sẽ giải thích Math.floor() / Math.ceil(), cho phép bạn cắt bỏ theo cách nhất quán toán học ngay cả với số âm.
3. Sử Dụng Math.floor / Math.ceil Để Cắt Bỏ Phần Thập Phân Đúng Đắn
Nếu bạn muốn cắt bỏ phần thập phân một cách toán học đúng đắn, cách tiếp cận cơ bản là sử dụng Math.floor() thay vì casting.
Đặc biệt khi số âm có thể xuất hiện, chỉ cần chọn Math.floor() sẽ giảm đáng kể lỗi.
3.1 Cắt Bỏ Với Math.floor() (Hàm Floor)
Math.floor() được gọi là hàm floor và làm tròn giá trị xuống dưới (hướng về giá trị nhỏ hơn) trên trục số.
System.out.println(Math.floor(3.9)); // 3.0
System.out.println(Math.floor(-3.9)); // -4.0
Các điểm chính:
3.9 → 3.0(di chuyển xuống dưới)-3.9 → -4.0(di chuyển xa hơn xuống dưới)
Lợi ích lớn nhất là việc cắt bỏ không hoạt động bất ngờ với số âm.
Một lỗi phổ biến là Math.floor() trả về double.
Nếu bạn cần số nguyên, bạn phải chuyển đổi sau đó.
3.2 Math.ceil() Làm Tròn Lên — Đừng Nhầm Lẫn
Math.ceil() là ngược lại của Math.floor() và làm tròn lên trên (hướng về giá trị lớn hơn) trên trục số.
System.out.println(Math.ceil(3.1)); // 4.0
System.out.println(Math.ceil(-3.1)); // -3.0
Một lỗi phổ biến là:
- Nghĩ rằng “loại bỏ phần thập phân” nghĩa là
ceil→ Thực tế, ceil làm tròn lên , thường là ngược lại với những gì bạn muốn.
Nếu bạn tìm kiếm “cắt bỏ phần thập phân,” floor thường là lựa chọn đúng.
3.3 Chuyển Đổi Kiểu Khi Chuyển Sang long / int
Nếu bạn muốn chuyển kết quả của Math.floor() sang int hoặc long, bạn cần casting nó.
double x = -3.9;
int a = (int) Math.floor(x);
System.out.println(a); // -4
Các điểm cần chú ý:
- Kết quả của
Math.floor()làdouble - Casting sang
intloại bỏ phần thập phân (không có sự không khớp ở giai đoạn này) - Nếu giá trị quá lớn, nó có thể không vừa vào
int
Để an toàn, bạn có thể chọn long trước.
double x = 12345678901.9;
long b = (long) Math.floor(x);
System.out.println(b); // 12345678901
Các lỗi phổ biến bao gồm:
- Quên casting và để giá trị là double
- Không hiểu sự khác biệt giữa floor và casting, gây lỗi với số âm
- Tràn số khi vượt quá phạm vi của int
Tóm lại, nếu số âm có thể liên quan, cách an toàn nhất là thiết kế xung quanh Math.floor() ngay từ đầu.
Trong phần tiếp theo, chúng ta sẽ giải thích cách cắt bỏ tại vị trí thập phân thứ n (ví dụ: giữ hai chữ số thập phân) với các ví dụ cụ thể.
4. Cách Cắt Bỏ Tại Vị Trí Thập Phân Thứ n (Phổ Biến Trong Hiển Thị & Tính Toán)
Trong các ứng dụng thực tế, rất phổ biến khi muốn giữ đến một vị trí thập phân nhất định và loại bỏ phần còn lại, không chỉ loại bỏ toàn bộ phần thập phân.
Ví dụ bao gồm tỷ lệ thuế, tỷ giá hối đoái, giá đơn vị và phần trăm.
Ở đây chúng ta tổ chức các cách thực tế để cắt bỏ tại vị trí thập phân thứ n.
Khi sử dụng double, có thể xảy ra vấn đề độ chính xác, vì vậy chúng ta sẽ đề cập đến các lỗi tiềm ẩn.
4.1 Mẫu Cơ Bản: Nhân Với 10^n, floor, Sau Đó Chia
Mẫu phổ biến nhất là:
- Xác định số chữ số thập phân
n - Nhân với
10^n - Áp dụng
Math.floor() - Chia cho
10^nđể khôi phục quy mô
Để cắt bớt tới 2 chữ số thập phân (ví dụ, 1.239 → 1.23):
double x = 1.239;
double y = Math.floor(x * 100) / 100;
System.out.println(y); // 1.23
Để cắt bớt tới 3 chữ số thập phân (ví dụ, 1.2399 → 1.239):
double x = 1.2399;
double y = Math.floor(x * 1000) / 1000;
System.out.println(y); // 1.239
Ưu điểm của cách tiếp cận này:
- Mã ngắn gọn và dễ hiểu
- Sử dụng
Math.floor(), vì vậy hành vi với số âm nhất quán - Không cần thư viện bổ sung
Tuy nhiên, vì cách này dựa trên double, nên không phù hợp cho các phép tính nghiêm ngặt như tiền tệ.
4.2 Cạm bẫy: Kết quả không mong đợi do độ chính xác của double
double của Java là một kiểu số thực và không luôn có thể biểu diễn chính xác các giá trị như 0.1 hay 0.01.
Do đó, bạn có thể thấy những sự khác biệt dường như “vô nghĩa” (tùy thuộc vào giá trị và môi trường).
- Bạn mong đợi
1.29, nhưng nó hiển thị như1.28 - Bạn xử lý
0.3, nhưng bên trong nó là0.299999999...
Ví dụ, đoạn mã sau trông hợp lý về mặt logic:
double x = 1.29;
double y = Math.floor(x * 100) / 100;
System.out.println(y);
Nhưng bên trong, x * 100 có thể được biểu diễn là 128.999999999....
Nếu floor trả về 128, kết quả sẽ là 1.28.
Đây không phải là lỗi trong Java, mà là đặc tính của phép tính số thực.
Điều khó khăn là điều này xảy ra chỉ thỉnh thoảng, khiến việc phát hiện trong quá trình kiểm thử trở nên khó khăn.
4.3 Cắt bớt an toàn với BigDecimal (Đề xuất)
Nếu bạn muốn cắt bớt tại vị trí thập phân thứ n một cách đáng tin cậy, việc sử dụng BigDecimal là lựa chọn an toàn nhất.
BigDecimal xử lý các số hệ thập phân một cách chính xác và thường được dùng cho các phép tính tiền tệ.
Mẫu cơ bản là:
import java.math.BigDecimal;
import java.math.RoundingMode;
BigDecimal x = new BigDecimal("1.239");
BigDecimal y = x.setScale(2, RoundingMode.DOWN); // truncate at 2 decimal places
System.out.println(y); // 1.23
Các điểm chính:
setScale(2, ...)giữ hai chữ số thập phânRoundingMode.DOWNchỉ định cắt bớt về phía zero
Lưu ý rằng DOWN của BigDecimal không giống với Math.floor().
Với các số âm, hành vi khác nhau, vì vậy bạn cũng có thể cần xem xét FLOOR (được giải thích sau).
Các lỗi thường gặp bao gồm:
- Tạo BigDecimal từ một double (gây lỗi độ chính xác)
- Quên gọi
setScale - Sử dụng chế độ làm tròn sai và vô tình làm tròn lên half-up
Tóm lại, Math.floor có thể đủ cho mục đích hiển thị, nhưng đối với các phép tính quan trọng, BigDecimal là lựa chọn an toàn nhất.
Trong phần tiếp theo, chúng ta sẽ đi sâu hơn vào việc cắt bớt bằng BigDecimal, bao gồm cách tạo đối tượng đúng cho mã thực tế.
5. Cắt bớt với BigDecimal (An toàn nhất cho Tài chính, Hóa đơn và Tỷ lệ)
Nếu bạn muốn cắt bớt các số thập phân với độ chính xác tối đa, BigDecimal nên là lựa chọn đầu tiên của bạn trong Java.
double nhanh nhưng dễ gặp lỗi độ chính xác, thường gây ra vấn đề sau này trong các phép tính tiền, hóa đơn, phí hoặc tỷ lệ.
BigDecimal xử lý các số thập phân theo cách gần hơn với mong đợi của con người, vì vậy nó được sử dụng rộng rãi trong mã doanh nghiệp.
5.1 Cơ bản về BigDecimal: Tạo từ double là Nguy hiểm (Quan trọng nhất)
Một lỗi rất phổ biến khi dùng BigDecimal là cách nó được tạo.
Nếu bạn truyền một double trực tiếp, lỗi độ chính xác nội bộ có thể được giữ lại.
import java.math.BigDecimal;
BigDecimal a = new BigDecimal(0.1);
System.out.println(a); // May become something like 0.10000000000000000555...
Cắt bớt hoặc tính toán với giá trị này thường dẫn đến các sự khác biệt “bí ẩn”.
Các cách an toàn để tạo BigDecimal là:
(A) Tạo từ một String (rõ ràng và an toàn nhất)
BigDecimal a = new BigDecimal("0.1");
(B) Sử dụng BigDecimal.valueOf(double) (thường được khuyến nghị)
BigDecimal a = BigDecimal.valueOf(0.1);
Đối với người mới bắt đầu, quy tắc an toàn nhất là: khi không chắc, hãy tạo BigDecimal từ một String.
5.2 Cắt bớt ở n chữ số thập phân với RoundingMode.DOWN
Để cắt bớt ở chữ số thập phân thứ n, sử dụng setScale.
setScale(2, ...)→ giữ lại hai chữ số thập phânRoundingMode.DOWN→ cắt bớt về phía 0import java.math.BigDecimal; import java.math.RoundingMode; BigDecimal x = new BigDecimal("123.4567"); BigDecimal y = x.setScale(2, RoundingMode.DOWN); System.out.println(y); // 123.45
Nếu bạn muốn loại bỏ tất cả các chữ số thập phân và có một giá trị dạng số nguyên, cùng một cách tiếp cận vẫn áp dụng.
BigDecimal x = new BigDecimal("123.999");
BigDecimal y = x.setScale(0, RoundingMode.DOWN);
System.out.println(y); // 123
Một chi tiết quan trọng: setScale thay đổi giá trị thực tế, không chỉ cách hiển thị.
Đây là một phép tính, không phải định dạng.
5.3 Cắt bớt về phía 0 so với hướng Floor (Sự khác biệt quan trọng)
BigDecimal cung cấp nhiều chế độ làm tròn, và có hai chế độ trông giống như “cắt bớt”, có thể gây nhầm lẫn.
- RoundingMode.DOWN : cắt bớt về phía 0
3.9 → 3-3.9 → -3
- RoundingMode.FLOOR : cắt bớt về phía −∞ (floor toán học)
3.9 → 3-3.9 → -4
Nếu bạn muốn các giá trị luôn di chuyển về phía nhỏ hơn trên trục số, FLOOR là lựa chọn đúng.
import java.math.BigDecimal;
import java.math.RoundingMode;
BigDecimal x1 = new BigDecimal("-3.9");
System.out.println(x1.setScale(0, RoundingMode.DOWN)); // -3
System.out.println(x1.setScale(0, RoundingMode.FLOOR)); // -4
Việc “đúng” phụ thuộc hoàn toàn vào trường hợp sử dụng của bạn.
- Chỉ đơn giản loại bỏ các chữ số (cắt bớt) →
DOWN - Cắt bớt toán học (floor) →
FLOOR
Nếu sự khác biệt này không rõ ràng, các giá trị âm có thể gây ra lỗi nghiêm trọng trong đặc tả.
5.4 Các lỗi thường gặp khi dùng BigDecimal
Dưới đây là những lỗi thường gặp khi cắt bớt bằng BigDecimal:
- Tạo BigDecimal từ double và gây ra lỗi độ chính xác → Tránh
new BigDecimal(0.1); sử dụng String hoặcvalueOf - Sử dụng scale sai → Ví dụ, dùng 0 thay vì 2 chữ số thập phân
- Nhầm lẫn các chế độ làm tròn → Nhầm lẫn DOWN và FLOOR, gây vấn đề với số âm
- Thay đổi giá trị khi bạn chỉ muốn định dạng →
setScalethay đổi giá trị; tách riêng tính toán và hiển thị
Tóm lại, đối với tiền tệ, hoá đơn hoặc tỷ lệ—nơi mà ngay cả chênh lệch một xu cũng quan trọng— hãy sử dụng BigDecimal và sửa cả phương pháp tạo và chế độ làm tròn.
Trong phần tiếp theo, chúng tôi sẽ giải thích cách tránh nhầm lẫn giữa định dạng hiển thị và cắt bớt tính toán.
6. DecimalFormat / String.format Chỉ Dùng Cho Hiển Thị (Không Dùng Cho Tính Toán)
Khi cắt bớt các chữ số thập phân, việc phân biệt bạn muốn cắt bớt giá trị đã tính hay chỉ định dạng hiển thị là rất quan trọng. Kết hợp hai việc này dẫn đến trường hợp màn hình trông đúng nhưng giá trị nội bộ sai, gây lỗi sau này.
Điều quan trọng cần nhớ: DecimalFormat và String.format chỉ dùng để hiển thị. Nếu bạn cần cắt bớt giá trị thực tế, hãy sử dụng BigDecimal hoặc Math.floor().
6.1 Định dạng số thập phân với DecimalFormat (Có thể cắt bớt)
DecimalFormat là một lớp dùng để chuyển đổi số thành chuỗi đã định dạng. Ví dụ, nó thường được dùng khi bạn muốn hiển thị hai chữ số thập phân.
import java.text.DecimalFormat;
double x = 1.239;
DecimalFormat df = new DecimalFormat("0.00");
System.out.println(df.format(x)); // May become 1.24 (rounded)
Điều quan trọng là giá trị trả về của format() là một String, và giá trị số của x không thay đổi.
Bạn cũng có thể chỉ định chế độ làm tròn. Để cắt bớt hiển thị, thực hiện như sau:
import java.text.DecimalFormat;
import java.math.RoundingMode;
double x = 1.239;
DecimalFormat df = new DecimalFormat("0.00");
df.setRoundingMode(RoundingMode.DOWN);
System.out.println(df.format(x)); // 1.23
However, this only changes the displayed string; the value of x remains unchanged.
6.2 Caveats When Using String.format
String.format also lets you control numeric output formatting.
double x = 1.239;
System.out.println(String.format("%.2f", x)); // Thường làm tròn lên 1.24
In many cases, String.format("%.2f", x) performs round half up behavior.
It’s usually unsuitable if you specifically want truncation.
A very common beginner mistake is converting a formatted string back into a number and using it in calculations.
double x = 1.239;
String s = String.format("%.2f", x); // "1.24"
double y = Double.parseDouble(s); // 1.24
// Tại thời điểm này, các phép tính sử dụng giá trị đã làm tròn, không phải giá trị đã cắt bớt
This mixes display concerns into calculation logic, making future changes harder.

6.3 Key Pitfall: Correct Display Does Not Mean Correct Values
The most dangerous assumption is “it looks correct on the screen, so it must be fine.”
- DecimalFormat / String.format change how values look
- Math.floor / BigDecimal.setScale change the actual value
If you confuse these, you may run into problems like:
- The UI shows “$1.23” but internal calculations still sum “$1.239”
- Rounding happens at the wrong stage, causing billing totals to differ
- Display rounding leaks into calculations, causing audit discrepancies
A simple rule of thumb:
- Only formatting for display → DecimalFormat (or UI formatting)
- Truncating as part of calculation → BigDecimal / Math.floor
In the next section, we’ll provide a quick reference table so you can instantly choose the right approach by use case.
7. Best Practices by Use Case (Quick Reference)
“Java decimal truncation” is confusing because there are multiple valid approaches.
Here, we fix the decision by mapping use case → best solution, so you can choose quickly.
7.1 Convert to int (Positive Numbers Only) → Casting Is Enough
If you just want to remove decimals and convert to int, and negative numbers will never appear, casting is the fastest option.
double x = 12.99;
int y = (int) x;
System.out.println(y); // 12
Things to remember:
- Casting rounds toward zero
- With positive values, it looks the same as truncation
- If negatives may appear, don’t lock in this approach
7.2 Truncate Including Negative Numbers → Math.floor
If you want mathematical truncation (floor), Math.floor() is the correct choice.
It’s safer than casting when negative numbers may occur.
double x = -3.9;
int y = (int) Math.floor(x);
System.out.println(y); // -4
Common notes:
Math.floor()returns adouble- Cast to
intorlongif needed - Watch out for
intoverflow with large values
7.3 Truncate at the n-th Decimal Place (Strict) → BigDecimal + setScale
If you want to truncate at a specific decimal place without precision errors, BigDecimal is the safest option.
import java.math.BigDecimal;
import java.math.RoundingMode;
BigDecimal x = new BigDecimal("1.239");
BigDecimal y = x.setScale(2, RoundingMode.DOWN);
System.out.println(y); // 1.23
This approach is ideal for:
- Money (JPY, USD, etc.)
- Billing and tax calculations
- Rate calculations where errors are unacceptable
- Batch jobs requiring deterministic results
Common pitfalls:
- Do not create BigDecimal from double (avoid
new BigDecimal(0.1)) - Understand the difference between DOWN and FLOOR (negative numbers)
7.4 Format for Display Only → DecimalFormat (Never for Calculation)
If you only want to format numbers for display (e.g., two decimals), DecimalFormat is convenient.
However, it does not change the underlying numeric value, so never use it for calculations.
import java.text.DecimalFormat;
import java.math.RoundingMode;
double x = 1.239;
DecimalFormat df = new DecimalFormat("0.00");
df.setRoundingMode(RoundingMode.DOWN);
System.out.println(df.format(x)); // "1.23"
Ghi chú:
- Giá trị trả về là một
String - Trộn lẫn logic hiển thị vào tính toán gây ra lỗi
Trong một câu, điểm chính là:
- Nhanh & đơn giản → Ép kiểu
- Đúng khi có số âm → Math.floor
- Ưu tiên độ chính xác (thực tế) → BigDecimal
- Chỉ hiển thị → DecimalFormat
Tiếp theo, chúng ta sẽ tóm tắt các lỗi thường gặp nhất và cách tránh chúng.
8. Các Sai Lầm Thường Gặp và Cảnh Báo Quan Trọng
Việc cắt bớt thập phân thường “có vẻ hoạt động”, khiến người mới dễ bỏ qua các lỗi tinh vi. Dưới đây là các lỗi thực tế và cách tránh chúng.
8.1 Hiểu Lầm Về Ý Nghĩa “Cắt Bớt” (Hướng về 0 vs Floor)
Sai lầm phổ biến nhất là cho rằng cắt bớt luôn có nghĩa là “đi về phía nhỏ hơn”. Trong Java, ý nghĩa phụ thuộc vào phương thức.
Ép kiểu
(int): hướng về 03.9 → 3-3.9 → -3Math.floor(): hướng về −∞3.9 → 3-3.9 → -4
Nếu có thể có giá trị âm và bạn dùng ép kiểu, chỉ phần âm sẽ sai. Điều này thường không được phát hiện nếu các bài kiểm tra chỉ dùng giá trị dương.
Biện pháp phòng ngừa:
- Nếu có thể xuất hiện số âm, hãy cân nhắc dùng
Math.floor()ngay từ đầu - Khi dùng BigDecimal, đừng nhầm lẫn
RoundingMode.DOWNvàFLOOR
8.2 Kết Quả Không Mong Muốn Do Độ Chính Xác của double
Khi thực hiện cắt bớt bằng Math.floor(x * 100) / 100, bạn có thể thấy kết quả không khớp ngay cả khi logic trông đúng. Nguyên nhân là do cách biểu diễn nội bộ của double.
double x = 1.29;
double y = Math.floor(x * 100) / 100;
System.out.println(y);
Tùy vào giá trị, x * 100 có thể trở thành 128.999999999..., dẫn đến 1.28. Vì điều này không xảy ra mỗi lần, thường được phát hiện trong môi trường thực tế.
Biện pháp phòng ngừa:
- Dùng
BigDecimalcho tiền và thanh toán - Nếu dùng double, hạn chế sử dụng trong các trường hợp cho phép sai số nhỏ
8.3 Dùng double cho Tính Toán Tiền
Việc dùng double cho tiền thường dẫn đến:
- Tổng không khớp sau khi cắt bớt
- Lỗi làm tròn nhỏ tích lũy
- Sự không khớp giữa giá trị hiển thị và giá trị nội bộ
Biện pháp phòng ngừa:
- Dùng
BigDecimalcho các giá trị tiền tệ - Sửa cách tạo (String hoặc
valueOf) - Ghi rõ các quy tắc làm tròn
8.4 Dùng Định Dạng Hiển Thị cho Tính Toán
Định dạng bằng DecimalFormat hoặc String.format rồi lại chuyển ngược lại thành số là nguy hiểm.
double x = 1.239;
String s = String.format("%.2f", x); // display formatting
double y = Double.parseDouble(s); // used in calculation (dangerous)
Điều này gây ra:
- Làm tròn hiển thị rò rỉ vào tính toán
- Thay đổi yêu cầu ảnh hưởng đến logic
- Mất sự tách biệt giữa hiển thị và tính toán
Biện pháp phòng ngừa:
- Hoàn thành tính toán bằng
BigDecimalhoặcMath.floor() - Định dạng chỉ ở giai đoạn hiển thị cuối cùng
- Giữ tính toán và trình bày riêng biệt
9. Tóm Tắt: Kết Luận Sao Chép Dán
Có nhiều cách để cắt bớt thập phân trong Java, nhưng con đường nhanh nhất là chọn theo trường hợp sử dụng. Dưới đây là các kết luận sẵn sàng sử dụng.
9.1 Nếu Bạn Không Chắc, Hãy Dùng Những Cách Này
Trường hợp 1: Chuyển sang int (Chỉ Số Dương)
double x = 12.99;
int y = (int) x; // 12
Lưu ý: Với số âm, -3.9 → -3, vì vậy đây không phải là floor toán học.
Trường hợp 2: Cắt Bớt Toán Học Bao Gồm Số Âm
double x = -3.9;
int y = (int) Math.floor(x); // -4
Điểm: Math.floor() cắt bớt hướng về −∞.
Trường hợp 3: Cắt Bớt ở n Chữ Số Thập Phân (double, đơn giản)
* Chỉ sử dụng khi cho phép lỗi độ chính xác nhỏ.
double x = 1.239;
double y = Math.floor(x * 100) / 100; // 1.23
Cảnh báo: có thể xảy ra vấn đề độ chính xác của double. Đối với độ chính xác nghiêm ngặt, hãy dùng BigDecimal.
Trường hợp 4: Cắt giảm đáng tin cậy tới n chữ số thập phân (Đề xuất)
import java.math.BigDecimal;
import java.math.RoundingMode;
BigDecimal x = new BigDecimal("1.239");
BigDecimal y = x.setScale(2, RoundingMode.DOWN); // 1.23
Các điểm chính:
- Không tạo
BigDecimaltừdouble - Sử dụng cách này cho tiền tệ, thanh toán và tỷ lệ
Trường hợp 5: Chỉ hiển thị (Không bao giờ dùng để tính toán)
import java.text.DecimalFormat;
import java.math.RoundingMode;
double x = 1.239;
DecimalFormat df = new DecimalFormat("0.00");
df.setRoundingMode(RoundingMode.DOWN);
System.out.println(df.format(x)); // "1.23"
Lưu ý: Điều này tạo ra một String; giá trị số vẫn không thay đổi.
Câu hỏi thường gặp
Q1. Cách dễ nhất để cắt giảm phần thập phân trong Java là gì?
Trả lời: Nếu bạn chỉ cần một số nguyên, ép kiểu bằng (int) là nhanh nhất. Nếu có khả năng xuất hiện số âm, hãy cân nhắc dùng Math.floor().
Q2. Tại sao (int) cho kết quả không mong muốn với số âm?
Trả lời: Ép kiểu làm làm tròn về phía 0. Ví dụ, -3.9 → -3. Đối với việc cắt giảm toán học, hãy dùng Math.floor().
Q3. Làm sao để cắt giảm tới hai chữ số thập phân (ví dụ, 1.239 → 1.23)?
Trả lời: Với cách đơn giản, dùng Math.floor(x * 100) / 100. Đối với độ chính xác nghiêm ngặt, dùng BigDecimal.setScale(2, RoundingMode.DOWN).
Q4. Tại sao Math.floor(x * 100) / 100 đôi khi cho ra giá trị sai?
Trả lời: Điều này là do lỗi độ chính xác của double. Đối với tiền tệ hoặc thanh toán, hãy chuyển sang BigDecimal.
Q5. Cách đúng để cắt giảm bằng BigDecimal là gì?
Trả lời: Tạo BigDecimal từ một String hoặc valueOf, sau đó dùng setScale(n, RoundingMode.DOWN). Tránh new BigDecimal(double).
Q6. Sự khác nhau giữa RoundingMode.DOWN và FLOOR là gì?
Trả lời: Chúng khác nhau đối với số âm. DOWN cắt giảm về phía 0; FLOOR cắt giảm về −∞. Chọn dựa trên việc bạn muốn cắt giảm hay làm tròn xuống toán học.
Q7. Tôi có thể cắt giảm phần thập phân bằng DecimalFormat không?
Trả lời: Bạn có thể cắt giảm hiển thị bằng cách đặt chế độ làm tròn, nhưng chỉ dành cho việc hiển thị. Giá trị nội bộ không thay đổi.
Q8. Khi nào nên áp dụng cắt giảm trong các phép tính?
Trả lời: Điều này phụ thuộc vào yêu cầu kỹ thuật. Quyết định cắt giảm ở mỗi bước hay chỉ ở cuối, ghi rõ quy tắc và thực hiện nhất quán—tốt nhất là dùng BigDecimal.

