CodeGym /Các khóa học /JAVA 25 SELF /Giới thiệu về số dấu phẩy động và kiểu double

Giới thiệu về số dấu phẩy động và kiểu double

JAVA 25 SELF
Mức độ , Bài học
Có sẵn

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
float
Các số ±1.5 × 10-45 ... ±3.4 × 1038 ~7 chữ số có nghĩa 4 byte
double
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: doubleint — 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ả
"%.2f"
23.57 số với 2 chữ số thập phân
"%.1f"
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 floatdouble

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.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION