LẬP TRÌNH PHÂN tán
Trang 1TRƯỜNG ĐẠI HỌC CÔNG NGHIỆP TP.HỒ CHÍ MINH
KHOA CÔNG NGHỆ THÔNG TIN
TÍNH BIỂU THỨC SỐ LỚN
Tp.HCM, ngày 6
Trang 2MỤC LỤC
Lời nói đầu 3
1 Phân tích bài toán 4
1.1 Phân tích cấu trúc dữ liệu 4
1.1.1 Phép toán Cộng: 4
1.1.2 Phép toán trừ: 4
1.1.3 Phép nhân 5
1.1.4 Tổng kết class BigNum 6
1.2 Phân tích bài toán đa thức theo hướng phân tán 6
2 Thực thi 7
2.1 Class Interfacecalculator chứa các interface xử lý các phép toán Bignum 7
2.2 Class CalculatorImpl dùng để thực thi các phương thức trong class InterfaceCalculator 7
2.3 Class Server 13
2.4 Class Client 14
2.5 Thực thi chương trình 24
3 Các mặt hạn chế và hướng phát triển 27
3.1 Các mặt hạn chế 27
3.2 Hướng phát triển 27
Trang 3L ỜI NÓI ĐẦU
Trong thời đại hiện nay với sự phát triển ngày càng lớn mạnh của công nghệ thông tin thì nhucầu xử lí dữ liệu với những con số cực lớn (từ 10000 chữ số trở lên) đang rất cần thiết, đặc biệttrong các ngành khoa học như Toán học như tìm các số nguyên tố lớn, tìm giai thừa của một
số cực lớn, v.v nhưng việc tính toán các giá trị ấy hiện nay vẫn chưa được hỗ trợ, trong đókiểu Integer chỉ cho phép tính toán đến 232 (khoảng 9 chữ số) và kiểu Long cho phép tính toánđến 264 số (khoảng 18 chữ số) Vì vậy chúng ta cần phải tạo ra một chương trình có thể thỏamãn điều này nhầm tạo điều kiện cho sự phát triển của Công nghệ thông tin trên toàn thế giớicũng như các ngành khoa học khác
Mặc dù những bài toán với số lớn này hiện nay đã có cách giải tuy nhiên việc tính toán rấtphức tạp và rất mất thời gian, đặc biệt khi máy chủ được yêu cầu quá nhiều bài toán cùng mộtlúc, rất may thay với sự hỗ trợ của Lập trình theo hướng phân tán, ta có thể tạo nên một ứngdụng theo hướng phân tán giúp ta có thể giảm thiểu được giời gian xử lí bài toán cũng như cóthể tính toán đồng thời nhiều biểu thức cùng một lúc
Trang 41 P HÂN TÍCH BÀI TOÁN
1.1 PHÂN TÍCH CẤU TRÚC DỮ LIỆU.
Để giải quyết bài toán tính đa thức với các chữ số lớn này trước hết chúng ta cần xây dựngmột Class với các phương thức tính toán đơn giản bao gồm các phép tính Cộng, Trừ và Nhâncác số lớn
Như chúng ta đã biết các kiểu dữ liệu Integer và Long trong java không thể xử lí các phép tínhcủa các số có từ 18 chữ số trở lên nên chúng ta không thể lưu dữ liệu dưới dạng Integer hayLong được mà sẽ lưu với một dạng khác đó chính là kiểu String, ở dạng kiểu String chúng ta sẽ
có thể lưu thoải mái số lượng chữ số cần thiết Từ đây chúng ta sẽ chia các phép toán ra thànhtừng phần và xử lí chúng:
1.1.1 Phép toán Cộng:
Để cộng 2 chuỗi số với nhau chúng ta cần chia chuỗi này thành các chuỗi con mỗi chuỗi gồm
có 3 chữ số, ta chuyển kiểu chuỗi này sang kiểu Integer và lưu vào một mảng mới kiểu Integer theo thứ tự từ sau ra trước
Giả sử chúng ta cần tính tổng giá trị của 2 số: 7128793451 và 495674968
Trước hết chúng ta cần phải phân tích cả 2 số này trở về kiểu mảng Integer như đã nói ở trên, sau khi phân tích ra ta sẽ được 2 mảng sau:
{451, 793, 128, 7}
{968, 674, 495}
Ta sẽ lần lượt cộng theo thứ tự từ vị trí 0 đến n với n là chiều dài của mảng dài nhất, nếu có
dư ta sẽ dùng một biến để lưu số dư này lại rồi cộng dồn cho các giá trị sau
Trang 5Trước tiên ta vẫn phân tích 2 số này thành các mảng số nguyên như trên:
{451, 793, 128, 7}
{968, 674, 495}
Ta sẽ lần lượt trừ theo thứ tự từ 0 đến n với n là chiều dài của mảng dài nhất trong 2 mảng trên, nếu số trên nhỏ hơn số ở dưới chúng ta sẽ cộng cho số ở trên cho 1000 và trừ như bình thường như cần phải có một biến để lưu giá trị ta “mượn” này
Sau khi trừ ta sẽ được một mảng kết quả như sau:
{483, 118, 633, 6}
Cũng tương tự như phép cộng, ta chỉ đơn giản ghép các số này lại theo thứ tự từ sau ra trước để có một kết quả hoàn chỉnh: 6633118483
Chú ý: Nếu số hạng thứ nhất nhỏ hơn số hạng thứ 2 thì ta sẽ lấy số thứ 2 trừ cho số thứ nhất
và trong kết quả ta sẽ gán thêm một dấu trừ phía trước kết quả
1.1.3 Phép nhân.
Thông thường để thực hiện một phép nhân phức tạp chúng ta sẽ cộng lần lượt các số lại với nhau để cho ra kết quả cuối cùng, tuy nhiên phương pháp này sẽ mất rất nhiều thời gian và công sức Ví dụ nếu ta nhân 2 con số 7128793451 và 495674968 lại với nhau theo phương pháp này thì chúng ta phải thực hiện 495674968 lần phép cộng số 7128793451 vào kết quả hiện tại!! Rõ ràng thuật toán này sẽ tốn của chúng ta rất nhiều thời gian để xử lí cũng như bộ nhớ
Để thực hiện phép nhân hai số lớn ta sẽ không thực hiện theo phương pháp đã nêu ở trên
mà sẽ sử dụng một phương pháp khác sẽ được trình bày ở dưới đây:
Ta sẽ có kết quả sau:
T = {436568, 1071598, 881631, 485583, 68078, 3465}
Ta sẽ cộng dồn kết quả lại sao cho mỗi phần tử chỉ có 3 chữ số, nếu vượt quá 3 chữ số ta sẽ lưu lại và cộng cho phần tử tiếp theo, kết quả sẽ là:
Trang 61.2 PHÂN TÍCH BÀI TOÁN ĐA THỨC THEO HƯỚNG PHÂN TÁN.
Để giải một bài toán đa thức theo hướng phân tán trước hết chúng ta cần phải chia bài toán lớn ra thành các bài toán con và đưa các bài toán con này cho các máy khác xử lí
Ví dụ ta có bài toán nhỏ sau: 3*4+5*(7+8)
Ta thấy trong bước đầu tiền khi phân tích đa thức này sẽ tồn tại 2 bài toán con cần xử lí đầu tiên là 3 * 4 và 7 + 8 Ta sẽ đưa 2 bài toán con này cho các máy con khác xử lí vào được kết quả là tạo thành một đa thức mới: 12 + 5 * 15 Từ đây lại sinh ra thêm một bài toán con nữa chính là 5 * 15 Ta lại có một đa thức mới là 12 + 75 Tương tự cho đến khi đa thức này không còn phép tính nào cả thì ta sẽ được kết quả cuối cùng là 87
Để có thể phân tích một đa thức ra thành các đơn thức con như trình bày ở trên ta cần phải
sử dụng thuật toán Kí pháp Ba Lan để xử lí nó
Khi sử dụng thuật toán kí pháp Ba Lan cho một đa thức ta sẽ phân tích đa thức đó thành một mảng các chuỗi được sắp xếp theo độ ưu tiên của phép toán, ví dụ như chuỗi ở trên sẽ cho ra kết quả: 3 4 * 5 7 8 + *
Các phép toán nào gần 2 số liên tiếp sẽ được xử lí trước và cho ra kết quả mới Tương tự cho đến khi kết quả cuối cùng chỉ còn lại một số
Trang 8public String Plus(String a, String b) throws RemoteException{
boolean ketQuaAm = false;
if (a.charAt(0) == '-' && b.charAt(0) == '-') {
int count = A.length;
int[] plus = new int[count + 1];
for (int i = 0; i < count; i++) {
du += A[i] + B[i];
plus[i] = du % 1000;
Trang 9//Ham xu li phep toan tru
public String Subtract(String a, String b) throws RemoteException{
int du = 0;
boolean smaller = false;
if (a.length() < b.length() || (a.length() == b.length() && a.compareToIgnoreCase(b) < 0)) {
Trang 10int[] A = BigNum.convertToArray(a);
int[] B = BigNum.convertToArray(b);
int count = A.length;
int[] subtract = new int[count];
for (int i = 0; i < count; i++) {
//Ham xu li phep toan nhan
public String Multi(String a, String b) throws RemoteException{
boolean aAm = false;
boolean bAm = false;
Trang 11int countA = A.length;
int countB = B.length;
int[] multi = new int[countA + countB];
Arrays.fill(multi, 0);
for (int i = 0; i < countA; i++)
for (int j = 0; j < countB; j++)
Trang 12}
multi[countA + countB - 1] += du;
String answer = modify(multi);
if (aAm && bAm)
//Ham de chuyen mot chuoi thanh mang integer
public static int[] convertToArray(String a) {
int count = a.length() / 3;
int[] answer = new int[count];
int len = a.length() - 1;
Trang 13//Ham de chuyen mot mang integer sang chuoi
public static String modify(int[] A) {
String answer = "";
int count = A.length;
for (int i = count - 1; i >= 0; i ) {
String temp = Integer.toString(A[i]);
Trang 14LocateRegistry.createRegistry(1099);
CaculatorImpl cal=new CaculatorImpl();
System.out.println ("Server has started");
Naming.bind("rmi://localhost/cal",cal);
System.out.println ("Caculator Bound");
}catch(Exception e){
System.out.println ("Error: "+e);
}}
Trang 15@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated
Code">//GEN-BEGIN:initComponents
private void initComponents() {
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
btnCal = new javax.swing.JButton();
txtInput = new javax.swing.JTextField();
txtOutput = new javax.swing.JTextField();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jLabel1.setFont(new java.awt.Font("Tahoma", 1, 14)); // NOI18N jLabel1.setForeground(new java.awt.Color(204, 0, 51));
jLabel1.setText("Your expression here:");
jLabel2.setFont(new java.awt.Font("Tahoma", 1, 14)); // NOI18N jLabel2.setForeground(new java.awt.Color(0, 102, 102));
jLabel2.setText("The result is here:");
btnCal.setFont(new java.awt.Font("Tahoma", 1, 20)); // NOI18N btnCal.setForeground(new java.awt.Color(153, 153, 0));
btnCal.setText("Calculate");
btnCal.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) {
btnCalActionPerformed(evt);
}
});
Trang 16txtInput.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N
txtInput.addFocusListener(new java.awt.event.FocusAdapter() { public void focusGained(java.awt.event.FocusEvent evt) { txtInputFocusGained(evt);
}
});
txtOutput.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N
javax.swing.GroupLayout layout = new
addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
addGroup(layout.createSequentialGroup()
addGap(36, 36, 36)
addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
addComponent(jLabel1)
addComponent(jLabel2))
addGap(18, 18, 18)
addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
addComponent(txtInput)
addComponent(txtOutput,
javax.swing.GroupLayout.DEFAULT_SIZE, 451, Short.MAX_VALUE)))
Trang 17addGroup(layout.createSequentialGroup()
addGap(244, 244, 244)
addComponent(btnCal)))
addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE,Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) addGroup(layout.createSequentialGroup()
addGap(25, 25, 25)
addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
addGroup(layout.createSequentialGroup()
addGap(53, 53, 53)
addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
Short.MAX_VALUE)
addComponent(btnCal)
addGap(27, 27, 27))))
Trang 18// TODO add your handling code here:
char[] exp = txtInput.getText().toCharArray();
int count = exp.length;
String[] balanExpr = new String[10000];
char[] S = new char[10000];
int headBalan = 0;
int headS = 0;
String curNum = "";
/*Bat dau thuat toan Balan*/
for (char c : exp) {
Trang 20balanExpr[headBalan++] = Character.toString(S[headS 1]);
headS ;
}
/*Ket thuc thuat toan Ba lan*/
/*Xu ly tinh bieu thuc*/
while (headBalan != 1) {
String[] tempBalan = new String[headBalan];
int headTemp = 0;
String[] A = new String[headBalan];
String[] B = new String[headBalan];
String[] phepToan = new String[headBalan];
int[] vitri = new int[headBalan];
Trang 21/*Danh sach cac bai toan nho can giai*/
for (int i = 0; i < curCount; i++)
Trang 22tempBalan[curVitri] = num1;
//System.out.println (A[i]+"-"+B[i]+"=" +num1);
String num2;
num2=abc.Multi(A[i],B[i]);
tempBalan[curVitri] = num2;
// System.out.println (A[i]+"*"+B[i]+"=" +num2);
}
}
} catch(Exception e)
Trang 23/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(Client.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(Client.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(Client.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
Trang 24private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JTextField txtInput;
private javax.swing.JTextField txtOutput;
// End of variables declaration//GEN-END:variables
}
2.5 THỰC THI CHƯƠNG TRÌNH.
Bước 1: Khởi động Server.
Trang 25Bước 2: Chạy Client.
Giao diện chương trình:
Trang 26Tính số lớn:
Trang 273 C ÁC MẶT HẠN CHẾ VÀ HƯỚNG PHÁT TRIỂN
3.1 CÁC MẶT HẠN CHẾ.
Chương trình hiện tại vẫn còn thiếu phép toán Chia do khi xử lí chia không hết sẽ sinh
ra các số thập phân vô hạn, việc xử lí các con số này vô cùng phức tạp và tốn rất nhiều thời gian để xử lí nên chương trình hiện tại vẫn chưa có phép tính này
Bên cạnh đó các phép tính cơ bản khác được xây dựng từ phép chia như phép tính Mod vẫn chưa có mặt trong chương trình này
Ngoài ra việc phân chia xử lí các bài toán con cho các máy con vẫn chưa thật sự tối ưu, chương trình hiện tại chỉ có thể chỉ định từng phép toán cho từng máy, nghĩa là máy A chỉ toàn giải phép nhân, máy B chỉ toàn giải phép cộng và máy C chỉ giải các bài toán trừ Điều này sẽ không hiệu quả nếu trong một bài toán chỉ toàn các phép tính cộng hoặc trừ hoặc nhân
Cuối cùng là giao diện chương trình vẫn còn đơn giản, tương tác với người dùng kém
3.2 HƯỚNG PHÁT TRIỂN.
Chương trình sẽ có thêm các phép toán thông dụng khác như phép chia, phép Mod, phép giai thừa, v.v
Chương trình sẽ được cải tiến thêm để có thể xử lí nhanh hơn
Ở giai đoạn phân tán các đơn thức cho các bài toán con sẽ được tối ưu hơn nhằm sử dụng hiệu quả nguồn tài nguyên của các máy
Giao diện của chương trình sẽ được tinh chỉnh nhiều hơn nhầm tạo ra sự thuận lợi cho người dùng