鍍金池/ 教程/ Java/ 教計算機程序解數(shù)學題
分布式鎖的簡單實現(xiàn)
關(guān)于框架體系與戰(zhàn)術(shù)的思考
開源與中小型軟件公司的未來趨勢
生態(tài)圈的建立
用200行的DBF解析器來展示良好架構(gòu)設(shè)計
緣起
業(yè)務流程引擎設(shè)計
軟件開發(fā)雜談
高屋建瓴,理念先行
借船下海還是造船下海
Web界面快速開發(fā)實踐
教計算機程序解數(shù)學題
量身定制規(guī)則引擎,適應多變業(yè)務場景
緩存相關(guān)代碼的演變
理想的開源框架與設(shè)計原則
框架2.0的設(shè)計梳理
與屈原對話及開源精神

教計算機程序解數(shù)學題

周末,看關(guān)于專家系統(tǒng)方面的書,其中有關(guān)于規(guī)則方面的內(nèi)容,忽然就想,能不能模仿人的學習方式來提升計算機程序的計算能力呢?

試想,一個小孩子,他一開始什么也不會,首先,你要告訴他什么是數(shù)字,然后告訴他什么是加、減;然后告訴他什么是乘、除,還要告訴他有乘、除要先計算乘除,然后又引入了括號說,有括號永遠要先計算括號。如此,隨著告訴他的技能越多,他的解題能力也就越強。
于是就想著試驗一下。

第一步,教計算機學習什么是數(shù)字。

下面的正則表達式,就是告訴“孩子”,數(shù)字就是前面可能有“-”號,當然也可能沒有,接下來連續(xù)的數(shù)字0-9,組成的數(shù)字,后面可能還會有小數(shù)點開始加一堆0-9的數(shù)字,當然沒有也沒有關(guān)系。如此,它就算懂得認數(shù)字了。

public final class MathNumber {  
    private MathNumber() {  
    }  

    public static String numberPattern = "[-]?[0-9]+([.][0-9]*)?";  
    public static Pattern pattern = Pattern.compile(numberPattern);  

    public static Matcher match(String string) {  
        Matcher match = pattern.matcher(string);  
        if (match.find()) {  
            return match;  
        }  
        throw new RuntimeException(string + " is not a number.");  
    }  
}  

第二步就是告訴“孩子”,計算數(shù)學題的過程。

如果兩邊有空格就忽略它,然后呢,看看是不是已經(jīng)是一個數(shù)字了,如果已經(jīng)是一個數(shù)字,那說明就算出結(jié)果了。如果不是,就從最高優(yōu)先級找起,如果找就就計算。如果找不到,說明這個式子有問題,不是一個合法的數(shù)學式子。

public static String eval(String string) {  
        string = string.trim();  
        while (!isMathNumber(string)) {// 同一優(yōu)先級的哪個先找到算哪個  
            System.out.println("求解算式:" + string);  
            boolean found = false;  
            for (MathInterface math : mathList) {  
                Matcher matcher = math.match(string);  
                if (matcher.find()) {  

                    String exp = matcher.group();  
                    String sig = "";  
                    if (exp.charAt(0) == '-' && matcher.start() != 0) {// 如果不是第一個數(shù)字,-號只能當運算符  
                        sig = "+";  
                    }  
                    System.out.println("發(fā)現(xiàn)算式:" + exp);  
                    String evalResult = math.eval(exp);  
                    string = string.substring(0, matcher.start()) + sig  
                            + evalResult + string.substring(matcher.end());  
                    System.out.println(exp + "計算結(jié)果為:" + evalResult + ",代回原式");  
                    found = true;  
                    break;  
                }  
            }  
            if (!found) {  
                throw new RuntimeException(string + " 不是合法的數(shù)學表達式");  
            }  
        }  
        return string;  
    }  

從現(xiàn)在開始,這孩子已經(jīng)會解題思路了,不過他還是啥也不懂,他還不知道啥是加,減、乘、除啥的,沒有辦法,孩子笨,只要多教他了。

下面就教他如何計算,加、減、乘、除、余、括號、指數(shù)。

addMathExpression(new Add());  
 addMathExpression(new Subtract());  
 addMathExpression(new Multiply());  
 addMathExpression(new Devide());  
 addMathExpression(new Minus());  
 addMathExpression(new Factorial());  
 addMathExpression(new Remainder());  
 addMathExpression(new Bracket());  
 addMathExpression(new Power());  
 Collections.sort(mathList, new MathComparator());  

由于大同小異,就里就只貼出來加法和括號的實現(xiàn)方式。

加法實現(xiàn),它的優(yōu)先級是1,它是由兩個數(shù)字中間加一個“+”號構(gòu)成,數(shù)字和加號前面的空格沒用,不用管它。計算的時候呢,就是用加的方式把兩個數(shù)字加起來,這一點計算機比人強,呵呵,告訴他怎么加永遠不會錯的。而且理解起加減乘除先天有優(yōu)勢。

public class Add implements MathInterface {  
    static String plusPattern = BLANK + MathNumber.numberPattern + BLANK  
            + "[+]{1}" + BLANK + MathNumber.numberPattern + BLANK;  
    static Pattern pattern = Pattern.compile(plusPattern);  
    static Pattern plus = Pattern.compile(BLANK + "\\+");  

    @Override  
    public Matcher match(String string) {  
        return pattern.matcher(string);  
    }  

    @Override  
    public int priority() {  
        return 1;  
    }  

    @Override  
    public String eval(String expression) {  
        Matcher a = MathNumber.pattern.matcher(expression);  
        if (a.find()) {  
            expression = expression.substring(a.end());  
        }  
        Matcher p = plus.matcher(expression);  
        if (p.find()) {  
            expression = expression.substring(p.end());  
        }  
        Matcher b = MathNumber.pattern.matcher(expression);  
        if (b.find()) {  

        }  
        return new BigDecimal(a.group()).add(new BigDecimal(b.group()))  
                .toString();  
    }  

}  

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

public class Bracket implements MathInterface {  

    static String bracketPattern = BLANK + "[(]{1}[^(]*?[)]" + BLANK;  
    static Pattern pattern = Pattern.compile(bracketPattern);  

    @Override  
    public Matcher match(String string) {  
        return pattern.matcher(string);  
    }  

    @Override  
    public int priority() {  
        return Integer.MAX_VALUE;  
    }  

    @Override  
    public String eval(String expression) {  
        expression = expression.trim();  
        return MathEvaluation.eval(expression.substring(1,  
                expression.length() - 1));  
    }  

}  

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

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

程序?qū)殞毜淖鲱}過程如下:

求解算式:1+2^(4/2)+5%2  
發(fā)現(xiàn)算式:(4/2)  
求解算式:4/2  
發(fā)現(xiàn)算式:4/2  
4/2計算結(jié)果為:2.00,代回原式  
(4/2)計算結(jié)果為:2.00,代回原式  
求解算式:1+2^2.00+5%2  
發(fā)現(xiàn)算式:2^2.00  
2^2.00計算結(jié)果為:4,代回原式  
求解算式:1+4+5%2  
發(fā)現(xiàn)算式:5%2  
5%2計算結(jié)果為:1,代回原式  
求解算式:1+4+1  
發(fā)現(xiàn)算式:1+4  
1+4計算結(jié)果為:5,代回原式  
求解算式:5+1  
發(fā)現(xiàn)算式:5+1  
5+1計算結(jié)果為:6,代回原式  
結(jié)果是 :6  

呵呵,程序?qū)殞毜淖鲱}過程和人的做題過程非常一致,而且程序?qū)崿F(xiàn)也非常簡單易懂。神馬編譯原理,神馬中綴表達式都用不上。(執(zhí)行效率與其它算法比較不一定高,僅用于驗證通過規(guī)則讓程序的處理能力增強,由于沒有進行深入測試,正則表達式和程序邏輯是否寫得嚴密沒有經(jīng)過深入驗證)

其實程序雖然很簡單,但是,實際上已經(jīng)是一個簡單的規(guī)則引擎的雛形。
首先,他加載了許多的業(yè)務處理規(guī)則,加,減,乘,除,插號,指數(shù),余數(shù)等等。

第二,他的業(yè)務規(guī)則是可以不斷進行擴展的。
第三,只要給出事實,最后,他通過規(guī)則的不斷應用,最后會導出結(jié)果,要么是正確的結(jié)果,要么說給出的事實是錯誤的。

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

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