首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

四則混合運算表達式遞歸計算函數第二版(支援函數與負數)

     編輯:關於C++

功能特性

  • 支援四則混合運算(+、-、*、/)
  • 支援括號巢狀:()、[]、{} 自動統一
  • 支援 int() 取整與 round() 四捨五入函數
  • 支援負數運算元(如 *-3、+-5)
  • 錯誤檢測:除零、運算元缺失、括號不匹配、函數語法錯誤

核心演算法邏輯

  1. 預處理:移除空格、統一括號、小寫轉換
  2. 遞歸處理括號:由內而外計算最內層括號內表達式
  3. 處理 round 函數:解析 round(值, 位數),以 floor(x * 10^n + 0.5) / 10^n 實現
  4. 處理 int 函數:直接 floor(值)
  5. 處理乘除序列:左結合,支援負數運算元,透過 IsMinus 標記處理連續符號
  6. 處理加減序列:最後處理剩餘加減,同樣支援負數

完整原始碼

#include <math.h>
#pragma warn -8060

AnsiString __fastcall Calc(String sExp)
{
    int posL, pos, posR, posM;
    String sTmp, sL, sR;
    bool IsMinus;
    
    sExp = sExp.LowerCase();
    if (sExp.AnsiPos("error")) return sExp;
    while (pos = sExp.AnsiPos(" ")) sExp = sExp.Delete(pos, 1);
    if (sExp.IsEmpty()) return "0";
    
    // 統一括號
    while ((pos = sExp.AnsiPos("[")) > 0 || (pos = sExp.AnsiPos("{")) > 0)
        sExp = sExp.SubString(1, pos-1) + "(" + sExp.SubString(pos+1, sExp.Length());
    while ((pos = sExp.AnsiPos("]")) > 0 || (pos = sExp.AnsiPos("}")) > 0)
        sExp = sExp.SubString(1, pos-1) + ")" + sExp.SubString(pos+1, sExp.Length());
    
    // 處理 round()
    while (pos = sExp.AnsiPos("round(")) {
        posL = pos + 5;
        while (posM = sExp.SubString(posL+1, sExp.Length()).AnsiPos("round("))
            posL = posL + posM + 5;
        for (posM = posL+2; !sExp.IsDelimiter(",", posM) && posM <= sExp.Length(); posM++);
        if (posM == 0) return "error:round沒有配對的逗號, 公式錯!";
        for (posR = posM+2; !sExp.IsDelimiter(")", posR) && posR <= sExp.Length(); posR++);
        sExp = sExp.SubString(1, posL-6)
            + floor(Calc(sExp.SubString(posL+1, posM-posL-1)).ToDouble() * 
                    pow(10, sExp.SubString(posM+1, posR-posM-1).ToDouble()) + 0.5) 
            / pow(10, sExp.SubString(posM+1, posR-posM-1).ToDouble())
            + sExp.SubString(posR+1, sExp.Length());
    }
    
    // 遞歸處理括號
    while (posL = sExp.LastDelimiter("(")) {
        sTmp = sExp.SubString(posL+1, sExp.Length());
        posR = sTmp.AnsiPos(")");
        if (posR == 0) return "error:沒有配對的), 公式錯!";
        sExp = sExp.SubString(1, posL-1) + Calc(sTmp.SubString(1, posR-1)) + sTmp.SubString(posR+1, sTmp.Length());
    }
    
    // 處理 int()
    while (pos = sExp.AnsiPos("int")) {
        posL = pos + 2;
        for (posR = posL+2; !sExp.IsDelimiter("+-*/", posR) && posR <= sExp.Length(); posR++);
        sExp = sExp.SubString(1, pos-1) + floor(sExp.SubString(posL+1, posR-posL-1).ToDouble()) + sExp.SubString(posR, sExp.Length());
    }
    
    // 處理 */ 序列
    IsMinus = false;
    while (sExp.LastDelimiter("*/")) {
        for (pos = 1; !sExp.IsDelimiter("*/", pos) && pos <= sExp.Length(); pos++);
        if (pos == 1 || pos == sExp.Length()) return "error:首或尾字符是*/運算符, 公式錯!";
        posL = sExp.SubString(1, pos-1).LastDelimiter("+-");
    Minus0:
        for (posR = pos+1; !sExp.IsDelimiter("+-*/", posR) && posR <= sExp.Length(); posR++);
        if (posR == (pos+1) && sExp.IsDelimiter("*/", posR)) return "error:*/運算符相鄰, 公式錯!";
        if (posR == sExp.Length()) return "error:尾字符是+-*/運算符, 公式錯!";
        if (sExp.SubString(pos, 2) == "*-" || sExp.SubString(pos, 2) == "/-") {
            sExp.Delete(pos+1, 1); IsMinus = !IsMinus; goto Minus0;
        }
        sL = sExp.SubString(posL+1, pos-posL-1);
        sR = sExp.SubString(pos+1, posR-pos-1);
        if (sExp.IsDelimiter("/", pos) && sR == "0") return "error:除數為零,無意義!";
        sExp = (posL == 0 ? "" : sExp.SubString(1, posL)) 
            + (sExp.IsDelimiter("*", pos) ? (sL.ToDouble()*sR.ToDouble()) : (sL.ToDouble()/sR.ToDouble()))
            + sExp.SubString(posR, sExp.Length());
    }
    if (IsMinus) sExp = "-" + sExp;
    
    // 處理 +- 序列
    IsMinus = false;
    while (sExp.LastDelimiter("+-")) {
        for (pos = 2; !sExp.IsDelimiter("+-", pos) && pos <= sExp.Length(); pos++);
        if (pos == sExp.Length()) return "error:尾字符是+-運算符,公式錯!";
        if (pos > sExp.Length()) return sExp;
    Minus1:
        for (posR = pos+1; !sExp.IsDelimiter("+-", posR) && posR <= sExp.Length(); posR++);
        if (posR == sExp.Length()) return "error:尾字符是+-運算符,公式錯!";
        if (sExp.SubString(pos, 2) == "+-" || sExp.SubString(pos, 2) == "--") {
            sExp.Delete(pos+1, 1); IsMinus = !IsMinus; goto Minus1;
        }
        sL = sExp.SubString(1, pos-1);
        sR = sExp.SubString(pos+1, posR-pos-1);
        sExp = String(sExp.IsDelimiter("+", pos) ? 
            (sL.ToDouble() + sR.ToDouble() * (IsMinus ? -1 : 1)) :
            (sL.ToDouble() - sR.ToDouble() * (IsMinus ? -1 : 1)))
            + sExp.SubString(posR, sExp.Length());
    }
    return sExp;
}

使用範例

Calc("3 + 5 * 2")           // 13
Calc("round(3.14159, 2)")   // 3.14
Calc("int(-3.7)")           // -4
Calc("(-3) * (-4) + 5")     // 17
Calc("2 * -3 + 4")          // -2
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved