1. Số dấu phẩy động
Giả sử bạn quyết định viết một máy tính đơn giản. Hoặc bất kỳ chương trình nào khác cần tính toán (từ việc đếm tiền đơn giản đến vật lý phức tạp). Không phải mọi thứ trong đời thực đều là số nguyên, và điều đó là không thể thay đổi!
Vậy hãy trang bị một kiểu dữ liệu mới!
Trong lập trình, các số thập phân còn được gọi là số thực, hay số dấu phẩy động (floating-point). Trong Java, như trong hầu hết các ngôn ngữ, chúng dùng để lưu không chỉ số nguyên mà còn cả các giá trị “thập phân”: như 3.14, -28.57, 2.718281828...
Các số dấu phẩy động có hai kiểu chính:
| Kiểu | Lưu trữ | Khoảng giá trị (xấp xỉ) | Độ chính xác | Kích thước điển hình |
|---|---|---|---|---|
|
Các số | ±1.5 × 10-45 ... ±3.4 × 1038 | ~7 chữ số có nghĩa | 4 byte |
|
Các số | ±5.0 × 10-324 ... ±1.7 × 10308 | ~15–16 chữ số có nghĩa | 8 byte |
Kiểu float
Kiểu float lấy tên từ floating-point number — số dấu phẩy động. “Số thực” là các số trong toán học với những tính chất nhất định. Còn máy tính thì có nhiều giới hạn. Vì vậy không hoàn toàn chính xác khi gọi các số thập phân trong Java là số thực. Tên gọi dùng cho chúng là “số dấu phẩy động”.
Kiểu float thường lưu khoảng 7 chữ số có nghĩa (ví dụ, 0.1234567), kèm số mũ cơ số 10 và chiếm 4 byte bộ nhớ. Điều này là quá ít cho các phép tính chính xác, nên mọi người nhanh chóng chuyển sang số độ chính xác kép.
Kiểu double
Kiểu double có tên từ độ chính xác kép (double). Nó chiếm 8 byte bộ nhớ (gấp 2 lần float) và có thể lưu đến 15 chữ số có nghĩa: 0.123456789012345. Chừng đó là đủ cho đa số phép tính với số thập phân, vì vậy double là kiểu chính để lưu số thập phân trong Java.
Trong bài giảng này, trọng tâm sẽ là kiểu double: nó được khuyến nghị mặc định cho tất cả các số thập phân “thông thường”. Nhưng sau đó chúng ta cũng sẽ xem cả kiểu float.
2. Khai báo và khởi tạo biến kiểu double
Mọi thứ giống như với int — chỉ là giờ dùng double.
// Khai báo biến và gán giá trị Pi
double pi = 3.1415926;
// Có thể khai báo mà chưa khởi tạo
double averageSalary;
averageSalary = 91234.56;
// Có thể tính toán!
double pizzaPieces = 8;
double friends = 3;
double piecesPerFriend = pizzaPieces / friends; // 2.666... (chứ không phải 2)
Đặc điểm cú pháp:
- Dấu phân tách thập phân là dấu chấm (3.14). Nếu dùng dấu phẩy — sẽ lỗi biên dịch!
- Nói chính xác thì khi viết double d = 3;, bạn sẽ không nhận lỗi — kiểu được chuyển tự động (số nguyên chuyển thành “số dấu phẩy động” mà không mất mát).
3. Nhập và xuất số thập phân với Scanner
Trước hết, thử in ra một số thập phân:
double amount = 42.75;
System.out.println(amount); // Sẽ in: 42.75
Ổn cả! Còn nếu thêm văn bản:
System.out.println("Trong tài khoản của bạn: " + amount + " euro."); // Trong tài khoản của bạn: 42.75 euro.
Nhập từ bàn phím
Để nhập double cần dùng phương thức chuyên biệt của lớp Scanner: console.nextDouble().
Scanner console = new Scanner(System.in);
System.out.println("Nhập nhiệt độ ngoài trời:");
double temperature = console.nextDouble(); // Nhập double trực tiếp
System.out.println("Ngoài trời hiện tại: " + temperature + " độ.");
4. Kiểu double trong thực tế: số học
Các phép toán quen thuộc (+, -, *, /) hoạt động giống như với int:
double distance = 100.5;
double time = 2.0;
double speed = distance / time; // 50.25
System.out.println("Tốc độ trung bình: " + speed); // Tốc độ trung bình: 50.25
Đó là toàn bộ số học. Khác biệt duy nhất: kết quả phép chia — luôn là số thập phân nếu ít nhất một toán hạng là double.
So sánh với int
int a = 5, b = 2;
System.out.println(a / b); // 2 (phần dư bị bỏ)
double aa = 5, bb = 2;
System.out.println(aa / bb); // 2.5
5. Các lỗi và điều kỳ lạ thường gặp khi làm việc với double
Lỗi chuyển đổi đầu vào
Tình huống kinh điển: người dùng nhập 3,14 — còn chương trình lại mong đợi 3.14. Trong Java, phương thức Scanner.nextDouble() phụ thuộc vào locale hiện tại: trong locale Nga/Đức, dấu phẩy được chấp nhận; trong tiếng Anh — cần dấu chấm. Khi cần, hãy cấu hình locale cho Scanner hoặc đọc chuỗi và tự phân tích (parse) thủ công.
// Điều này sẽ gây vấn đề trong Locale.US nếu nhập "3,14"
double value = console.nextDouble();
Lỗi “không chính xác” của số trong máy tính
Đây là chỗ khiến người mới thường hơi bối rối:
double x = 0.1 + 0.2;
System.out.println(x); // Hmm... 0.30000000000000004
Chúc mừng, bạn đã gặp “ma thuật” của cách biểu diễn số thập phân bên trong máy tính. Sự thật là nhiều số không thể biểu diễn chính xác trong hệ nhị phân. Điều này thường không quá nghiêm trọng với đa số ứng dụng, nhưng có những lưu ý trong tài chính và các ngành khoa học chính xác.
6. Quan trọng: double và int — chuyển đổi tự động và tường minh
Đôi khi bạn cộng số nguyên với số thập phân, hoặc gán int cho biến double — sẽ không có lỗi:
int i = 2;
double d = i; // Ổn hết!
System.out.println(d); // 2
double dd = 3.7;
int ii = (int) dd; // Cần ép kiểu double sang int một cách tường minh!
System.out.println(ii); // 3, phần thập phân bị bỏ
Điều này thường gây bất ngờ — vì sao sau khi ép kiểu phần thập phân biến mất? Đơn giản vì kiểu int không thể lưu số thập phân (mọi thứ sau dấu chấm biến mất vĩnh viễn).
Chi tiết về việc chuyển double sang int và toán tử (int) sẽ có trong bài giảng tiếp theo.
7. Xuất có định dạng: in đẹp double
Thường thì mặc định double được in kèm nhiều số 0 không cần thiết. Ta có thể định dạng đầu ra:
double temp = 23.56789;
System.out.println(temp); // 23.56789
// 2 chữ số thập phân
System.out.println(String.format("%.2f", temp)); // 23.57
// 1 chữ số thập phân
System.out.println(String.format("%.1f%n", temp)); // 23.6
| Định dạng | Kết quả | Mô tả |
|---|---|---|
|
23.57 | số với 2 chữ số thập phân |
|
23.6 | số với 1 chữ số thập phân |
8. Các lỗi thường gặp khi làm việc với float và double
Lỗi số 1: chuyển đổi ngầm double sang float
float f = 1.23; // Lỗi!
Trình biên dịch sẽ phàn nàn: “Bạn đang cố gán double vào float — điều này có thể làm mất độ chính xác!” Luôn thêm hậu tố f.
Lỗi số 2: quên rằng phép chia của hai int — cho kết quả kiểu int
int a = 7, b = 2;
double result = a / b; // 3.0, chứ không phải 3.5
Để có phần thập phân, hãy ép kiểu tường minh ít nhất một toán hạng:
double result = (double) a / b; // 3.5
Lỗi số 3: so sánh số dấu phẩy động
Đừng so sánh số dấu phẩy động bằng ==. Hãy so sánh với một sai số nhỏ (epsilon).
Lỗi số 4: float mất độ chính xác
Đừng lưu các số rất lớn hoặc các giá trị cần độ chính xác cao trong float — chúng có thể “vỡ” hoặc mất các chữ số quan trọng.
GO TO FULL VERSION