Trong các ngôn ngữ lập trình, khả năng lưu trữ của kiểu số thường có 1 giới hạn. Ví dụ kiểu dữ liệu
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
0 của ngôn ngữ C++ thường giới hạn ở mức
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
1 đến
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
2.
Có những bài toán thực tế cần thao tác với những số vượt quá giới hạn này. Do đó cần phải có những phương pháp để giải quyết như:
- Sử dụng những thư viện hỗ trợ thêm.
- Tự xây dựng các kiểu dữ liệu này và cung cấp các phương thức lưu trữ và thao tác.
Phép cộng hai số lớn
Lựa chọn kiểu dữ liệu
Với một số nguyên lớn có 20 độ dài 20 ký số, một biến thông thường không thể hiện được toàn bộ số lớn này. Vì vậy chọn cách dùng nhiều biến để biểu diễn từng chữ số, như vậy có thể sử dụng một mảng các ký số để biểu diễn cho một số lớn.
Một chữ số có giá trị từ 0 – 9 nên để tối ưu và đơn giản cho thao tác nhập mảng, có thể sử dụng mảng kiểu
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
3.
Hàm cộng hai số lớn có dạng:
char* addBigNumber[char* number1, char* number2];
Với hai chuỗi
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
4,
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
5 là hai số lớn cần tính toán.
Hiện thực phép toán
Có 2 trường hợp sau khi cộng hai số
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
4 và
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
5:
- size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false; 4 có chiều dài [số ký số] lớn hơn hoặc bằng số size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false; 5.
- size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false; 5 có chiều dài lớn hơn hoặc bằng số size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false; 4.
Để tổng quát hóa hai trường hợp trên, cần so sánh chiều dài hai số
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
4 và
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
5, nếu số
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
5 có chiều dài lớn hơn số
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
4, thực hiện đảo giá trị hai pointer chứa địa chỉ mảng
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
4 và mảng
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
5. Từ đó,
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
4 luôn có chiều dài lớn hơn hoặc bằng
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
5.
Để đơn giản cho thao tác với chuỗi, sử dụng hàm
int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0';
0 trong thư viện
int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0';
1.
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
Hàm
int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0';
2 được định nghĩa như sau:
void swapPointer[char* a, char* b] { char* temp = *a; *a = *b; *b = temp; }
Khai báo một số biến cần thiết trong quá trình tính toán như sau:
- int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0'; 3, int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0'; 4 là chiều dài hai số size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false; 4, size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false; 5.
- int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0'; 7 là kết quả int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0'; 8, chiều dài của int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0'; 7 luôn bằng hoặc lớn hơn chiều dài số size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false; 4 một đơn vị tùy trường hợp nên khi cấp phát cho int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0'; 7 cần thêm 1 byte và 1 byte nữa là dành cho ký tự rỗng cuối chuỗi là 2 byte.
- if [remember] temp++; remember = temp > 9; temp = temp % 10; 2 là biến chỉ trạng thái “nhớ” của phép tính khi cộng 2 chữ số, ban đầu là if [remember] temp++; remember = temp > 9; temp = temp % 10; 3.
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
Có hai công đoạn khi thực hiện cộng 2 số:
- Tính tổng các chữ số của cả size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false; 4 và size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false; 5 [phần bên phải].
- Tính tổng các chữ số của
size_t number1Len = strlen[number1], number2Len = strlen[number2];
char* result = new char[number1len + 2];
bool remember = false;
4 với
if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
7 [phần bên trái].
Như vậy cần hai vòng lặp để làm những việc này.
Bước 1
Số lần lặp của công đoạn này sẽ là
if [remember] temp++; remember = temp > 9; temp = temp % 10;
8
for [int i = 0; i < number2Len; i++] { //... }
Cần tính tổng các chữ số từ phải qua trái, lấy giá trị các chữ số này bằng cách sử dụng
if [remember] temp++; remember = temp > 9; temp = temp % 10;
9 và
*[result + number1Len - i] = temp + '0';
0.
Mỗi giá trị hiện tại đang được lưu trong mảng với kiểu
*[result + number1Len - i] = temp + '0';
1, để lấy được chính xác giá trị kiểu số của các chữ số này, trừ mỗi giá trị cho
*[result + number1Len - i] = temp + '0';
2 [
*[result + number1Len - i] = temp + '0';
3]. Ví dụ: ký tự
*[result + number1Len - i] = temp + '0';
4 trong kiểu char có giá trị là
*[result + number1Len - i] = temp + '0';
5, lấy
*[result + number1Len - i] = temp + '0';
6 được 9.
Dùng một biến tạm để lưu tổng của 2 giá trị này:
int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0';
Ví dụ: khi cộng
*[result + number1Len - i] = temp + '0';
7 và
*[result + number1Len - i] = temp + '0';
8, kết quả là
*[result + number1Len - i] = temp + '0';
9
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}0 nên chỉ lấy chữ số hàng đơn vị là
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}1, nhớ
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}1, tiếp theo, lấy
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}3 được
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}4, vì có nhớ nên ghi
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}5. Kết quả là
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}6.
Theo logic đó, tiếp xét giá trị biến
if [remember] temp++; remember = temp > 9; temp = temp % 10;
2, nếu là
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}8 thì cộng
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}9 lên 1 đơn vị, nếu
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}9 có giá trị
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}0, gán
int temp = number1[number1Len - number2Len - i – 1] - '0';
2, ngược lại ta gán
int temp = number1[number1Len - number2Len - i – 1] - '0';
3. Để lấy chữ số hàng đơn vị của
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}9, ta lấy
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}9 chia phần dư cho 10.
if [remember] temp++; remember = temp > 9; temp = temp % 10;
Tổng các chữ số của
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
4 và
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
5 đã được tính với cách trên, gán giá trị này vào mảng
int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0';
7. Tương tự cách làm ở trên, để ghi được ký tự
*[result + number1Len - i] = temp + '0';
4 vào mảng, cộng số
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
00 với
*[result + number1Len - i] = temp + '0';
2 [
*[result + number1Len - i] = temp + '0';
3].
*[result + number1Len - i] = temp + '0';
Vậy ta có code hoàn chỉnh cho vòng lặp vừa rồi như sau:
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}Với vòng lặp này, có thể cộng hai số lớn có chiều dài bằng nhau.
Bước 2
Tương tự các bước của công đoạn thứ nhất, số lần lặp của công đoạn này là:
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
03.
Giai đoạn này lấy giá trị các ký số của
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
4 bằng cách sử dụng:
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
05, từ đó có giá trị biến
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}9 là:
int temp = number1[number1Len - number2Len - i – 1] - '0';
Tương tự giá trị
int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0';
7 như sau:
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
0
Code hoàn chỉnh:
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
1
Để đánh dấu kết thúc chuỗi
int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0';
7, gán:
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
2
Ví dụ
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
09, làm lần lượt các bước như trên, được result có 4 chữ số, nhưng đáp án là
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
10 có 5 ký số. Để làm được việc này, xét giá trị biến
if [remember] temp++; remember = temp > 9; temp = temp % 10;
2, nếu là
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}8: gán giá trị
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
13, ngược lại, dịch tất cả các phần tử của mảng
int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0';
7 sang bên trái một đơn vị.
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
3
Cuối cùng, trả về
int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0';
7 là kết quả của
int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0';
8.
Kiểm thử với hàm
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
17:
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
4
Kết quả:
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
18.
Code hoàn chỉnh cộng 2 số lớn
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
5
Phép trừ hai số lớn
Hàm trừ hai số lớn có dạng:
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
6
Với hai chuỗi
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
4,
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
5 là hai số lớn cần tính toán.
Hiện thực phép toán
Khi trừ hai số
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
4 và
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
5, phải biết số nào lớn hơn để thực hiện phép trừ. Ví dụ khi thực hiện phép toán
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
23. Xác định 100 lớn hơn 9 nên lấy
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
24, thêm dấu trừ và được kết quả
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
25.
Để cho thuận tiện kiểm tra
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
5 có lớn
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
4 hay không? Nếu có thì ta đảo hai pointer chứa địa chỉ hai mảng
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
4,
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
5 và thêm dấu trừ vào trước kết quả.
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
7
Đoạn code trên kiểm tra độ dài 2 số, nếu bằng nhau sẽ tiếp tục so sánh từng chữ số từ phải qua trái để tìm ra số lớn hơn, sau đó đảo vị trí các pointer [nếu cần].
Khai báo và gán giá trị một số biến cần thiết trong quá trình tính toán như sau:
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
8
int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0';
7 được cấp phát thêm 2 bytes: một byte dành cho ký tự rỗng cuối chuỗi, một byte cho dấu trừ đầu chuỗi nếu kết quả là số âm.
Có hai công đoạn khi thực hiện trừ hai số:
- Tính hiệu các chữ số của size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false; 4 cho size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false; 5 [phần bên phải].
- Tính hiệu các chữ số của
size_t number1Len = strlen[number1], number2Len = strlen[number2];
char* result = new char[number1len + 2];
bool remember = false;
4 với
if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
7 [phần bên trái].
Như vậy cần hai vòng lặp để làm việc này.
Bước 1
Số lần lặp của công đoạn này là
int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0';
4:
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
9
Cần tính hiệu các ký số từ phải qua trái, vì phép trừ nên chỉ cần số chênh lệch giữa 2 số:
void swapPointer[char* a, char* b] { char* temp = *a; *a = *b; *b = temp; }
0
Theo như logic của phép trừ, khi một chữ số của
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
4 nhỏ hơn
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
5, khi trừ phải mượn 1 từ chữ số tiếp theo bên trái. Và kết quả phép trừ được cộng thêm 10, kết quả phép trừ tiếp theo sẽ giảm 1 đơn vị do mượn 1 từ phép trừ vừa rồi:
void swapPointer[char* a, char* b] { char* temp = *a; *a = *b; *b = temp; }
1
Gán kết quả vừa tính vào
int temp = number2[number2Len - i - 1] - '0' + number1[number1Len - i - 1] - '0';
7:
void swapPointer[char* a, char* b] { char* temp = *a; *a = *b; *b = temp; }
2
Code hoàn chỉnh cho vòng lặp vừa rồi như sau:
void swapPointer[char* a, char* b] { char* temp = *a; *a = *b; *b = temp; }
3
Bước 2
Số lần lặp của công đoạn này là:
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
03.
Giai đoạn này chỉ cần lấy giá trị các ký số của
size_t number1Len = strlen[number1], number2Len = strlen[number2]; char* result = new char[number1len + 2]; bool remember = false;
4 bằng cách sử dụng:
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
41, từ đó có giá trị biến
for [int i = 0; i < number2Len; i++] { int temp = [b + number2Len - i - 1] - '0' + [a + number1Len - i - 1] - '0'; if [remember]
temp++;
remember = temp > 9;
temp = temp % 10;
result[number1Len - i] = temp + '0';
}9 là:
void swapPointer[char* a, char* b] { char* temp = *a; *a = *b; *b = temp; }
4
tương tự ta có giá trị result như sau:
void swapPointer[char* a, char* b] { char* temp = *a; *a = *b; *b = temp; }
5
vậy ta có code hoàn chỉnh:
void swapPointer[char* a, char* b] { char* temp = *a; *a = *b; *b = temp; }
6
Ví dụ:
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
43 với những gì đã làm ta được kết quả là
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
44, xóa số 0 trước chuỗi và thêm dấu trừ [nếu có] vào đầu chuỗi dựa vào giá trị biến
if [strlen[number1] < strlen[number2]] { swapPointer[&number1, &number2]; }
45.