Dữ liệu & CPU/Module 1 — Tổng kết & cheat sheet biểu diễn dữ liệu
7/23
Bài 7 / 23~12 phútBiểu diễn dữ liệuMiễn phí lượt xem

Module 1 — Tổng kết & cheat sheet biểu diễn dữ liệu

Recap Module 1: bit/byte/hex, two's complement, IEEE 754, UTF-8, endianness và thao tác bit. Cheat sheet, glossary, pitfall và self-assessment để bookmark.

TL;DR: Module 1 bóc 5 quy ước mã hoá nền tảng mà mọi kiểu dữ liệu trong máy tính đều xây trên đó. Đây là 1 trang để bookmark — cheat sheet, glossary và pitfall tổng hợp để tra nhanh khi cần.

Đã đi qua những gì

Bài 01 đặt nền với bit, byte và hệ cơ số: máy chọn nhị phân vì phần cứng phân biệt tin cậy hai mức điện áp, còn hex chỉ là cách viết tắt gọn cho người (2^4 = 16 nên 1 chữ số hex = 4 bit). Bài 02 xây trên đó để giải thích số nguyên có dấu: two's complement cho phép cộng trừ dùng chung một mạch, nhưng cũng là nguyên nhân tràn số wrap-around khi kết quả vượt giới hạn n bit. Bài 03 chuyển sang số thực IEEE 754 — lý do 0.1 + 0.2 ra 0.30000000000000004 nằm ở chỗ 0.1 không biểu diễn chính xác trong nhị phân, giống 1/3 không viết được chính xác trong thập phân. Bài 04 rời thế giới số sang văn bản: Unicode gán code point cho mọi ký tự trên đời, UTF-8 mã hoá chúng thành 1–4 byte theo cơ chế prefix, và mojibake xảy ra khi byte được đọc bằng sai encoding. Bài 05 khép lại với endianness — thứ tự byte khi lưu số nhiều byte — và bộ thao tác bit-level (mask, shift, flag) thực dụng cho lập trình hằng ngày.

Sơ đồ dưới tóm tắt chuỗi 5 bài và pitfall trung tâm của từng bài:

flowchart LR
  A["Bit/byte/hex<br/>2^n gia tri"] --> B["So nguyen<br/>tran so wrap"]
  B --> C["IEEE 754<br/>float != chinh xac"]
  C --> D["UTF-8<br/>1 ky tu != 1 byte"]
  D --> E["Endianness<br/>+ bitmask"]

Cheat sheet

Khái niệmÝ chínhPitfall
n bit, 2^n giá trị8 bit = 256 giá trị (0–255); 32 bit = hơn 4 tỷChọn kiểu quá nhỏ → tràn; quá lớn → phí bộ nhớ
Two's complementBit cao nhất là dấu; đảo bit + 1 ra số âmGiá trị âm nhỏ nhất không có đối xứng dương (INT_MIN không negation được)
OverflowKết quả vượt giới hạn → wrap-around, không raise error mặc địnhKết quả âm từ phép cộng hai số dương là dấu hiệu tràn
IEEE 754float 32 bit (1 dấu + 8 exp + 23 mantissa); double 64 bitPhép so sánh == với float không đáng tin; dùng epsilon
Float cho tiềnSai lầm kinh điển — float không biểu diễn chính xác phần thập phân nhị phânDùng BigDecimal (Java), decimal (Python/C#) cho tiền tệ
Code point vs byteCode point là số định danh ký tự trong Unicode; byte là cách mã hoá thực tếLen của string ≠ len byte khi có ký tự ngoài ASCII
UTF-8ASCII tương thích (1 byte); ký tự mở rộng 2–4 byte, prefix 10xxxxxxĐọc file mà không chỉ rõ charset UTF-8 → mojibake
MojibakeByte UTF-8 bị đọc bằng encoding khác (Latin-1, Windows-1252...) → ký tự lạTiếng Việt hiện Tiếng Viá»t thường là UTF-8 bị đọc Latin-1
EndiannessBig-endian: byte cao trước; little-endian: byte thấp trướcx86 little-endian; network byte order big-endian — phải convert khi đọc binary protocol
Bitmaskvalue & mask giữ lại bit muốn đọc; value | flag bật bitQuên & 0xFF khi ép byte sang int → sign extension gây giá trị âm

Glossary

Thuật ngữĐịnh nghĩa 1 câu
bitĐơn vị thông tin nhỏ nhất, chứa giá trị 0 hoặc 1.
byte8 bit gộp lại, biểu diễn được 256 giá trị khác nhau (0–255).
hexHệ cơ số 16, dùng ký hiệu 09AF; 1 chữ số hex tương đương đúng 4 bit.
two's complementQuy ước mã hoá số nguyên có dấu: đảo tất cả bit rồi cộng 1 để ra số âm, giúp cộng/trừ dùng chung mạch.
overflowKết quả phép toán vượt dải giá trị của kiểu dữ liệu, dẫn đến wrap-around thay vì báo lỗi.
mantissaPhần định trị trong biểu diễn IEEE 754, quyết định độ chính xác của số thực.
exponentPhần số mũ trong biểu diễn IEEE 754, xác định quy mô (magnitude) của số.
NaN"Not a Number" — giá trị IEEE 754 đặc biệt xuất hiện khi phép toán không có kết quả hợp lệ (vd: 0.0 / 0.0).
code pointSố định danh duy nhất của một ký tự trong bảng Unicode, ký hiệu U+XXXX.
UTF-8Encoding biến độ dài mã hoá code point Unicode thành 1–4 byte, tương thích ngược với ASCII.
mojibakeChuỗi ký tự lạ xuất hiện khi byte văn bản được đọc bằng encoding sai với encoding lúc ghi.
endiannessThứ tự byte khi lưu số nguyên nhiều byte vào bộ nhớ: big-endian (byte cao trước) hoặc little-endian (byte thấp trước).
bitmaskGiá trị nhị phân dùng để chọn ra (AND) hoặc bật/tắt (OR/XOR) một tập bit cụ thể trong một số nguyên.
sign extensionHiện tượng bit dấu được nhân rộng khi mở rộng kiểu số có dấu, ví dụ byte -1 (0xFF) thành int -1 (0xFFFFFFFF).

Pitfall tổng hợp

Pitfall 1: So sánh float bằng ==

// Wrong -- floating-point is imprecise
double a = 0.1 + 0.2;
if (a == 0.3) System.out.println("equal"); // never prints
// Correct -- compare with epsilon tolerance
double a = 0.1 + 0.2;
double epsilon = 1e-9;
if (Math.abs(a - 0.3) < epsilon) System.out.println("equal"); // works

Pitfall 2: Dùng float/double cho tiền tệ

// Wrong -- monetary rounding error accumulates
double price = 0.1;
double total = 0;
for (int i = 0; i < 10; i++) total += price;
System.out.println(total); // 0.9999999999999999
// Correct -- use BigDecimal for money
import java.math.BigDecimal;
BigDecimal price = new BigDecimal("0.1");
BigDecimal total = BigDecimal.ZERO;
for (int i = 0; i < 10; i++) total = total.add(price);
System.out.println(total); // 1.0

Pitfall 3: Tràn số int không báo lỗi

// Wrong -- silent overflow, no exception
int x = Integer.MAX_VALUE; // 2_147_483_647
int y = x + 1;             // wraps to -2_147_483_648
System.out.println(y);     // -2147483648 (?!)
// Correct -- use Math.addExact to throw on overflow, or switch to long
int x = Integer.MAX_VALUE;
int y = Math.addExact(x, 1); // throws ArithmeticException
// Or: long y = (long) x + 1;

Pitfall 4: Đọc file không chỉ rõ charset UTF-8

// Wrong -- relies on platform default charset (may not be UTF-8)
BufferedReader reader = new BufferedReader(new FileReader("data.txt"));
// Correct -- always specify charset explicitly
BufferedReader reader = new BufferedReader(
    new InputStreamReader(new FileInputStream("data.txt"), StandardCharsets.UTF_8)
);

Pitfall 5: Quên & 0xFF khi đọc byte thành int

// Wrong -- sign extension turns 0xFF into -1
byte b = (byte) 0xFF;
int val = b;          // val = -1, not 255
// Correct -- mask off sign extension
byte b = (byte) 0xFF;
int val = b & 0xFF;   // val = 255

Pitfall 6: Nhầm endianness khi đọc binary protocol

// Wrong -- reading little-endian data as big-endian (or vice versa)
DataInputStream dis = new DataInputStream(socket.getInputStream());
int value = dis.readInt(); // DataInputStream always reads big-endian
// If the sender wrote little-endian, value is byte-swapped
// Correct -- use ByteBuffer with explicit byte order
byte[] raw = socket.getInputStream().readNBytes(4);
int value = ByteBuffer.wrap(raw).order(ByteOrder.LITTLE_ENDIAN).getInt();

Pitfall 7: Nhầm length() của String với số byte

// Wrong -- assumes 1 char = 1 byte
String s = "Việt";
int byteCount = s.length(); // 4 -- counts Java chars, not bytes
// Correct -- get actual UTF-8 byte count
String s = "Việt";
int byteCount = s.getBytes(StandardCharsets.UTF_8).length; // 7 bytes

Self-assessment

Bạn đã đạt Module 1 nếu trả lời được:

  • Giải thích được bit, byte và cách đọc nhị phân, hex — nếu chưa chắc, đọc lại bài 01 section "Bit và byte" + "Hex: cách viết tắt cho người".
  • Dự đoán được khi nào phép tính tràn số và kết quả wrap-around ra sao với two's complement — nếu chưa chắc, đọc lại bài 02 section "Two's complement" + "Tràn số".
  • Giải thích được vì sao 0.1 + 0.2 không bằng 0.3 và khi nào không được dùng float — nếu chưa chắc, đọc lại bài 03 section "Vì sao 0.1 không biểu diễn chính xác" + "Float cho tiền".
  • Truy vết được cách UTF-8 mã hoá ký tự Unicode thành byte và chẩn đoán được lỗi font (mojibake) — nếu chưa chắc, đọc lại bài 04 section "UTF-8 mã hoá thế nào" + "Mojibake".
  • Implement được vài thao tác bit-level: bitmask để đọc flag, shift để nhân/chia luỹ thừa 2 — nếu chưa chắc, đọc lại bài 05 section "Bitmask và flag" + "Shift".

What's next

Bạn vừa học cách dữ liệu được biểu diễn — số nguyên, số thực, văn bản, thứ tự byte đều là quy ước mã hoá bit. Câu hỏi tiếp theo tự nhiên là: CPU xử lý đống bit đó như thế nào? Module 2 "Máy chạy thế nào" sẽ giải thích vòng lặp fetch-decode-execute, kiến trúc thanh ghi, stack, heap và cách instruction set biến code cấp cao thành thứ CPU thực sự chạy.

Máy chạy thế nào

Tài liệu mở rộng

📚 Sách nền tảng
📚 Floating-point chuyên sâu
📚 Unicode & encoding

Bài tiếp theo: Máy chạy thế nào — tổng quan

Bài này có giúp bạn hiểu bản chất không?

Hỏi đáp về bài này

Chưa có câu hỏi

Đặt câu hỏi

Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).

Đặt câu hỏi đầu tiên