# TASK_02
## A.Các hệ đếm cơ bản
**I.Hệ nhị phân(hệ cơ số 2)**
- Một số có thể được biểu diễn trong hệ nhị phân bằng 2 chữ số 0 và 1
- Trong máy tính, các giá trị nhị phân được biểu diễn dưới dạng các bit. Một bit biểu diễn 2 giá trị khác nhau, có thể là 0 hoặc 1, đúng hoặc sai, có hoặc không, …
- Các bit kết hợp với nhau sẽ tạo thành một chuỗi bit. Chúng ta có các chuỗi bit sau:
- Nibble: Chuỗi 4 bit. Hầu hết các máy tính không hỗ trợ truy cập 1 nibble trong bộ nhớ.
- Byte/Octet: Chuỗi 8 bit. Là đơn vị nhỏ nhất mà các máy tính có thể truy cập vào bộ nhớ. Do vậy, hầu hết các ngôn ngữ lập trình hỗ trợ kiểu dữ liệu nhỏ nhất là 1 byte. Octet được sử dụng khi thuật ngữ byte có ý nghĩa mơ hồ, vì byte trong lịch sử từng được sử dụng làm đơn vị lưu trữ có nhiều kích thước khác nhau (không chỉ là 8 bit).
- Word: Chuỗi 16 bit.
- Double word: Chuỗi 32 bit.
- Quad word: Chuỗi 64 bit.
- Long word: Chuỗi 128 bit.
- Tbyte: Chuỗi 80 bit. Sử dụng trong các hệ CPU Intel 80x86 để giữ các giá trị chấm động và các giá trị BCD nhất định (BCD - binary-coded decimal là một giá trị thập phân được mã hóa nhị phân).
- Khi biểu diễn một chuỗi bit, ta sẽ đánh dấu các bit từ phải qua trái và bắt đầu từ 0. Bit bên phải cùng ứng với bit vị trí thấp nhất gọi là bit LO (low-order), bên trái cùng là bit HO (high-order). Cũng dùng LO để chỉ vị trí từ bên phải qua và HO cho vị trí từ bên trái qua.

**Một số đặc trưng:**
- Nếu bit LO của số nhị phân (số nguyên) là 1 thì số đó là số lẻ. Ngược lại, nếu là 0 thì là số chẵn.
->Ví dụ: Cho số nhị phân 00110101, nhìn bit LO là 1 thì có thể đoán ra ngay đây là số lẻ.
- Nếu một lượng n-bit LO đều là 0, thì số đó có thể chia hết cho 2n.
->Ví dụ: Với số nhị phân 01010000, 4-bit LO đều là 0 nên số này có thể chia hết cho 24.
- Nếu số nhị phân có bit thứ n là 1, tất cả các bit còn lại là 0 thì số đó bằng 2n.
->Ví dụ: số nhị phân 00010000, chắc chắn số này bằng 24.
- Nếu n-bit LO đều là 1, các bit còn lại là 0, thì số đó bằng 2n - 1. Có thể nói là 2n - 1 sẽ chứa n bit đều là 1.
- Dịch trái 1 bit toàn bộ các bit trong số nhị phân sẽ tương đương với phép nhân với 2.
- Dịch phải 1 bit của số nhị phân không dấu tương đương với phép chia cho 2 (phần lẻ sẽ được làm tròn xuống). Không áp dụng với số nguyên có dấu.
- Nhân 2 giá trị nhị phân n-bit có thể cần 2n bit để lưu kết quả.
- Cộng hoặc trừ 2 số nhị phân n bit sẽ không cần quá n + 1 bit để lưu.
- Đảo tất cả các bit của số nhị phân sẽ tương đương với đổi dấu một số nguyên ở hệ thập phân và trừ đi 1. Phép toán đảo bit sẽ đảo bit 0 thành 1 và 1 thành 0. Vì vậy, số nhị phân 00001001 ở hệ thập phân là 9 khi đảo tất cả các bit thành 11110110 thì giá trị của nó sẽ là -10. Lưu ý là ở đây mình đang minh họa giá trị ở dạng số nhị phân 8-bit nhé. Nếu các bạn có số nhị phân 16-bit 0000000000001001 biểu diễn số 9, thì khi đảo bit lại là 1111111111110110 mới biểu diễn số -10.
- Tăng giá trị của số nguyên nhị phân không dấu lớn nhất thêm 1 sẽ luôn cho kết quả là 0. Điều này cũng dễ hiểu, giả sử bạn có số nguyên không dấu 8-bit lớn nhất là 11111111 biểu diễn số 255, nếu thêm 1 vào sẽ là 100000000 (9 bit) biểu diễn số 256. Vì số nguyên này chỉ biểu diễn được 8 bit, nên sẽ thành 00000000. Các bạn sẽ thấy kiểu dữ liệu 1 byte không dấu thường chỉ biểu diễn được từ 0 đến 255 mà thôi.
- Trừ giá trị của số nguyên nhị phân không dấu đi 1 sẽ luôn cho kết quả là số nguyên nhị phân không dấu lớn nhất.
- Một giá trị n-bit sẽ cho ra 2n các kết hợp duy nhất của các bit. Ví dụ: Số nhị phân 8-bit sẽ cho ra 28 giá trị duy nhất, tức là biểu diễn được 256 giá trị.
**Các phép toán:**
- Qui tắc cộng 2 số nhị phân
0 + 0 = 0
0 + 1 = 1
1 + 0 = 1
1 + 1 = 0 (nhớ 1)
ví dụ:
```
1 0 0 0 1 1 1 (71)
+ 1 1 1 1 0 (30)
---------------
= 1 1 0 0 1 0 1 (101)
```
- Qui tắc trừ 2 số nhị phân
0 − 0 = 0
0 − 1 = 1 (mượn 1)
1 − 0 = 1
1 − 1 = 0
ví dụ:
```
1 1 0 1 1 1 0
− 1 0 1 1 1
---------------
= 1 0 1 0 1 1 1 ← kết quả
```
- Phép tính nhân trong hệ nhị phân cũng tương tự như phương pháp làm trong hệ thập phân.
```
1 0 1 1
× 1 0 1 0
----------------
0 0 0 0
+ 1 0 1 1
+ 0 0 0 0
+ 1 0 1 1
----------------
= 1 1 0 1 1 1 0
```
- Phép chia nhị phân cũng tương tự như phép chia trong hệ thập phân.
```
10011111 | 1100
- 1100 |------
---- | 1101
1111 |
- 1100 |
---- |
1111 |
- 1100 |
---- |
11 |
```
- Kiểm tra 1 bit bên trong dãy bit dùng phép toán AND
-> Kiểm tra bit cuối cùng để xác định chẵn hay lẻ. Cần tạo ra một mask để thực hiện việc này. Bit cuối cùng của mask sẽ là 1 và các bit còn lại là 0. Phép toán AND sẽ biến các bit khác thành 0, ngoại trừ bit cuối cùng. Nếu bit cuối cùng là 0 sẽ dẫn đến kết quả là 0, còn nếu là 1, phép AND sẽ không thay đổi giá trị của nó.
Mã giải:
```
// biến `a` là biến cần test
result = (a & 1) != 0;
```
Trường hợp bit mà bạn muốn kiểm tra không phải là bit cuối cùng thì dời bit đó về cuối cùng thông qua phép dịch phải, rồi thực hiện phép toán AND với mask. Mask của chúng ta ở đây là 1.
```
// cần test bit thứ `n` của biến `a`, n bắt đầu từ 0 nhé
result = ((a >> n) & 1) != 0;
```
hoặc
```
// cần test bit thứ `n` của biến `a`
result = (a & (1 << n)) != 0;
```
- Kiểm tra 1 chuỗi n-bit dùng phép toán AND
Tương tự với trường hợp kiểm tra 1 bit, có thể kiểm tra một chuỗi n-bit có phải toàn là 0 hay không bằng cách tạo ra 1 mask với toàn giá trị 1, rồi dùng phép toán AND để kiểm tra.
Ví dụ:
Nếu biết giá trị của mask 1111 là 15, có thể dễ dàng làm như sau:
```
// biến `a` là biến cần test
result = (a & 15) != 0;
```
Nếu không biết giá trị của mask mà muốn tạo một mask n-bit, có thể làm như sau:
```
mask = (1 << n) - 1;
```
**II. Hệ bát phân(hệ cơ số 8)**
- chỉ có 8 ký hiệu hoặc các giá trị chữ số có thể có, có 0, 1, 2, 3, 4, 5, 6, 7. Nó chỉ yêu cầu 3 bit để biểu diễn giá trị của bất kỳ chữ số nào. Số bát phân được biểu thị bằng cách thêm tiền tố 0o hoặc hậu tố 8
- Vị trí của mỗi chữ số có trọng số là lũy thừa của 8. Mỗi vị trí trong hệ Bát phân có ý nghĩa hơn 8 lần so với vị trí trước đó, có nghĩa là giá trị số của một số bát phân được xác định bằng cách nhân mỗi chữ số của số đó với giá trị của vị trí mà chữ số xuất hiện và sau đó thêm các sản phẩm. Vì vậy, nó cũng là một hệ thống số vị trí (hoặc trọng số).
Biểu diễn:
- chỉ có thể được biểu diễn bằng cách sử dụng 3 bit, với mỗi nhóm bit có giá trị riêng từ 000 (cho 0) đến 111 (cho 7 = 4 + 2 + 1). Số nhị phân tương đương của số Bát phân như được đưa ra bên dưới:
- Hệ thống số bát phân tương tự như hệ thống số thập lục phân. Hệ thống số bát phân cung cấp cách thuận tiện để chuyển đổi các số nhị phân lớn thành các nhóm nhỏ gọn hơn và nhỏ hơn, tuy nhiên hệ thống số bát phân này ít phổ biến hơn.
Ứng dụng:
Các số bát phân không còn phổ biến như trước nữa. Tuy nhiên, Octal được sử dụng khi số bit trong một từ là bội số của 3. Nó cũng được sử dụng như một cách viết tắt để biểu diễn quyền đối với tệp trên hệ thống UNIX và biểu diễn số UTF8, v.v.
Ưu điểm => nó sử dụng ít chữ số hơn hệ thống số thập phân và hệ thập lục phân ->nó có ít tính toán hơn và ít lỗi tính toán hơn. Nó chỉ sử dụng 3 bit để biểu diễn bất kỳ chữ số nào trong hệ nhị phân và dễ dàng chuyển đổi từ bát phân sang nhị phân và ngược lại. Nó dễ dàng hơn để xử lý đầu vào và đầu ra ở dạng bát phân.
Nhược điểm => máy vi tính không hiểu trực tiếp hệ thống số bát phân -> chúng ta cần bộ chuyển đổi bát phân sang nhị phân
**III. Hệ thập phân(hệ cơ số 10)**
- Bảng chữ số {0,1,2,3,4,5,6,7,8,9}
- Quy tắc biểu diễn: ghép các chữ số
- Quy tắc tính giá trị: mỗi chữ số x đứng ở hàng thứ i tính từ bên phải có
giá trị là x.10 i-1. Như vậy một đơn vị ở một hàng sẽ có giá trị gấp 10
lần một đơn vị ở hàng kế cận bên phải
**IV. Hệ thập lục phân(hệ cơ số 16)**
- Hệ nhị phân tuy tính toán đơn giản nhưng biểu diễn số rất dài. Hệ
thập phân thì không thích hợp với máy tính. Người ta thường
dùng hệ 16 (hexa) vì biểu diễn số ngắn mà chuyển đổi với hệ nhị
phân rất đơn giản
- Hệ đếm cơ số 16 dùng các chữ số
{ 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F}
- Bảng cộng, nhân không hoàn toàn giống như trong hệ thập phân,
ví dụ 5+6 = B nhưng cách thực hiện các phép toán số học cũng
tương tự như hệ thập phân.
**Cách chuyển đổi giữa các hệ đếm**
Từ hệ cơ số 10 sang hệ cơ số 2 và ngược lại
-> chia số thập phân cho 2
-> lấy thương tiếp tục chia cho 2 đến khi thương số bằng 0 thì dừng
-> lấy số dư viết lại lần lượt từ dưới lên.
vd:
- cộng hết các chữ số trong dãy nhị phân lần lượt từ phải sang trái với 2^ tăng tương ứng từ 0...n
vd: 
Tương tự ta sẽ chuyển dc hệ cơ số 10, 2, 8 với nhau
vd: 
- khi chuyển từ hệ cơ số khác về hệ cơ số 16 với số dư > 9 cần đưa về mã trong bảng ASCII

vd:
## B.Tìm hiểu về bit và byte
**I.Khái niệm:**
- Bit là đơn vị nhỏ nhất của thông tin máy tính và là nơi lưu trữ dung lượng của các bộ nhớ như: ROM, RAM, ổ cứng, USB, thẻ nhớ,…. Bit là một điểm dữ liệu nhị phân duy nhất; có hoặc không, bật hoặc tắt, lên hoặc xuống.
- Biểu diễn dưới dạng số nhị phân là 0 hoặc 1.
- Một byte là một đơn vị bộ nhớ thường chứa 8 bit. 8 bit là điều kiện tối thiểu để mã hóa một ký tự văn bản.
- 1 byte được thể hiện 256 giá trị trạng thái của thông tin. Có nghĩa, 1 byte được biểu diễn từ số 0 – 255. 1 byte chỉ biểu diễn 1 ký tự, 10 byte đương đương gần 1 từ, và 100 byte tương đương khoảng 1 câu có độ dài ở mức trung bình.
**II.Vai trò:**
- Byte (viết tắt: B)được sử dụng dùng để biểu thị dung lượng của các thiết bị lưu trữ.
- Bit (viết tắt: b)thể hiện tốc độ truyền tải dữ liệu của thiết bị lưu trữ mạng internet.
**III.Cách chuyển đổi:**

- Ngoài ra còn có: mega, giga, tera, peta,…
- Với 1 file dung lượng 10MB chỉ mất khoảng 1 giây để truyền dữ liệu từ máy A sang máy B và có tốc độ 80Mbps(10MB x 8 = 80Mbps)

## **Bài tập**
### Chuyển số hệ cơ số 2 sang 10 và ngược lại
```
#include <stdio.h>
#include <math.h>
int BinToDec(long long a)
{
int p = 0;
int n = 0;
while (a > 0)
{
n += (a % 10) * pow(2, p);
p=p+1;
a /= 10;
}
return n;
}
long long BinToDec(int n) // Ctrl H => find & replace
{
long long a = 0;
int p = 0;
while (n > 0)
{
a += (n % 2) * pow(10, p);
++p;
n /= 2;
}
return a;
}
int main()
{
long long a;
printf("\nBin: ");
scanf("%d", &a);
printf("Dec = %d", BinToDec(a));
int n;
printf("\nDec: ");
scanf("%d", &n);
printf("Bin = %d", BinToDec(n));
}
```
run:

### Chuyển số hệ cơ số 10 sang 8 và ngược lại
```
#include <stdio.h>
#include <math.h>
int DecToOct(int a){
int p = 0;
int n = 0;
while(a > 0){
n += (a % 8) * pow(10, p);
p++;
a /= 8;
}
return n;
}
int OcttoDec(int a){
int p = 0;
int x = 0;
while(a > 0){
x += (a % 10) * pow(8, p);
p++;
a /= 10;
}
return x;
}
int main(){
int x;
printf("\nDec=: ");
scanf("%d", &x);
printf("\nOct = %d", DecToOct(x));
int n;
printf("\nOct: ");
scanf("%d", &n);
printf("\nDec = %d", OcttoDec(n));
}
```
run:

### Chuyển số hệ cơ số 10 sang 16 và ngược lại
```
#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;
void chuyen10sang16(int n, char KQ[]);
void chuyen10sang16(int n, char KQ[])
{
int d=0;
while (n>0)
{
int x= n%16;
n=n/16;
if (x<10)
KQ[d]= x + '0';
else
KQ[d]= x +55;
d++;
}
KQ[d]= '\0';
strrev(KQ);
printf("%s",KQ);
}
void chuyen16sang10(char S[], int &h);
void chuyen16sang10(char S[], int &h)
{
strrev(S);
h = 0;
int i;
int len = strlen(S);
for (int i=0; i<len;i++)
{
if (S[i]>='0' && S[i]<='9')
h = h + (S[i] - '0')*pow(16,i);
else
h = h + (S[i] +10 -'A')*pow(16,i);
}
}
int main()
{
int n,h;
printf("Nhap he 10: ");
scanf("%d", &n);
char KQ[20];
chuyen10sang16(n,KQ);
char S[20];
cout<<"\nNhap he 16: ";
cin>>S;
chuyen16sang10(S,h);
cout<<h;
}
```
run:
