Tải bản đầy đủ (.docx) (18 trang)

Báo cáo tìm hiểu các thuật toán thực hiện trên số lớn như phép toán cộng, trừ, nhân, chia 2 số nguyên lớn

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (304.75 KB, 18 trang )

BÀI TẬP NHÓM
CHỦ ĐỀ: CÀI ĐẶT THƯ VIỆN SỐ LỚN
(Tìm hiểu các thuật toán thực hiện trên số lớn như phép toán
cộng, trừ, nhân, chia 2 số nguyên lớn).
Giáo viên: HÀ THỊ THANH
THÀNH VIÊN NHÓM
1. Vũ Văn Hậu
2. Lê Mạnh Cường,
3. Hoàng Trọng Quỳnh
4. Lê Văn Trường
5. Nguyễn Hoàng Chung
MỤC LỤC
LỜI MỞ ĐẦU
Tuy rằng trong cuộc sống và công việc bình thường chúng ta chỉ có nhu cầu
tính toán với các số đến hàng tỷ (9 chữ số) hay đến tỷ tỷ (18 chữ số) với phần thập
phân cũng chỉ cần chính xác đến 4,5 số là đã nhiều, nhưng trong một số nghành
khoa học đòi hỏi sự chính xác cao như khoa học nguyên tử, vũ trụ, thì nhu cầu
tính toán với những con số lớn hơn nữa với phần thập phân có khi cần chính xác
đến vài chục chữ số sau dấu phẩy là hoàn toàn cần thiết. Hoặc đơn giản hơn nó chỉ
là một đề bài tập hay bài kiểm tra trong lớp học công nghệ thông tin của chúng ta.
Tư tưởng của thuật toán này là không sử dụng những kiểu dữ liệu số sẵn có
của C#, vì tất cả các kiểu dữ liệu này đều bị giới hạn. Thay vào đó, ta sử dụng kiểu
dữ liệu string, sử dụng các hàm xử lý chuỗi để nó có thể tính toán theo đúng những
nguyên tắc cộng trừ nhân chia số học.
Nhóm chúng em sau một thời gian tìm hiểu và đã xây dựng một chương
trình tính toán đơn giản các số nguyên lớn trên (C#) với nhiều chữ số. Kết quả đã
được test trên nhiều thiết bị máy tính khác, như máy tính của windows đều cho kết
quả rất chính xác.
Phần 1:
THAO TÁC CỘNG
1.1 THUẬT TOÁN


Thông thường, khi cộng hai số có nhiều chữ số, chúng ta thực hiện từ phải
qua trái. Với mỗi lần cộng, kết quả của nó còn được cộng với giá trị nhớ của lần
trước đó và đồng thời cũng xác định giá trị nhớ mới. Ở đây, vì các số được lưu
theo chiều ngược lại nên chúng ta thực hiện từ trái qua phải, tức là từ đầu đến cuối
xâu.
Giả sử chúng ta có một số nguyên (lớn) a=32145; sẽ có rất nhiều cách lưu trữ số
nguyên này (do ta quy định), ở đây ta sẽ đưa ra cách lưu số này qua mảng 1 chiều
ngược, cụ thể như sau: a[0]=5, a[1]=4, a[2]=1, a[3]=2 và a[4]=3; nhưng khi xuất
thì lại xuất ngược lại so với cách lưu trữ!, số nguyên này có 5 chữ số, khi nhập
(input) số này vào chương trình thì chúng ta sẽ dùng dấu khoảng trắng (space) để
ngăn cách các chữ số và nhập bình thường theo thứ tự thông thường, ví dụ
a=32145 sẽ được nhập vào như sau: 3 2 1 4 5.
Vậy nếu cần thực hiện phép toán Cộng hai số a và b sau đó lưu vào mảng c (kết
quả) thì ta đề xuất các bước (c=a+b)
1.2 CÁC BƯỚC THỰC HIỆN
- Bước 1: Loại bỏ các chữ số 0 vô nghĩa ở 2 mảng a và b.
- Bước 2: Thêm chữ số 0 ở đầu mảng có độ dài ngắn hơn để 2 mảng có cùng độ dài
(tức là nếu a=1234, b=21 thì chúng ta thấy: mảng b có 2 phần tử; mảng a có 4 phần
tử; vậy để hai mảng này có số phần tử bằng nhau thì chúng ta thêm 2 chữ số 0 nữa
vào mảng b; lúc này b=0021).
- Dùng một biến nhớ, để lưu trữ số nhớ sau mỗi bước tính. Ta lưu giá trị vào một
mảng INT đã được khởi tạo có giá trị là 0.
Bước 3: Đảo ngược chuỗi và tính toán.
Bước 4: Xuất kết quả ta đảo ngược chuỗi kết quả.
THEO CÁC BƯỚC Ở TRÊN TRƯƠNG TRÌNH THỰC HIỆN CỘNG SẼ
CÓ CODE NHƯ SAU:
//hàm cộng 2 số nguyên cực lớn
#region addInt()
public string addInt(string strNum1, string strNum2)
{

//B1:tìm ra chuỗi ngắn hơn và thêm số 0 vào chuỗi cho đủ.
if(strNum1.Length > strNum2.Length)
strNum2 = strNum2.PadLeft(strNum1.Length, '0');
else if(strNum2.Length > strNum1.Length)
strNum1 = strNum1.PadLeft(strNum2.Length, '0');
//Bước 2: đưa vào mảng int int[], thực hiên chuyển đổi các sô về thành dạng
int32 để tiện cho việc tính toán nếu số quá lớn
int[] arrNum1 = new int[strNum1.Length];
int[] arrNum2 = new int[strNum2.Length];
for(int i=0; i<strNum1.Length; i++)
{
arrNum1[i] = Convert.ToInt32(strNum1.Substring(i,1));
}
for(int i=0; i<strNum2.Length; i++)
{
arrNum2[i] = Convert.ToInt32(strNum2.Substring(i,1));
}
//Bước 3: Đảo ngược chuỗi và tính toán.
Array.Reverse(arrNum1);
Array.Reverse(arrNum2);
// Tính toán.
int[] arrResult = new int[strNum1.Length+1];
int phanbu = 0;
for(int i=0; i<strNum1.Length; i++)
{
arrResult[i] = arrNum1[i] + arrNum2[i] + phanbu;
if(arrResult[i] >= 10)
{
arrResult[i] -= 10;
phanbu = 1;

}
else
phanbu = 0;
}
if(phanbu==1)
arrResult[arrResult.Length-1] = 1;
//Đảo ngược chuỗi kết quả và hiển thị kết quả trên màn hình.
Array.Reverse(arrResult);
StringBuilder strbd = new StringBuilder(arrResult.Length);
foreach(int i in arrResult)
strbd.Append(i);
string strResult = "";
if(phanbu==1)
strResult = strbd.ToString();
else if(phanbu==0)
strResult = strbd.ToString().Substring(1);
return strResult;
}
#endregion
PHẦN 2
PHÉP TRỪ SỐ NGUYÊN LỚN
2.1 Giải thuật trừ:
Giống như cộng, chúng ta cũng thực hiện từ phải qua trái. Với mỗi lần trừ,
đề phòng chữ số của số bị trừ nhỏ hơn nên ta cứ vay tạm một chục. Nếu lần trước
đã vay rồi thì lần này phải trừ đi. Nhưng chỉ đáng vay nếu kết quả sau khi trừ là bé
hơn 10, còn lớn hơn 10 là không phải vay. Dưới đây ta xem rằng a >= b.
2.2 Về chương trình.
Vì là phép trừ nên khi tính toán ta cần phải nhận biết số trừ và số bị trừ, sẽ có một
hàm so sánh như sau:
//1. Tim so lon hon

for(int i=0; i<strNum1.Length; i++)
{
if(arrNum1[i] > arrNum2[i])
{
strNumBig = strNum1;
break;
}
else if(arrNum1[i] < arrNum2[i])
{
strNumBig = strNum2;
break;
}
}
if(strNumBig == "")
{
txtResult.Text = "0"
else //neu 2 so ko bang nhau
{
if(strNumBig == strNum1)
strNumSmall = strNum2;
else
strNumSmall = strNum1;
Sau đó đưa phần các phần tử vào mảng INT[]
//Dua vao mang int[]
int[] arrNumBig = new int[strNumBig.Length];
int[] arrNumSmall = new int[strNumSmall.Length];
for(int i=0; i<strNumBig.Length; i++)
{
arrNumBig[i] = Convert.ToInt32(strNumBig.Substring(i,1));
}

for(int i=0; i<strNumSmall.Length; i++)
{
arrNumSmall[i] = Convert.ToInt32(strNumSmall.Substring(i,1));
}
Cuối cùng là đảo ngược chuỗi , tính toán và cho kết quả ra màn hình:
//Dao nguoc chuoi
Array.Reverse(arrNumBig);
Array.Reverse(arrNumSmall);
//so mu~ cua 10 chinh la chi so phan tu trong mang int[]
int[] arrResult = new int[strNumBig.Length];
int phanbu = 0;
for(int i=0; i<strNumBig.Length; i++)
{
arrNumSmall[i] = arrNumSmall[i] + phanbu;
if(arrNumBig[i] >= arrNumSmall[i])
{
arrResult[i] = arrNumBig[i] - arrNumSmall[i];
phanbu = 0;
}
else
{
arrResult[i] = arrNumBig[i]+10 - arrNumSmall[i];
phanbu = 1;
}
}
//Dao nguoc chuoi Result
Array.Reverse(arrResult);
StringBuilder strbd = new StringBuilder(arrResult.Length);
foreach(int i in arrResult)
strbd.Append(i);

Phần 3
PHÉP NHÂN 2 SỐ LỚN
3.1 Giải thuật nhân:
Thông thường, khi nhân a với b, chúng ta thực hiện từ phải qua trái. Mỗi lần
sẽ nhân một chữ số của b với số a và đặt kết quả dịch sang trái 1 chữ số. Nhưng
trong mỗi lần đó chúng ta lại lần lượt nhân từng chữ số của a với chữ số nói trên
của b. Cũng như phép cộng, kết quả cũng phụ thuộc việc nhớ của lần nhân trước và
xác định giá trị nhớ mới. Việc nhận này được thực hiện từ trái qua phải đó.
3.2 Tương tự như phép cộng ta có đoạn chương trình sau:
// nhập các số để tiến hành nhân.
#region Phep nhan
private void btnMul_Click(object sender, System.EventArgs e)
{
if(!checkInput())
{
MessageBox.Show("Input Number is not valid");
txtNumber1.Focus();
}
else
{
//Phep nhan 2 so nguyen
string strNum1 = strTempN1[0];
string strNum2 = strTempN2[0];
//Dua vao mang int[]
int[] arrNum2 = new int[strNum2.Length];
for(int i=0; i<strNum2.Length; i++)
{
arrNum2[i] = Convert.ToInt32(strNum2.Substring(i,1));
}
//mang string luu tru cac so hang

string[] arrstr = new string[strNum2.Length];
int x = 0;
for(int i=strNum2.Length-1; i>=0; i )
{
arrstr[x] = Mul(strNum1, arrNum2[i]);
//them so 0 o cuoi chuoi
arrstr[x] = arrstr[x].PadRight(arrstr[x].Length + x, '0');
x++;
}
//cong cac so hang nguyen bang ham addInt() voi nhau
string strResult = "";
for(int i=0; i<arrstr.Length; i++)
{
strResult = addInt(strResult, arrstr[i]);
}
}
#endregion
Phần 4
PHÉP CHIA 2 SỐ LỚN
4.1 Giải thuật chia:
Thông thường, khi chia a với b, chúng ta thực hiện từ trái qua phải. Lần đầu
tiên lấy nhóm có số chữ số bằng số chữ số của b, các lần sau đó chỉ lần lượt hạ một
số xuống phần dư. Thay vì nhẩm xem được mấy lần, ở đây chỉ việc thử lần lượt từ
0 đến có thể. Vì chúng ta lưu ngược nên ta thực hiện từ phải qua trái. Hàm sau thực
hiện chia a cho b, đặt kết quả vào c và phần dư.
4.2 Về chương trình ta có như sau:
//Phep chia btnDiv_Click
#region Phep chia
private void btnDiv_Click(object sender, System.EventArgs e)
{

if(!checkInput())
{
MessageBox.Show("Input Number is not valid");
txtNumber1.Focus();
}
else
{
string strNum1 = txtNumber1.Text;
string strNum2 = txtNumber2.Text;
// Thuc hien phep chia nhu chia 2 so nguyen
if(strNum1 == strNum2)
{
txtResult.Text = "1";
}
else //khi 2 so ko bang nhau
{
string strResult = "";
//neu so bi chia (strNum1) lon hon
if(NumBigger(strNum1, strNum2) == strNum1)
{
string strtemp = strNum1.Substring(0, strNum2.Length);
string strBookmark = strtemp;
string phandu="";
bool flag = true;
while(phandu != "0" || strtemp != "00")
{
//ket qua co toi da 80 chu so (tinh ca dau .)
//result: max 80 char
if(strResult.Length == 80)
break;

string[] arrKetqua = DivInt(strtemp, strNum2).Split(
new char[]{'~'});
strResult += arrKetqua[0];
phandu = arrKetqua[1];
// MessageBox.Show("~"+arrKetqua[0]+"~"+arrKetqua[1]+"~");
if(strBookmark.Length < strNum1.Length) //van con so de ha
{
strBookmark = strNum1.Substring(0, strBookmark.Length+1);
//ha so xuong de tiep tuc chia
strtemp = phandu + strNum1.Substring(strBookmark.Length-1,1);
if(strtemp.IndexOf('0')==0) //Ex: 0.34/0.03
strtemp = strtemp.Substring(1);
}
else if(strBookmark.Length == strNum1.Length) //het so de ha
{
if(flag == true)
{
strResult += ".";
flag = false;
}
//them 0 vao sau phan du de tiep tuc chia
strtemp = phandu + "0";
//neu da them 0 ma strtemp van nho hon so bi chia
if(NumBigger(strtemp, strNum2) == strNum2)
{
// strResult += "0";
strtemp = phandu + "0";
}
//neu so chia lon hon
else if(NumBigger(strNum1, strNum2) == strNum2)

{
strResult = "0.0";
while(NumBigger(strNum1, strNum2) == strNum2)
{
strNum1 += "0";
strResult += "0";
}
bool flag = true;
if(strNum1.Length > strNum2.Length)
{
flag = false;
}
strResult = strResult.Substring(0, strResult.Length-2);
//Thuc hien tuong tu phan tren ===============
string strtemp = strNum1.Substring(0, strNum2.Length);
string strBookmark = strtemp;
string phandu="";
while(phandu != "0")
{
//ket qua co toi da 40 chu so (tinh ca dau .)
if(strResult.Length == 40)
break;
string[] arrKetqua = DivInt(strtemp, strNum2).Split(
new char[]{'~'});
strResult += arrKetqua[0];
phandu = arrKetqua[1];
if(strBookmark.Length < strNum1.Length) //van con so de ha
{
strBookmark = strNum1.Substring(0, strBookmark.Length+1);
//ha so xuong de tiep tuc chia

strtemp = phandu + strNum1.Substring(strBookmark.Length-1,1);
}
else if(strBookmark.Length == strNum1.Length) //het so de ha
{
//them 0 vao sau phan du de tiep tuc chia
strtemp = phandu + "0";
//neu da them 0 ma strtemp van nho hon so bi chia
if(NumBigger(strtemp, strNum2) == strNum2)
{
// strResult += "0";
strtemp = phandu + "0";
}
}
if(flag == false)
{
strResult = "0." + strResult.Substring(3);
}
}
//neu co dau . o cuoi thi bo di
if(strResult.IndexOf('.') == strResult.Length-1)
strResult = strResult.Substring(0, strResult.Length-1);
txtResult.Text = strResult;
// txtResult.Text = "~"+strNum1 +"~"+ strNum2 +"~" + strResult;
}
#endregion
PHẦN 5
MỘT SỐ HÀM BỔ TRỢ
Trong quá trình tính toán các số lớn khá phức tạp, vậy để đơn giản
hơn trong quá trình tính toán, ta kết hợp một số hàm bổ trợ để trong
những chương trình con chúng ta có thể sử dụng chúng để tính toán.

5.1 Hàm bỏ tất cả các số 0 ở đầu 1 chuỗi số nguyên.
//Ham bo tat ca cac so 0 o dau 1 chuoi so nguyen
#region MyRemove()
public string MyRemove(string strnum)
{
char[] ch = strnum.ToCharArray();
int n=0;
for(int i=0;i<ch.Length; i++)
{
if(ch[i] == '0')
n++;
else
break;
}
return strnum.Substring(n);
}
#endregion
5.2 Hàm lấy về chuỗi số lớn hơn trong 2 chuỗi
//Ham lay ve chuoi so lon hon trong 2 chuoi, = nhau thi tra ve ""
#region NumBigger() - so nguyen
private string NumBigger(string strNum1, string strNum2)
{
string strNumBig = "";
if(strNum1.Length > strNum2.Length)
{
strNumBig = strNum1;
strNum2 = strNum2.PadLeft(strNum1.Length, '0');
}
else if(strNum2.Length > strNum1.Length)
{

strNumBig = strNum2;
strNum1 = strNum1.PadLeft(strNum2.Length, '0');
}
else if(strNum1.Length == strNum2.Length)
{
int[] arrNum1 = new int[strNum1.Length];
int[] arrNum2 = new int[strNum2.Length];
for(int i=0; i<strNum1.Length; i++)
{
arrNum1[i] = Convert.ToInt32(strNum1.Substring(i,1));
}
for(int i=0; i<strNum2.Length; i++)
{
arrNum2[i] = Convert.ToInt32(strNum2.Substring(i,1));
}
for(int i=0; i<strNum1.Length; i++)
{
if(arrNum1[i] > arrNum2[i])
{
strNumBig = strNum1;
break;
}
else if(arrNum1[i] < arrNum2[i])
{
strNumBig = strNum2;
break;
}
}
}
return strNumBig;

}
#endregion
5.3 Hàm chuyển số thập phân thành số nguyên
//ham chuyen so thap phan thanh so nguyen
//va lay ve vi tri dau . tu ben phai sang
#region myConvert()
public string myConvert(string strnum)
{
string numpos = ""; //return dang 645437~4 hoac 849~0 (so~vitridau.)
if(strnum.IndexOf('.') < 0)
numpos = strnum + "~0";
else if(strnum.IndexOf('.') > 0)
{
string temp1 = strnum.Substring(0, strnum.IndexOf('.'));
string temp2 = strnum.Substring(strnum.IndexOf('.')+1);
numpos = temp1 + temp2 + "~" + temp2.Length.ToString();
}
return numpos;
}
#endregion
5.4 Hàm kiểm tra đầu vào.
#region kiem_tra_dau_vao()
public bool kiemtradauvao()
{
bool flag = true;
string strNum1 = txtNumber1.Text;
string strNum2 = txtNumber2.Text;
Regex regexDou1 = new Regex(@"^[1-9]+[0-9]*\.{0,1}[0-9]*[1-9]+$");
Regex regexDou2 = new Regex(@"^0{1}\.[0-9]*[1-9]+$");
Regex regexInt = new Regex(@"^[1-9]{1}[0-9]*$");

Match m1 = regexInt.Match(strNum1);
Match m2 = regexInt.Match(strNum2);
Match m3 = regexDou1.Match(strNum1);
Match m4 = regexDou1.Match(strNum2);
Match m5 = regexDou2.Match(strNum1);
Match m6 = regexDou2.Match(strNum2);
if((!m1.Success && !m3.Success && !m5.Success) ||
(!m2.Success && !m4.Success && !m6.Success))
flag = false;
return flag;
}
#endregion
PHẦN 6
GIỚI THIỆU VỀ CHƯƠNG TRÌNH
1. Giao diện chính của trương trình
2. Cách sử dụng:
Nhập số thứ nhất, số thứ 2 sau đó ấn các phép tính cộng trừ nhân chia, kết quả sẽ
hiển thị ra phần textbox kết quả ở dưới.
Yêu cầu phải nhập đúng chữ số.
LỜI KẾT
Như vậy nhóm em đã giới thiệu song về tìm hiểu các tháo tác phép toán với
số nguyên lớn, trong qua trình tìm hiểu không tránh khỏi sai sót mong các bạn và
thầy cô đóng góp ý kiến, để cho nhóm có thể hoàn thành tốt bài thảo luận này.
EM XIN CHÂN THÀNH CÁM ƠN!

×