Nhân hai số nguyên lớn - mô tả phép nhân tay
Trang 1LỜI NÓI ĐẦU
Khoa học công nghệ ngày nay đang ngày một phát triển, với nhữngứng dụng của khoa học công nghệ vào trong thực tiễn đã giúp cho đời sốngcon người được nâng lên một tầm cao mới
Trong đó sự phát triển mạnh mẽ nhất và cũng được ứng dụng nhiềunhất vào đời sống của con người đó là khoa học về máy tính Bao gồm cảcác ứng dụng về phần cứng và phần mềm
Với sự tìm tòi và nghiên cứu của các công ty phần mềm và các lậptrình viên trên thế giới Các ngôn ngữ lập trình mới xuất hiện liên tục, ngônngữ ra đời sau càng hỗ trợ nhiều component hơn, giúp cho các lập trình viênthiết kế các chương trình ứng dụng ngày càng đơn giản và thuận tiện
Tuy nhiên để nắm bắt được các ngôn ngữ lập trình mới một cách toàndiện và đầy đủ đòi hỏi các lập trình viên phải có một căn bản lập trình tốt.Điều đó có nghĩa là họ phải nghiên cứu và sử dụng thành thạo các ngôn ngữ
hỗ trợ ít hơn (như C,C++)
Với mong muốn có một căn bản lập trình tốt để sau này có thể nghiêncứu và tiếp thu nhanh các ngôn ngữ mới, em đã chọn ngôn ngữ C để thựchiện bài tập tốt nghiệp cuối khóa, với đề tài:
“ Viết chương trình nhân 2 số nguyên lớn ”.
Đây là một đề tài rất hay, bởi đề tài đặt ra cho người thực hiện mộtkhó khăn rất lớn là làm thế nào để lưu được kết quả của mỗi phép nhân Vìvới các kiểu dữ liệu về số thông thường như int, long int, float,…đều khôngthể lưu được vì vượt quá giá trị có thể lưu của mỗi kiểu dữ liệu
Với sự giúp đỡ tận tình của thầy Đinh Tuấn Long, cộng với sự tìm
tòi, học hỏi của bản thân em đã giải quyết được vấn đề mà bài toán đặt rabằng cách sử dụng mảng kí tự để giải quyết bài toán
Tuy nhiên do sự hạn chế về kiến thức lập trình và thời gian nghiêncứu không sâu, nên có thể bài toán được giải quyết chưa triệt để Vì vậymong sự góp ý và chỉ bảo của các thầy, cô để em có thể có cách giải quyếtvấn đề tốt hơn, đồng thời có thể hiểu sâu hơn về ngôn ngữ C
Em xin chân thành cảm ơn !
Trang 2Nội dung trình bày bài toán sẽ bao gồm 6 Chương:
- Chương 1 sẽ trình bày sơ bộ về những nét cơ bản, những tiện ích và
những hạn chế của ngôn ngữ C
- Chương 2 sẽ trình bày về việc tìm hiểu nội dung bài toán, những câu
hỏi cần được giải đáp, và sẽ giải đáp theo phương hướng nào
- Chương 3 sẽ trình bày một số giao diện sử dụng trong chương trình.
- Chương 4 là những dòng mã lệnh thực hiện chương trình.
- Chương 5 sẽ đưa ra những tài liệu tham khảo để thực hiện bài toán.
- Chương 6 là mục lục – lần lượt trình bày các nội dung bài toán.
Trang 3Chương 1: Tìm hiểu về ngôn ngữ C
I LỊCH SỬ NGÔN NGỮ C
1 Giới thiệu về ngôn ngữ C
Ngôn ngữ lập trình C là một ngôn ngữ mệnh lệnh được phát triển từ đầu
thập niên 1970 bởi Ken Thompson và Dennis Ritchie để dùng trong hệ điềuhành UNIX Từ dó, ngôn ngữ này đã lan rộng ra nhiều hệ điều hành khác vàtrở thành một những ngôn ngữ phổ dụng nhất C là ngôn ngữ rất có hiệu quả
và được ưa chuộng nhất để viết các phần mềm hệ thống, mặc dù nó cũngđược dùng cho việc viết các ứng dụng Ngoài ra, C cũng thường được dùnglàm phương tiện giảng dạy trong khoa học máy tính mặc dù ngôn ngữ nàykhông dược thiết kế dành cho người nhập môn
Những phát triển ban đầu:
Phát triển khởi đầu của C xảy ra ở AT&T Bell Labs giữa 1969 và 1973; theoRitchie thì thời gian sáng tạo nhất là vào năm 1972 Nó được đặt tên là C vìnhiều đặc tính của nó rút ra từ một ngôn ngữ trước đó là B
Thêm vào đó, các điểm khác với ngôn ngữ nguyên thủy "B": Ken Thompson
kể tới ngôn ngữ lập trình BCPL, nhưng ông ta cũng đã tạo ra ngôn ngữ làBon để vinh danh vợ mình
Có nhiều truyền thuyết về nguồn gốc của C và hệ điều hành liên quan tới nó
là Unix bao gồm:
Sự phát triển của C là kết quả của các lập trình viên đã muốn chơiSpace Travel Họ đã chơi nó trên mainframe của hãng làm việc,nhưng bị thiếu khả năng (chạy) và phải hỗ trợ khoảng 100 ngườidùng, Thompson và Ritchie tìm thấy rằng họ đã không có đủ sự kiểmsoát tàu vũ trụ (của trò chơi) để tránh được các va chạm khỏi sựchuyển dịch của các thiên thạch Do đó, họ quyết định để xuất trò chơinày sang một máy PDP-7 để không trong văn phòng Nhưng nó lạikhông có hệ điều hành; do đó, họ viết một hệ điều hành Tiếp tục, họquyết định để xuất hệ điều hành này sang PDP-11 của văn phòngnhưng việc này thật khó vì tất cả mã đều là ngôn ngữ Assembly Họquyết dịnh dùng một ngôn ngữ dể xuất cấp cao để hệ điều hành có thểxuất được dễ dàng từ máy tính này sang máy khác Họ đã tìm đếnngôn ngữ B, nhưng nó lại thiếu các chức năng để khai thác một số khảnăng của PDP-11 Vậy nên họ đã sáng tạo ra một ngôn ngữ mới là C
Trang 4 Unix nguyên đã được phát triển để tạo ra một hệ thống tự động lập hồ
sơ cho các bằng phát minh Phiên bản đầu tiên của Unix đã phát triển
từ ngôn ngữ Assembly Sau đó, ngôn ngữ C đã được phát triển để từ
đó thay thế hệ điều hành mới
Cho đến 1973, C đã trở nên đủ mạnh để dùng viết nhân cho Unix, thay vìtrước nó chúng được viết bằng Assembly trong các máy PDP-11/20 Đây làlần đầu tiên mà nhân của một hệ điều hành được lắp thành bằng một ngônngữ khác hơn Assembly
2 Những điểm mạnh và hạn chế của ngôn ngữ C.
C là một ngôn ngữ lập trình tương đối nhỏ gọn vận hành gần với phầncứng và nó giống với ngôn ngữ Assembler hơn hầu hết các ngôn ngữ bậccao Hơn thế, C đôi khi được đánh giá như là "có khả năng di động", chothấy sự khác nhau quan trọng giữa nó với ngôn ngữ bậc thấp như làAssembler, đó là việc mã C có thể được dịch và thi hành trong hầu hết cácmáy tính, hơn hẳn các ngôn ngữ hiện tại trong khi đó thì Assembler chỉ cóthể chạy trong một số máy tính đặc biệt Vì lý do này C được xem là ngônngữ bậc trung
* Ưu điểm của ngôn ngữ C:
C đã được tạo ra với một mục tiêu là làm cho nó thuận tiện để viết cácchương trình lớn với số lỗi ít hơn trong mẫu hình lập trình thủ tục mà lạikhông đặt gánh nặng lên vai người viết ra trình dịch C, là những người bềbộn với các đặc tả phức tạp của ngôn ngữ Cuối cùng C có thêm những chứcnăng sau:
Một ngôn ngữ cốt lõi đơn giản, với các chức năng quan trọng chẳnghạn như là những hàm hay việc xử lý tập tin sẽ được cung cấp bởi các
Trang 5 Mức thấp của ngôn ngữ cho phép dùng tới bộ nhớ máy tính qua việc
xử dụng kiểu dữ liệu pointer
Số lượng từ khóa rất nhỏ gọn
Các tham số được đưa vào các hàm bằng giá trị, không bằng địa chỉ
Hàm các con trỏ cho phép hình thành một nền tảng ban đầu cho tínhđóng và tính đa hình
Hổ trợ các bản ghi hay các kiểu dữ liệu kết hợp do người dùng từkhóa định nghĩa struct cho phép các dữ liệu liên hệ nhau có thểđược tập hợp lại và được điều chỉnh như là toàn bộ
* Những điểm hạn chế của ngôn ngữ C:
Một số chức năng khác mà C không có (hay còn thiếu) nhưng có thể tìmthấy ở các ngôn ngữ khác bao gồm:
Quá tải và Quá tải toán tử,
Các hỗ trợ cho đa luồng, đa nhiêm và mạng
Mặc dù C còn thiếu nhiều chức năng hữu ích nhưng lý do quan trọng để Cđược chấp nhận vì nó cho phép các trình dịch mới được tạo ra một cáchnhanh chóng trên các nền tảng mới và vì nó cho phép người lập trình dễkiểm soát được những gì mà chưong trình (do họ viết) thực thi Đây là điểmthường làm cho mã C chạy hiệu quả hơn các ngôn ngữ khác Thường thì chỉ
có ngôn ngữ ASM chỉnh bằng tay chạy nhanh hơn (ngôn ngữ C), bởi vìASM kiểm soát đưọc toàn bộ máy Mặc dù vậy, với sự phát triển các trìnhdịch C, và với sự phức tạp của các CPU hiện đại, C đã dần thu nhỏ khoảngcách khác biệt về vận tốc này
Một lý do nữa cho việc C được xử dụng rộng rãi và hiệu quả là do các trìnhdịch, các thư viện và các phần mềm thông dịch của các ngôn ngữ bậc caokhác lại thường được tạo nên từ C
Trang 6II NHỮNG KIẾN THỨC SỬ DỤNG TRONG CHƯƠNG TRÌNH.
1 Sử dụng kiểu dữ liệu
Trong C sử dụng các kiểu dữ liệu:
- Ký tự (char)
- Số nguyên (int)
- Số dấu phẩy động độ chính xác đơn (float)
- Số dấu phẩy động chính xác kép (double)
Các kiểu ký tự cũng được xem là một dạng của Kiểu nguyên
c Kiểu dấu phẩy động.
Trong C cho phép sử dụng 3 loại giá trị dấu phẩy động là float, double vàlong double
Kích cỡ và phạm vi biểu diễn:
Trang 7Kiểu Phạm vi Chữ chữ số Kích thước
biểu diễn có nghĩa (byte) float 3.4E-38->3.4E+38 7-8 4 double 1.7E-308->1.7E+308 15-16 8 long double 3.4E-4932->1.1E+4932 17-18 10
float x,y;// Khai báo biến kiểu float double xd,yd;// Khai báo biến kiểu double
… }
Vị trí khai báo: Các khai báo cần đặt ngay sau dấu { đầu tiên của thânhàm và cần đứng trước mọi câu lệnh khác Chẳng hạn sau câu lệnh gán thìkhông được khai báo nữa
Khởi đầu cho các biến:
Ví dụ:
int a,b = 20,c,d = 40;
Tức vừa khai báo vừa khởi đầu giá trị cho biến Trong trường hợp trênbiến b được gán cho giá trị bằng 20, và biến d cũng được gán giá trị bằng 40
Lấy địa chỉ của biến: Mỗi biến được cấp phát một vùng nhớ gồm một
số byte liên tiếp Số hiệu của byte đầu chính là địa chỉ của biến Địa chỉ củabiến chỉ dùng trong một số hàm như hàm scanf…Để nhận địa chỉ của biến tadùng phép toán:
& tên_biến;
3 Sử dụng mảng.
Mảng là một tập hợp nhiều phần tử có cùng một kiểu giá trị và có chungmột tên Mỗi phần tử mảng có vai trò như một biến và chứa được một giá trị
Trang 8Có bao nhiêu kiểu dữ liệu cho biến thì cũng có bấy nhiêu kiểu dữ liệu chomảng.
Mảng bao gồm mảng một chiều và mảng nhiều chiều
Ví dụ:
char ho[20],ten[20]; //khai báo mảng một chiều kiểu char
//mỗi mảng gồm tối đa 20 phần tử int matran[10][10];//Khai báo mảng hai chiểu kiểu int
//mảng gồm 10 hàng và 10 cột
Các phần tử của mảng được cấp phát các khoảng nhớ liên tiếp nhau trong
bộ nhớ, đối với mảng hai chiều các phần tử mảng được sắp xếp theo hàng.Chỉ số mảng: Một phần tử cụ thể của mảng được xác định nhờ các chỉ sốcủa nó Chỉ số của mảng phải có giá trị int không được vượt quá kích thướccủa chiều tương ứng Số chỉ số phải bằng số chiều của mảng
Có thể lấy địa chỉ mảng một chiều như: &a[i];
Nhưng không cho phép lấy địa chỉ mảng hai chiều
4 Sử dụng hàm.
a Hàm printf.
Hàm printf có khả năng chuyển dạng, tạo khuôn và đưa giá trị các đối ramàn hình Dạng tổng quát của hàm như sau:
Int printf(const char *dk,[,danh sách các đối]);
- Với đối dk là biến con trỏ kiểu char chứa địa chỉ của chuỗi điều khiển
Chuỗi điều khiển bao gồm ba loại ký tự:
+ Các ký tự không phải là đặc tả cũng không phải là ký tự điều khiển gọi là ký tự hiển thị (được đưa ra màn hình).
- Danh sách các đối:
Các đối cần được phân cách nhau bởi dấu phẩy Đối có thể là một hằng, mộtbiến, một phần tử mảng, một lời gọi hàm…Giá trị của đối sẽ được chuyển
Trang 9dạng và in ra theo cách của đặc tả tương ứng Khi mà một đặc tả không tìmthấy đối tương ứng hoặc khi kiểu giá trị của đối tương ứng không tươngthích với ký tự chuyển dạng thì máy sẽ bị lẫn lộn và có thể đưa ra kết quả vônghĩa.
- Giá trị của hàm printf():
Khi thành công, hàm cho biết số ký tự(kể cả ký tự điều khiển) được đưa ra.Khi có lỗi, hàm có giá trị -1
b Hàm scanf.
Hàm scanf là hàm có nhiều chức năng tương tự như hàm printf nhưngtheo chiều ngược lại Nó đọc thông tin từ thiết bị vào chuẩn(bàn phím),chuyển dịch chúng (thành số nguyên, thực,…) và lưu trữ vào bộ nhớ theocác địa chỉ xác định
Hàm có dạng:
int scanf(const char*dk,[,danh sách các đối]);
- dk là biến con trỏ kiểu char chứa địa chỉ của chuỗi điều khiển
- danh sách các đối: Mỗi đối trong danh sách là một con trỏ chứa địachỉ của một vùng nhớ(địa chỉ, biến mảng,…) dùng để lưu một giá trịđọc vào từ bàn phím Các đối cần được phân cách với nhau bởi dấuphẩy
- Chuỗi điều khiển gồm các ký tự đặc tả chuyển dạng Mỗi đặc tảchuyển dạng thường có một đối tương ứng
- Giá trị của hàm: Hàm cho một số nguyên bằng số giá trị nhận được(lưu vào bộ nhớ)
Chú ý: Để việc nhập số liệu được chính xác ta nên làm theo các yêu cầu:
+ Số đối, số đặc tả và số trường vào phải bằng nhau
+ Giữa đối, đặc tả và trường vào cần có sự phù hợp
- Nếu bộ đệm rỗng, thì máy tạm dừng Khi gõ một ký tự thì hàm nhậnngay được ký tự đó (Không cần bấm thêm Enter như trong các hàmnhập từ stdin) Ký tự vừa gõ không được hiện lên màn hình
+ Hàm trả về ký tự nhận được
Trang 10d Hàm gotoxy Cho phép di chuyển con trỏ chuột đến vị trí bất kỳ trên
- Biểu thức có thể nguyên hoặc thực
* Sự hoạt động của toán tử if:
Trước tiên máy sẽ xác định giá trị của biểu thức Nếu thiểu thức đúng (cógiá trị khác không) máy sẽ thực hiện khối lệnh 1 sau đó nhảy đến các lệnhviết sau khối lệnh 2 (hoặc thực hiện các lệnh tiếp theo ở Dạng 2) và sau đóthực hiện các lệnh viết sau đó
Trang 11- Tính biểu thức 3, sau đó quay trở lại bước 2 để bắt đầu một vòngmới của chu trình.
* Sự hoạt động của while:
- Xác định giá trị của biểu thức (viết sau while)
- Tùy thuộc vào tính đúng sai của biểu thức này, máy sẽ lựa chọn mộttrong hai nhánh:
+ Nếu biểu thức có giá trị 0 (sai), máy sẽ ra khỏi chu trình vàchuyển tới câu lệnh sau thân while
+ Nếu biểu thức có giá trị khác 0 (đúng), máy sẽ thực hiện cáccâu lệnh trong thân while Khi gặp dấu ngoặc nhọn đóng cuối cùng của thânwhile máy sẽ trở lại bước 1
d Toán tử do…while.
Tương tự như toán tử for và while, nhưng khác với hai toán tử trên trong
chu trình do while việc kiểm tra điều kiện kết thúc đặt ở cuối chu trình Như
vậy thân chu trình bao giờ cũng được thực hiện ít nhất một lần
Toán tử do while có dạng:
do
khối lệnh;
while(biểu thức);
* Sự hoạt động của do while: Toán tử này thực hiện theo các bước sau
- Thực hiện các câu lệnh trong thân do while
- Khi gặp dấu ngoặc nhọn cuối cùng của thân do while, máy sẽ xácđịnh giá trị của biểu thức sau từ khóa while
- Máy sẽ phân nhánh theo giá trị của biểu thức vừa nhận được
Trang 12+ Nếu biểu thức có giá trị bằng 0 (sai), máy sẽ ra khỏi chu trình
và chuyển tới câu lệnh đứng sau dấu chấm phẩy đặt cuối toán tử do while
+ Nếu biểu thức có giá trị bằng 1 (đúng), máy sẽ quay trở lạibước đầu, thực hiện biểu thức trong thân do while
Trang 13Chương 2: Đặt vấn đề và hướng giải quyết bài toán
I TRÌNH BÀY TỔNG QUAN VỀ CHƯƠNG TRÌNH
Như đã trình bày ở Chương 1, thì việc thực hiện bài toán không thểthực hiện một cách thông thường như việc nhân hai số kiểu “int” hay kiểu
“long”, mà để thực hiện nhân hai số nguyên lớn cỡ 20 chữ số ta phải dùngmảng để lưu trữ các phần tử nhập vào, cụ thể trong bài toán em sử dụng mộtmảng kiểu “char”, từ đó mỗi phần tử nhập vào ta có thể coi như mỗi kí tự
mà mỗi kí tự sẽ được lưu trữ vào mỗi phần tử trong mảng Số các phần tửnhập vào sẽ phụ thuộc vào độ lớn của mảng khai báo
Theo đề bài: “Nhân hai số nguyên lớn” với yêu cầu nhập vào hai số
nguyên lớn (dưới 20 kí tự), và in ra tích hai số nguyên đó Mô tả phép nhântay Theo sự góp ý của Thầy giáo hướng dẫn Em đã chia ra thành hai bàitoán nhỏ:
- Một là nhân một số có 1 chữ số với một số nguyên lớn
- Hai là cộng hai số nguyên lớn
Khi nhân một số với một số nguyên lớn, tương đương với việc lấy số đólần lượt nhân với từng thành phần trong số nguyên lớn: chẳng hạn, lấy một
số nhân với hàng đơn vị của của số nguyên lớn, ta sẽ được hàng đơn vị của
số kết quả, cứ tiếp như vậy ta sẽ lần lượt nhân một số với hàng chục, hàngtrăm…và cuối cùng ta sẽ có kết quả của việc nhân một số với một số nguyênlớn
Như vậy ta sẽ có một số nhân lần lượt với từng phần tử trong mộtmảng lưu trữ các số nguyên nhập vào, kết quả nhận được cũng sẽ lưu trữ vàomột mảng các chữ số nguyên Được kết quả của việc nhân một số với một sốnguyên lớn, cộng dồn các kết quả ta sẽ có được tích của hai số nguyên lớn.Việc cộng hai số nguyên lớn thực chất là việc cộng từng phần tử của haimảng lưu trữ các số nguyên lại với nhau
Bài toán sử dụng hai hàm: Hàm nhan() và hàm main() Hàm nhan() sẽlàm nhiệm vụ nhân hai số nguyên lớn, còn hàm main() là hàm chính, đểtrình bày giao diện nhập, gọi hàm nhân và in ra kết quả phép tính
* Trong hàm nhan() sẽ phải thực hiện nhân một số với một số nguyên
lớn, và sẽ có kết quả của phép nhân và phép cộng, vì vậy trong hàm sẽ phải
sử dụng hai mảng để lưu trữ hai kết quả của phép nhân và phép cộng Đó là
mảng “int tg[]” để lưu trữ kết quả phép nhân và mảng “int tong[]” để lưu trữ
kết quả phép cộng
Trong phép nhân và phép cộng, kết quả đều liên quan đến phép nhớ, nếuphép nhân với hàng đơn vị >=10 thì cần có một biến để lưu trữ giá trị nhớ
Trang 14cho lần nhân tiếp theo, tương tự phép cộng, nếu cộng hàng đơn vị được kếtquả >=10 cũng cần một biến nhớ để lưu trữ giá trị nhớ cộng vào hàng chục.
Vì vậy ở trong hàm nhan() phải sử dụng một biến nhớ chung là biến “nho”
kiểu int
Và khi nhân hai số nguyên lớn ta sẽ thực hiện lấy từng số từ hàng đơn vịnhân với số kia và đến hàng chục, hàng trăm… Vậy cần một biến để quyđịnh phần tử mảng nào đem nhân là hàng đơn vị, hàng chục, trăm… Biến
“bac” kiểu int, sẽ quy định bậc của phần tử đem nhân
Cộng với một số các biến để sử dụng trong các vòng lặp như i,j,ntg,nmax
* Trong hàm main(), vì đây là hàm chính dùng để cho phép nhập giá trị
hai số nguyên và in ra kết quả phép nhân(tức gọi hàm nhan()) vì vậy trong
hàm sẽ phải sử dụng một số biến cục bộ cho phép hàm nhan() có thể sử dụngđược nó
- Hai biến mảng kiểu “char[]” dùng để lưu hai giá trị số nguyên nhập vào là son[] và sobn[], và hai mảng kiểu “int[]” là “mảng s1[] và mảng
s2[]” dùng để tách và lưu trữ từng phần tử nhập vào.
- Việc nhân hai số nguyên bao gồm cả số nguyên dương và số nguyên
âm, vì vậy cần có biến để quy định dấu của số nhập vào, trong hàm sử dụng
biến cục bộ là biến “dau” kiểu int.
- Và một số các biến khác được sử dụng trong chương trình
II SỬ DỤNG THUẬT TOÁN
1 Nhân một số với một số nguyên lớn.
Giả sử ta lấy một số nguyên a nhân với một số nguyên lớn
Sử dụng mảng “char son[]” để nhập số nguyên lớn, sau khi nhập từng phần tử mảng son[] sẽ được chuyển thành giá trị kiểu int và lưu vào trong một mảng int s1[] bằng cách cộng thêm vào mã ASCII.
Lúc này việc nhân số nguyên a với số nguyên lớn là việc nhân một số với
từng phẩn tử trong mảng số nguyên s1[].
Ta sử dụng vòng lặp for() duyệt từ đầu đến cuối mảng mảng s1[] rồi lấy
từng phần tử trong mảng nhân với a Nếu giá trị nhớ khác “0” thì sẽ đượccộng vào phần tử mảng tiếp theo
Trang 15nhớ = tích / 10;//Chia lấy phần nguyên }
Ta sử dụng vòng lặp while để kiểm tra trong khi đến phần tử cuối cùng
mà nhớ có giá trị khác “0” ta sử dụng phần tử mảng tiếp theo để lưu giá trịnhớ đó
Sử dụng vòng lặp for() để cộng dồn kết quả sau khi nhận được kết quả
tích = s1[i]*s2[j] + nhớ;
tg[i+bậc] = tích%10;
nhớ = tích/10;
} ntg = n1+bậc;
while(nho) {
ntg++;
tg[ntg] = nhớ%10;