1. Làm tròn số thực
Như chúng ta đã thảo luận, khi một số thực được gán cho một int
biến, nó luôn được làm tròn xuống số nguyên nhỏ hơn gần nhất — phần phân số đơn giản bị loại bỏ.
Nhưng thật dễ dàng để tưởng tượng một tình huống khi một phân số cần được làm tròn thành số nguyên gần nhất theo một trong hai hướng hoặc thậm chí làm tròn lên. Bạn làm gì trong trường hợp này?
Đối với trường hợp này và đối với nhiều tình huống tương tự, Java có Math
lớp có các phương thức round()
, ceil()
, và floor()
.
Math.round()
phương pháp
Phương Math.round()
thức làm tròn một số đến số nguyên gần nhất:
long x = Math.round(real_number)
Nhưng có một sắc thái khác ở đây: phương thức này trả về một long
số nguyên (không phải là int
). Vì số thực có thể rất lớn nên những người tạo ra Java đã quyết định sử dụng loại số nguyên có sẵn lớn nhất của Java: long
.
Theo đó, nếu một lập trình viên muốn gán kết quả cho một int
biến, thì cô ấy phải chỉ rõ ràng cho trình biên dịch rằng cô ấy chấp nhận khả năng mất dữ liệu (trong trường hợp số kết quả không khớp với một int
loại).
int x = (int) Math.round(real_number)
Ví dụ:
Tuyên bố | Kết quả |
---|---|
|
|
|
|
|
|
Math.ceil()
phương pháp
Phương Math.ceil()
thức làm tròn một số lên đến một số nguyên. Dưới đây là các ví dụ:
Tuyên bố | Kết quả |
---|---|
|
|
|
|
|
|
Math.floor()
phương pháp
Phương Math.floor()
thức làm tròn một số xuống một số nguyên. Dưới đây là các ví dụ:
Tuyên bố | Kết quả |
---|---|
|
|
|
|
|
|
Tất nhiên, khi làm tròn một số xuống một số nguyên, việc sử dụng toán tử truyền kiểu sẽ dễ dàng hơn:(int)
Tuyên bố | Kết quả |
---|---|
|
|
Nếu bạn cảm thấy khó nhớ những tên này, một bài học tiếng Anh ngắn sẽ giúp:
Math
có nghĩa là toán họcRound
có nghĩa là trònCeiling
có nghĩa là trần nhàFloor
có nghĩa là tầng
2. Cấu trúc của số dấu phẩy động
Loại double
có thể lưu trữ các giá trị trong phạm vi từ đến . Phạm vi giá trị lớn này (so với loại) được giải thích là do loại (cũng như ) có cấu trúc bên trong hoàn toàn khác với các loại số nguyên. Bên trong, loại mã hóa giá trị của nó dưới dạng hai số: số đầu tiên được gọi là phần định trị và số thứ hai được gọi là số mũ .-1.7*10308
+1.7*10308
int
double
float
double
Giả sử chúng ta có số 123456789
và lưu nó vào một double
biến. Khi chúng tôi thực hiện, số được chuyển đổi thành , và bên trong loại lưu trữ hai số — và . Ý nghĩa ("phần quan trọng của số" hoặc phần định trị) được đánh dấu bằng màu đỏ, trong khi số mũ được đánh dấu bằng màu xanh lam.1.23456789*108
double
23456789
8
Cách tiếp cận này cho phép lưu trữ cả số rất lớn và số rất nhỏ. Nhưng vì biểu diễn của số bị giới hạn ở 8 byte (64 bit) và một số bit được sử dụng để lưu trữ số mũ (cũng như dấu của phần định trị và dấu của số mũ), các chữ số tối đa có sẵn để biểu diễn phần định trị là 15 .
Đây là một mô tả rất đơn giản về cách các số thực được cấu trúc.
3. Mất chính xác khi làm việc với số thực
Khi làm việc với số thực, hãy luôn nhớ rằng số thực không chính xác . Có thể luôn có lỗi làm tròn và lỗi chuyển đổi khi chuyển đổi từ thập phân sang nhị phân. Ngoài ra, nguyên nhân phổ biến nhất của lỗi là mất độ chính xác khi cộng/trừ các số ở các tỷ lệ hoàn toàn khác nhau.
Sự thật cuối cùng này là một chút khó hiểu đối với các lập trình viên mới làm quen.
Nếu chúng ta trừ từ , chúng ta nhận được .1/109
109
109
Trừ các số trên các tỷ lệ hoàn toàn khác nhau | Giải trình |
---|---|
|
Số thứ hai là cực kỳ nhỏ , điều này sẽ khiến ý nghĩa của nó (được đánh dấu bằng màu xám) bị bỏ qua. 15 chữ số có nghĩa được đánh dấu bằng màu cam. |
Chúng ta có thể nói gì, lập trình không giống như toán học.
4. Cạm bẫy khi so sánh số thực
Một mối nguy hiểm khác đang rình rập các lập trình viên khi họ so sánh các số thực. Nó phát sinh khi làm việc với các số thực, vì các lỗi làm tròn có thể tích lũy. Kết quả là có những tình huống khi các số thực được cho là bằng nhau, nhưng thực tế lại không như vậy. Hoặc ngược lại: các con số dự kiến sẽ khác nhau, nhưng chúng bằng nhau.
Ví dụ:
Tuyên bố | Giải trình |
---|---|
|
Giá trị của biến a sẽ là 1000000000.0 Giá trị của biến c sẽ là 1000000000.0 (số trong b biến quá nhỏ) |
Trong ví dụ trên, a
và c
không nên bằng nhau, nhưng chúng thì có.
Hoặc hãy lấy một ví dụ khác:
Tuyên bố | Giải trình |
---|---|
|
Giá trị của biến a sẽ là 1.0 Giá trị của biến b sẽ là1.0 |
5. Một sự thật thú vị vềstrictfp
Java có một strictfp
từ khóa đặc biệt ( strict f loating p point ), từ khóa này không có trong các ngôn ngữ lập trình khác. Và bạn có biết tại sao bạn cần nó không? Nó làm giảm độ chính xác của các hoạt động với các số dấu phẩy động. Đây là câu chuyện về việc nó đã ra đời như thế nào:
GO TO FULL VERSION