














Preview text:
lOMoAR cPSD| 59994889
Môn học: Hệ thống Máy tính
BÁO CÁO BÀI TẬP SỐ 2 Biểu diễn số thực
1.Thông tin sinh viên thực hiện ST T MSSV Họ và tên Email 1 2312007 Nguyễn Văn Phước nguyenvanphuoc1172@gmail.c om 4
2.Đánh giá mức độ hoàn thành đồ án.
Điểm tự đánh giá: 10/10 Bài Đặc điểm Mức độ Ghi chú hoàn thành 1 Viết chương trình 100% -
Viết được hàm void dumpFloat(float * nhập vào số chấm
&x) dùng để thực hiện xuất ra biểu động. Hãy xuất ra
diễn nhị phân của số chấm động được biểu diễn nhị phân trỏ từ con trỏ x - từng thành phần
Thực hiện kiểm tra với toàn bộ test
case mẫu và hàm chạy đúng (dấu, phần mũ, - phần trị) của số
Thực hiện viết hàm driver4() để thực chấm động vừa hiện kiểm tra yêu cầu nhập 2 Viết chương trình 100% - Viết được hàm float* nhập vào biểu diễn
forceFloat(float*x, char *s) dùng để nhị phân của số
thực hiện xuất ra biểu diễn thập phân chấm động. Hãy
tương ứng của biểu diễn nhị phân xuất ra biểu diễn -
Thực hiện kiểm tra với toàn bộ test thập phân tương
case mẫu và hàm chạy đúng ứng -
Thực hiện viết hàm driver2() để thực hiện kiểm tra yêu cầu 1 lOMoAR cPSD| 59994889 3 Dùng hai hàm nói 100% -
Thực hiện nạp giá trị 1.3e+20 ( trên ở bài 1 và bài 2
1.3∗1020) vào trong hàm dumpFloat để thực hiện các để kiểm tra yêu cầu với những -
Sử dụng hàm forceFloat để nạp giá trị số đặc biệt
biểu diễn nhị phân của số nhỏ nhất
lớn hơn 0 theo kiểu float để cho ra
kết quả thập phân tương ứng -
Thực hiện xem xét những trường hợp
số đặc biệt tương ứng -
So sánh các giá trị được định nghĩa
như trên (−∞,∞,NaN ,v ..v..) với hai
thư viện (giống math.h của C) và limits -
Thực hiện viết hàm driver3() để thực hiện kiểm tra yêu cầu 4 Khảo sát các 100% -
Thực hiện viết hàm driver4() để thực trường hợp liên hiện kiểm tra yêu cầu quan đến ép kiểu, chuyển kiểu
3.Thông số kĩ thuật của môi trường phát triển - Môi trường phát triển:
o Hệ điều hành: Windows 11 24H2 o Môi trường phát triển: Visual Studio Code 1.98.1
o Ngôn ngữ được dùng: C++ 14 o Trình biên dịch: MinGW 6.3.0 - Lưu ý:
o Hệ điều hành: Sử dụng Windows 11 (có thể sử dụng Windows 10 hoặc thấp hơn)
o Môi trường phát triển: Có thể sử dụng các môi trường sau:
Visual Studio Code (tốt nhất nên sử dụng bản 1.98.1 trở lên).
Một số gợi ý khác như:
• DevC++ (Embarcadero 6.3) hoặc hơn
• Visual Studio 2022 Community (trình biên dịch MSVC 14.40,
tuy nhiên cần chỉnh sửa một chút trong code)
o Ngôn ngữ: C++ 14 (có thể sử dụng C++ 14 hoặc hơn) 2 lOMoAR cPSD| 59994889
4.Mô tả về các cấu trúc dữ liệu, hàm được sử dụng 4.1. Câu 1
- Hàm `dumpFloat` nhận một con trỏ float* từ danh sách tham số, chuyển đổi kiểu
của nó để có thể thao tác bits, và sau đó in ra các bits theo thứ tự: bit dấu, các bit
mũ (exponent), và mantissa. Hàm này lấy ý tưởng sử dụng các toán tử bit và thực
hiện lấy từng bit để lưu trữ void dumpFloat(float *x) {
string sign, exponent, mantissa; int *p = (int *)x;
// Lấy bit dấu đầu tiên bằng cách thực hiện dịch phải 31
lần sign.push_back(((*p >> 31) & 1) + '0') ;
// Lấy 8 bit tiếp theo (2 - 9) bằng cách lặp dịch phải từ 30 ,29,..., 23
for (int i = 30; i >= 23; i--)
exponent.push_back(((*p >> i) & 1) + '0') ; // Các bit còn lại
for (int i = 22; i >= 0; i--)
mantissa.push_back(((*p >> i) & 1) + '0')
cout << sign << " " << exponent << " " << mantissa << endl; }
Ngoài ra, còn có một hàm driver1() để thực hiện nhập xuất và gọi hàm này dể thực hiện yêu cầu 4.2. Câu 2
Câu 2 gồm có hai hàm, một hàm chính và một hàm hỗ trợ nhập:
- Hàm hỗ trợ nhập, inputBinary, nhận vào một con trỏ s được tham chiếu trực tiếp địa
chỉ của nó, dùng để đọc một dãy nhị phân nhập từ bàn phím người dùng và trả về
kết quả là độ dài của toàn bộ dãy bit nếu đọc được thành công.
- Hàm forceFloat là hàm thực thi chính của bài này. Nó gọi vào một con trỏ p kiểu
float* và một chuỗi s dưới dạng con trỏ char*, thực hiện gán từng kí tự vào trong bit
tương ứng của giá trị được p trỏ đến (tính từ đầu biểu diễn nhị phân của số được trỏ
bởi con trỏ này), sau đó trả về kết quả là con trỏ của số đã được đổi.
Hàm này có ý tưởng giống với hàm dumpFloat nhưng có cơ chế hoạt động ngược lại int inputBinary(char *&s) { s = new char[33] ; memset(s, '0', 33) ; 3 lOMoAR cPSD| 59994889 fgets(s, 33, stdin) ; int len = strlen(s) ; if (s[len - 1] == '\n') s[len - 1] = '\0';
len = strlen(s); // Đảm bảo độ dài chuỗi không tính '\n' và '\0' return len; } float
*forceFloat(float *p, char *s) { int *x = (int *)(p) ;
*x = 0; // Xóa toàn bộ bit int len = strlen(s) ;
for (int i = 0; i < len && i < 32; i++) { int number = s[i] - '0'; if (number == 1) {
*x |= (1L << (31 - i)); } }
return p; // Trả về con trỏ float }
Ngoài ra, còn có một hàm driver2() để thực hiện nhập xuất và gọi hàm này dể thực hiện yêu cầu 4.3. Câu 3
Câu này không có hàm mới, chỉ có một hàm driver3() (được đề cập ở mục 4.5)
dùng để thực hiện yêu cầu của câu 3 này 4.4. Câu 4
Câu này không có hàm mới, chỉ có một hàm driver4() ( được đề cập ở mục
4.5) dùng để thực hiện yêu cầu của câu 4 này 4.5. Các hàm khác
Các câu 1, 2, 3, 4 nói trên, mỗi câu đều được viết một hàm driver dùng để thực
hiện chạy và thực hiện các yêu cầu của đề bài. Các hàm driver được đặt tên theo dạng driver ()
Hàm main chỉ chứa 4 lời gọi hàm cho 4 hàm driver tương ứng, nơi chúng có thể
gọi hàm và thực thi yêu cầu của bài. 4 lOMoAR cPSD| 59994889
Ở câu 3, có phần kiểm tra và so sánh với các giá trị trả về của những số đặc biệt
với thư viện so với thư viện : -
Các giá trị đặc biệt được dùng của thư viện limits:
o numeric_limits::infinity() – Dương vô cùng
o -numeric_limits::infinity() – Âm vô cùng o
numeric_limits::quiet_NaN() – NaN
- Các giá trị đặc biệt dùng trong thư viện cmath: o
INFINITY – Dương vô cùng o –
INFINITY – Âm vô cùng o NAN – NaN
5.Kết quả thực hiện các yêu cầu 5.1. Câu 1
Để thực hiện kiểm tra hàm dumpFloat với các test case trên, hàm driver1()
được viết ra để người dùng nhập vào số và hàm sẽ viết ra dãy nhị phân tương ứng. Test Số nhập vào
Kết quả mong đợi case 1 6
0 10000001 10000000000000000000000 2 -12.625
1 10000010 10010100000000000000000 3 0.1015625
0 01111011 10100000000000000000000 4 0.1
0 01111011 10011001100110011001101 5 0
0 00000000 00000000000000000000000 5 lOMoAR cPSD| 59994889
Các màn hình kết quả khi lần lượt chạy 5 lần tương ứng với 5 test case trên: 5.2. Câu 2
Để thực hiện kiểm tra hàm forceFloat với các test case trên, hàm driver2()
được viết ra để người dùng nhập vào số và hàm sẽ viết ra dãy nhị phân tương ứng.
Test Biểu diễn nhị phân nhập vào
Kết quả mong đợi (single) case 1
0 10001000 01101100001000000000000 728.25 2
1 01000110 01101011000000000000000 -9.83913471531 × 10-18 3
0 01111011 10011001100110011001101 0.1 4
0 11111111 00000000000000000000000 ∞ 5
0 11111111 10000000000000000000000 NaN 6 lOMoAR cPSD| 59994889
Các màn hình kết quả khi lần lượt chạy 5 lần tương ứng với 5 test case trên:
Có một số khác biệt nhỏ bao gồm:
- Ở test case số 2, mặc định float chỉ có thể biểu diễn được 6 chữ số có nghĩa. Do đó,
kết quả sẽ bị cắt ngắn hơn kết quả mong đợi một chút, tuy nhiên vẫn đúng so với kết quả mong đợi
- Ở các test case 4, 5: inf, nan tương ứng với ∞ và NaN. Hai giá trị này là hai giá trị
mặc định khi sử dụng kiểu float trong C/C++ 5.3. Câu 3
- Số 1.3E+20 khi chuyển sang dạng nhị phân theo chuẩn IEEE 754 (32-bit) được biểu diễn như sau:
o Dạng thập phân: 1.3 × 10²⁰ 7 lOMoAR cPSD| 59994889
o Dạng nhị phân: 0 10011100 10101110100001110111100
- Số dương nhỏ nhất dạng phi chuẩn (denormalized): 1.40129846 × 10⁻⁴⁵
Biểu diễn nhị phân: 0 00000000 00000000000000000000001
Số dương nhỏ nhất dạng chuẩn hóa (normalized): 1.17549435×10−38
Biểu diễn nhị phân: 0 00000001 00000000000000000000000 -
Các trường hợp trả ra số đặc biệt:
o Dương vô cùng: Xuất hiện khi phép tính vượt quá khả năng biểu diễn, dẫn đến
tràn số : 1.0 / 0.0, MAX_FLT * x,… (x ≥ 1)
Biểu diễn nhị phân: 0 11111111 00000000000000000000000 o Âm vô
cùng: Tương tự dương vô cùng, xuất hiện khi phép tính vượt quá khả năng biểu diễn.
Biểu diễn nhị phân: 1 11111111 00000000000000000000000 o NaN –
Not A Number: Như cái tên, nó dùng để biểu thị kết quả của những phép tính
không hợp lệ: ∞ - ∞, ∞ / ∞, …
Biểu diễn nhị phân: x 111111111 1xxxxxxxxxxxxxxxxxxxxxxxxx (mỗi x có thể là 0 hoặc 1 tùy ý )
Để thực hiện kiểm tra các kết quả trên, hàm driver3() được viết ra.
Kết quả của các yêu cầu được thực hiện trong Câu 3:
Ngoài ra, còn thực hiện so sánh với các giá trị tương ứng với thư viện limits so với việc
sử dụng các hằng số trong thư viện cmath: 5.4. Câu 4 8 lOMoAR cPSD| 59994889 - Ý đầu tiên:
o Khi chuyển đổi từ float sang int, phần phân thập phân sẽ bị cắt bỏ
(truncation), tức là chỉ giữ lại phần nguyên, không làm tròn. Khi chuyển từ int
o Chương trình minh họa (là một phần của hàm driver4() )
o Kết quả (là một phần khi chạy hàm driver4() trong hàm main)
- Ý thứ 2: trở lại float, giá trị phần lẻ đã mất sẽ không được khôi phục
o Khi chuyển từ int sang float, giá trị được bảo toàn nếu nằm trong phạm vi biểu diễn của float.
o Khi chuyển ngược lại từ float sang int, phần thập phân sẽ bị cắt bỏ.
o Với các giá trị quá lớn (> 2³¹ - 1 hoặc < -2³¹), kết quả có thể bị mất chính xác,
do đã nằm ngoài vùng biểu diễn float nói chung.
o Chương trình minh họa (là một phần của hàm driver4() ) 9 lOMoAR cPSD| 59994889
Kết quả (là một phần khi chạy hàm driver4() trong hàm main) - Ý thứ 3: o
o Do sự sai khác trong việc lưu trữ số chấm động, không có tính kết hợp trong
o Chương trình minh họa (là một phần của hàm driver4())
o Kết quả (là một phần khi chạy hàm driver4() trong hàm main)
- Ý thứ 4: Theo cách ép kiểu int, phần thập phân của biểu thức được cắt đi , do đó kết
phép cộng số chấm động:
quả của biểu thức i=(int)(3.14159 * f) với f = -12.5 là -39. 10 lOMoAR cPSD| 59994889
o Chương trình minh họa (là một phần của hàm driver4())
o Kết quả (là một phần khi chạy hàm driver4() trong hàm main)
- Ý thứ 5: Chuyển kiểu float cho i và cộng vào biến f. Vì phần định trị của float chỉ có
o Chương trình minh họa (là một phần của hàm driver4())
o Kết quả (là một phần khi chạy hàm driver4() trong hàm main)
- Ý thứ 6: Kết quả là true. Căn bản thì khi chuyển kiểu như vậy thì phần thập
23 bit, nếu số quá lớn, có thể gây sai số:
phân .00… sẽ được thêm vào và sau đo được cắt bỏ khi ép kiểu int. tuy nhiên nếu
biểu diễn số quá lớn, chương trình sẽ sai.
o Tuy nhiên trong khuôn khổ chương trình trên, kết quả luôn là true. o
Chương trình minh họa (là một phần của hàm driver4()) 11 lOMoAR cPSD| 59994889
o Kết quả (là một phần khi chạy hàm driver4() trong hàm main)
- Ý thứ 7: Kết quả là true. Lần này, do double được thiết kế để thực hiện lưu trữ nhiều o Chương trình minh họa: o Kết quả:
- Ý thứ 8: Kết quả là false hay true tùy vào giá trị đầu vào
bit hơn (52 bit phần trị), do đó có thể lưu chính xác toàn bộ bit của số kiểu int.
o Câu lệnh đó thực hiện kiểm tra xem sau khi cắt ngắn hàng thập phân, số đó
có bằng chính nó ban đầu không. 12 lOMoAR cPSD| 59994889
o Nếu số chấm động có dạng x.0 , điều này là đúng; ngược lại thì sai.
- Ý thứ 9: Kết quả là false hay true tùy vào giá trị đầu vào. Căn bản thì chương trình 13 lOMoAR cPSD| 59994889
này sẽ trả ra kết quả giống ý thứ 8.
6. Một số lưu ý
- Ở câu 1 và câu 2, khi thực hiện chạy hàm driver tương ứng, chỉ có thể nhập một số
( một dãy biểu diễn nhị phân) một lần o Ở câu 1, ta chỉ có thể nhập những số hợp
lệ, không thể nhập những số như:
∞, -∞, NaN,…. Hay nhập các biểu thức o Ở câu 2, ta chỉ có thể nhập dãy bit
với những bit không ngăn cách, các bit liền nhau và không được tách ra bởi dấu cách
o Ở câu 3 và 4, không có các phương thức nhập xuất, vì đề bài chỉ yêu cầu thực
hiện kiểm tra và so sánh
- Thực tế khi được lưu trữ số thập phân dấu chấm động độ chính xác đơn, sẽ có một
phần sai lệch khi được lưu trữ trong bộ nhớ, nên sẽ có một số sai lệch trong một số test case nhất định 7.Kết luận
Trong khi thực hiện bài tập này, sẽ có vài sự cố không mong muốn, đôi khi xuất hiện trong lúc
thực thi, dẫn đến các kết quả trả ra không theo mong muốn. Điều này là do trình độ còn “non”
của em trong việc lập trình, mong được thầy “nương tay” ạ. Em cảm ơn thầy rất nhiều. 14 lOMoAR cPSD| 59994889
8.Ảnh chụp màn hình kết quả điền form 15