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 intbiế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ó Mathlớ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 longsố 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 intbiế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 intloại).

int x = (int) Math.round(real_number)

Ví dụ:

Tuyên bố Kết quả
int x = (int) Math.round(4.1);
4
int x = (int) Math.round(4.5);
5
int x = (int) Math.round(4.9);
5

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ả
int x = (int) Math.ceil(4.1);
5
int x = (int) Math.ceil(4.5);
5
int x = (int) Math.ceil(4.9);
5

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ả
int x = (int) Math.floor(4.1);
4
int x = (int) Math.floor(4.5);
4
int x = (int) Math.floor(4.9);
4

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ả
int x = (int) 4.9
4

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:

  • Mathcó nghĩa là toán học
  • Roundcó nghĩa là tròn
  • Ceilingcó nghĩa là trần nhà
  • Floorcó nghĩa là tầng

2. Cấu trúc của số dấu phẩy động

Loại doublecó 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ố .-1.7*10308+1.7*10308intdoublefloatdouble

Giả sử chúng ta có số 123456789và lưu nó vào một doublebiế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*108double234567898

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ố (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ị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ònlỗ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/109109109

Trừ các số trên các tỷ lệ hoàn toàn khác nhau Giải trình
 1000000000.000000000;
-         0.000000001;
 1000000000.000000000;
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
double a = 1000000000.0;
double b = 0.000000001;
double c = a - b;
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, ackhô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
double a = 1.00000000000000001;
double b = 1.00000000000000002;
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 strictfptừ 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:

Những người tạo ra Java:
Chúng tôi thực sự muốn Java trở nên siêu phổ biến và chạy các chương trình Java trên càng nhiều thiết bị càng tốt. Vì vậy, chúng tôi đảm bảo rằng thông số kỹ thuật cho máy Java nói rằng tất cả các chương trình phải chạy theo cùng một cách trên tất cả các loại thiết bị!
Các nhà sản xuất bộ vi xử lý Intel:
Nè mọi người! Chúng tôi đã cải tiến bộ xử lý của mình và giờ đây, tất cả các số thực được biểu thị bằng cách sử dụng 10 byte thay vì 8 byte bên trong bộ xử lý của chúng tôi. Nhiều byte hơn có nghĩa là nhiều chữ số quan trọng hơn. Điều đó nghĩa là gì? Đúng rồi! Bây giờ tính toán khoa học của bạn sẽ còn chính xác hơn!
Các nhà khoa học và tất cả những người tham gia vào các tính toán cực kỳ chính xác:
Mát mẻ! Làm tốt. Tin tức tuyệt vời!
Những người tạo ra Java:
Không-không-không, các bạn! Chúng tôi đã nói với bạn rằng tất cả các chương trình Java phải chạy giống nhau trên tất cả các thiết bị . Chúng tôi sẽ vô hiệu hóa khả năng sử dụng số thực 10 byte bên trong bộ xử lý Intel.
Bây giờ mọi thứ đã ổn trở lại! Đừng cảm ơn chúng tôi.
Các nhà khoa học và tất cả những người tham gia vào các tính toán cực kỳ chính xác:
Bạn đã hoàn toàn mất trí? Hãy nhanh chóng lấy lại mọi thứ như nó vốn có!
Những người tạo ra Java:
Các bạn, đây là vì lợi ích của riêng bạn! Hãy tưởng tượng: tất cả các chương trình Java đều chạy theo cùng một cách trên tất cả các thiết bị . Thú vị thật!
Các nhà khoa học và tất cả những người tham gia vào các tính toán cực kỳ chính xác:
Không. Nó không tuyệt chút nào. Nhanh chóng đưa mọi thứ trở lại như cũ! Hoặc bạn có biết chúng tôi sẽ đặt Java của bạn ở đâu không?
Những người tạo ra Java:
Hừm. Tại sao bạn không nói ngay lập tức? Tất nhiên, chúng tôi sẽ đặt nó trở lại.
Chúng tôi đã khôi phục khả năng sử dụng tất cả các tính năng của bộ xử lý mới nhất cho bạn.
Nhân tiện... Chúng tôi cũng đặc biệt thêm strictfptừ khóa vào ngôn ngữ. Nếu bạn viết nó trước tên của một hàm, thì tất cả các hoạt động liên quan đến số thực bên trong hàm đó sẽ tệ như nhau trên tất cả các thiết bị !