posts - 27,  comments - 0,  trackbacks - 0
          周末,看關于專家系統方面的書,其中有關于規則方面的內容,忽然就想,能不能模仿人的學習方式來提升計算機程序的計算能力呢?

          試想,一個小孩子,他一開始什么也不會,首先,你要告訴他什么是數字,然后告訴他什么是加、減;然后告訴他什么是乘、除,還要告訴他有乘、除要先計算乘除,然后又引入了括號說,有括號永遠要先計算括號。如此,隨著告訴他的技能越多,他的解題能力也就越強。
          于是就想著試驗一下。
          第一步,教計算機學習什么是數字。
          下面的正則表達式,就是告訴“孩子”,數字就是前面可能有“-”號,當然也可能沒有,接下來連續的數字0-9,組成的數字,后面可能還會有小數點開始加一堆0-9的數字,當然沒有也沒有關系。如此,它就算懂得認數字了。

          1. public final class MathNumber { 
          2.     private MathNumber() { 
          3.     } 
          4.   
          5.     public static String numberPattern = "[-]?[0-9]+([.][0-9]*)?"
          6.     public static Pattern pattern = Pattern.compile(numberPattern); 
          7.   
          8.     public static Matcher match(String string) { 
          9.         Matcher match = pattern.matcher(string); 
          10.         if (match.find()) { 
          11.             return match; 
          12.         } 
          13.         throw new RuntimeException(string + " is not a number."); 
          14.     } 

          第二步就是告訴“孩子”,計算數學題的過程。
          如果兩邊有空格就忽略它,然后呢,看看是不是已經是一個數字了,如果已經是一個數字,那說明就算出結果了。如果不是,就從最高優先級找起,如果找就就計算。如果找不到,說明這個式子有問題,不是一個合法的數學式子。

          1. public static String eval(String string) { 
          2.         string = string.trim(); 
          3.         while (!isMathNumber(string)) {// 同一優先級的哪個先找到算哪個 
          4.             System.out.println("求解算式:" + string); 
          5.             boolean found = false
          6.             for (MathInterface math : mathList) { 
          7.                 Matcher matcher = math.match(string); 
          8.                 if (matcher.find()) { 
          9.   
          10.                     String exp = matcher.group(); 
          11.                     String sig = ""
          12.                     if (exp.charAt(0) == '-' && matcher.start() != 0) {// 如果不是第一個數字,-號只能當運算符 
          13.                         sig = "+"
          14.                     } 
          15.                     System.out.println("發現算式:" + exp); 
          16.                     String evalResult = math.eval(exp); 
          17.                     string = string.substring(0, matcher.start()) + sig 
          18.                             + evalResult + string.substring(matcher.end()); 
          19.                     System.out.println(exp + "計算結果為:" + evalResult + ",代回原式"); 
          20.                     found = true
          21.                     break
          22.                 } 
          23.             } 
          24.             if (!found) { 
          25.                 throw new RuntimeException(string + " 不是合法的數學表達式"); 
          26.             } 
          27.         } 
          28.         return string; 
          29.     } 


          從現在開始,這孩子已經會解題思路了,不過他還是啥也不懂,他還不知道啥是加,減、乘、除啥的,沒有辦法,孩子笨,只要多教他了。
          下面就教他如何計算,加、減、乘、除、余、括號、指數。

          1. addMathExpression(new Add()); 
          2. addMathExpression(new Subtract()); 
          3. addMathExpression(new Multiply()); 
          4. addMathExpression(new Devide()); 
          5. addMathExpression(new Minus()); 
          6. addMathExpression(new Factorial()); 
          7. addMathExpression(new Remainder()); 
          8. addMathExpression(new Bracket()); 
          9. addMathExpression(new Power()); 
          10. Collections.sort(mathList, new MathComparator()); 


          由于大同小異,就里就只貼出來加法和括號的實現方式。
          加法實現,它的優先級是1,它是由兩個數字中間加一個“+”號構成,數字和加號前面的空格沒用,不用管它。計算的時候呢,就是用加的方式把兩個數字加起來,這一點計算機比人強,呵呵,告訴他怎么加永遠不會錯的。而且理解起加減乘除先天有優勢。

          1. public class Add implements MathInterface { 
          2.     static String plusPattern = BLANK + MathNumber.numberPattern + BLANK 
          3.             + "[+]{1}" + BLANK + MathNumber.numberPattern + BLANK; 
          4.     static Pattern pattern = Pattern.compile(plusPattern); 
          5.     static Pattern plus = Pattern.compile(BLANK + "\\+"); 
          6.   
          7.     @Override 
          8.     public Matcher match(String string) { 
          9.         return pattern.matcher(string); 
          10.     } 
          11.   
          12.     @Override 
          13.     public int priority() { 
          14.         return 1
          15.     } 
          16.   
          17.     @Override 
          18.     public String eval(String expression) { 
          19.         Matcher a = MathNumber.pattern.matcher(expression); 
          20.         if (a.find()) { 
          21.             expression = expression.substring(a.end()); 
          22.         } 
          23.         Matcher p = plus.matcher(expression); 
          24.         if (p.find()) { 
          25.             expression = expression.substring(p.end()); 
          26.         } 
          27.         Matcher b = MathNumber.pattern.matcher(expression); 
          28.         if (b.find()) { 
          29.   
          30.         } 
          31.         return new BigDecimal(a.group()).add(new BigDecimal(b.group())) 
          32.                 .toString(); 
          33.     } 
          34.   


          接下來是括號,括號的優先級是最大啦,只要有它就應該先計算。當然,要先計算最內層的括號中的內容。括號中的內容,計算的時候,可以先拉出來,不用管外面的內容,計算好了,放回去就可以了。

          1. public class Bracket implements MathInterface { 
          2.   
          3.     static String bracketPattern = BLANK + "[(]{1}[^(]*?[)]" + BLANK; 
          4.     static Pattern pattern = Pattern.compile(bracketPattern); 
          5.   
          6.     @Override 
          7.     public Matcher match(String string) { 
          8.         return pattern.matcher(string); 
          9.     } 
          10.   
          11.     @Override 
          12.     public int priority() { 
          13.         return Integer.MAX_VALUE; 
          14.     } 
          15.   
          16.     @Override 
          17.     public String eval(String expression) { 
          18.         expression = expression.trim(); 
          19.         return MathEvaluation.eval(expression.substring(1
          20.                 expression.length() - 1)); 
          21.     } 
          22.   


          到目前為止,我們的程序“寶寶”已經學會數學計算了,出個題讓伊試試。

          1. public static void main(String[] args) { 
          2. String string = "1+2^(4/2)+5%2"
          3. System.out.println("結果是 :" + MathEvaluation.eval(string)); 


          程序寶寶的做題過程如下:

          1. 求解算式:1+2^(4/2)+5%2 
          2. 發現算式:(4/2
          3. 求解算式:4/2 
          4. 發現算式:4/2 
          5. 4/2計算結果為:2.00,代回原式 
          6. (4/2)計算結果為:2.00,代回原式 
          7. 求解算式:1+2^2.00+5%2 
          8. 發現算式:2^2.00 
          9. 2^2.00計算結果為:4,代回原式 
          10. 求解算式:1+4+5%2 
          11. 發現算式:5%2 
          12. 5%2計算結果為:1,代回原式 
          13. 求解算式:1+4+1 
          14. 發現算式:1+4 
          15. 1+4計算結果為:5,代回原式 
          16. 求解算式:5+1 
          17. 發現算式:5+1 
          18. 5+1計算結果為:6,代回原式 
          19. 結果是 :6 


          呵呵,程序寶寶的做題過程和人的做題過程非常一致,而且程序實現也非常簡單易懂。神馬編譯原理,神馬中綴表達式都用不上。(執行效率與其它算法比較不一定高,僅用于驗證通過規則讓程序的處理能力增強,由于沒有進行深入測試,正則表達式和程序邏輯是否寫得嚴密沒有經過深入驗證)

          其實程序雖然很簡單,但是,實際上已經是一個簡單的規則引擎的雛形。
          首先,他加載了許多的業務處理規則,加,減,乘,除,插號,指數,余數等等。
          第二,他的業務規則是可以不斷進行擴展的。
          第三,只要給出事實,最后,他通過規則的不斷應用,最后會導出結果,要么是正確的結果,要么說給出的事實是錯誤的。

          需要源碼的童鞋請到GIT上直接獲取代碼。

          git地址:http://git.oschina.net/tinyframework/mathexp.git


          點擊右上角的watch、star、fork,變成unwatch、unstar、unfork(如果Tiny項目沒有fork到用戶空間的話,后面clone命令會出錯),以支持Tiny框架發展!


          歡迎訪問開源技術社區:http://bbs.tinygroup.org。本例涉及的代碼和框架資料,將會在社區分享?!蹲约簞邮謱懣蚣堋烦蓡TQQ群:228977971,讓我們一起動手,了解開源框架的奧秘!

          posted on 2015-06-23 22:14 柏然 閱讀(63) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2015年6月>
          31123456
          78910111213
          14151617181920
          21222324252627
          2829301234
          567891011

          常用鏈接

          留言簿

          隨筆檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 阿荣旗| 兰西县| 资兴市| 祁阳县| 遵义市| 海门市| 马龙县| 山西省| 新津县| 曲水县| 观塘区| 墨玉县| 桐乡市| 嵊州市| 龙口市| 绥宁县| 汕尾市| 临沂市| 扬州市| 平和县| 太湖县| 敖汉旗| 五原县| 夏河县| 内黄县| 南通市| 同德县| 广水市| 磴口县| 大渡口区| 潜山县| 巴楚县| 连州市| 泾源县| 苏州市| 长顺县| 湄潭县| 酉阳| 塘沽区| 嘉祥县| 宣威市|