1. 程式人生 > >科學計算器(windows標準)—C++&Java

科學計算器(windows標準)—C++&Java

模擬Windows系統自帶的標準計算器

完成功能:

         多位數(小數預設最多保留4位小數)加減乘除、括號、取反、退格、CE清空數字、C重置——鍵盤輸入或滑鼠點選都可

         開方、求倒未實現(擴充套件很容易),M系按鍵未實現(不知道幹嘛用的)

         若還存在輸入bug,請評論指出=.=,我來修改

執行效果:

實現方式:

    計算器核心:

1、表示式儲存->

Vector<String>:使用一個動態的字串陣列來儲存中綴表示式,為什麼不用字串呢,如果你以前寫過計算器或者看過別人寫的程式碼,大多數人寫的要麼只支援一位數的運算,要麼存在很多bug,為什麼有這些問題,因為把表示式當成一個字串的話,數與數之間,數與運算子之間,以及數的檢測是個讓人很頭疼的問題,所以這裡才用字串陣列,比如你的表示式是(15+2)*3,那麼這個字串陣列應該是{“(”,“15”,“+”,“2”,“)”,“*”,“3”},這樣就避免了很多問題

2、表示式轉換(中綴->字尾)->trans()函式:使用庫中的棧(Stack,Java和C++都有)來進行轉換,為什麼要轉換成字尾表示式呢?是因為電腦並不能識別運算的優先順序(比如先乘除後加減)、而後綴表示式就是通過比較優先順序將得到的,所以計算機如果拿到了字尾表示式,就可以之間運算。

3、表示式運算->counter()函式得到了表示式之後就很容易了,逐個出棧進行運算就行了,但要注意的是除法運算除數不為0;

      圖形介面:

            使用javaFx做的介面,細節沒什麼好說的。

C++:https://blog.csdn.net/qq_40946921/article/details/83353033

           無圖形介面,只支援一位數運算,可擴充套件,因為java的計算器核心程式碼其實就是從C++這搬過去的,可以看一下java程式碼的資料型別和counter,trans函式,很容易就能得到C++版本的程式碼。

Java:

import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
import javax.xml.soap.Text;
import java.lang.reflect.Array;
import java.text.DecimalFormat;
import java.util.*;
public class Calculate extends Application{
    Vector<String> m_exp=new Vector<>(),p_exp=new Vector<>();  //m_exp[]為中綴表示式字串陣列,p_exp[]為字尾
    GridPane pane =new GridPane();  //網格佈局面板
    Pane box=new Pane();            //顯示面板
    double result=0;    //運算結果

    //number表示當前數,exp為表示式
    Label number=new Label("0"),exp=new Label();

    //按鈕
    Button num[]=new Button[11],operator[]=new Button[4],other[]=new Button[13];

    //按鈕text
    String op[]={"+","-","*","/"},ot[]={"MC","MR","MS","M+","M-","←","CE","C","±","√","%","1/x","="},out;

    boolean shift=false,lastIsNumber=false,havePut=true,couldBack=false;

    //面板
    public void loadPane(){
        //建立10個數字鍵及小數點按鈕並繫結事件
        for(int i=0;i<11;i++){
            String tmp;
            if(i<10)
                tmp=String.valueOf(i);
            else
                tmp=".";
            num[i]=new Button(tmp);
            num[i].setMinSize(30,26);
            num[i].setOnMouseClicked(e->putNum(tmp));
        }

        //建立4個運算子按鍵
        for(int i=0;i<4;i++){
            String tmp=op[i];
            operator[i]=new Button(tmp);
            operator[i].setMinSize(30,26);
            operator[i].setOnMouseClicked(e->{
                putExp(tmp);
            });
        }


        for(int i=0;i<13;i++){
            String tmp=ot[i];
            other[i]=new Button(tmp);
            other[i].setFont(Font.font(9));
            other[i].setMinSize(30,26);
        }

        //other鍵佈局
        for(int i=2;i<4;i++)
            for(int j=0;j<5;j++)
                pane.add(other[(i-2)*5+j],j,i);
        pane.add(other[10],4,4);
        pane.add(other[11],4,5);
        other[12].setMinSize(30,58);
        pane.add(other[12],4,6,1,2);

        //數字鍵佈局
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                pane.add(num[(2-i)*3+j+1],j,i+4);
        pane.add(num[0],0,7,2,1);
        num[0].setMinSize(66,26);
        pane.add(num[10],2,7);

        //4個運算子鍵佈局
        for(int i=0;i<4;i++)
            pane.add(operator[i],3,7-i);

        pane.setPadding(new Insets(15,15,0,15));
        pane.add(box,0,0,6,2);
        pane.setHgap(6);
        pane.setVgap(6);
        pane.setBackground(new Background(new BackgroundFill(Color.rgb(217,228,242),null,null)));       //設定面板背景色
        exp.setMinWidth(170);
        exp.setAlignment(Pos.BASELINE_RIGHT);
        exp.setLayoutY(5);
        number.setFont(Font.font("Arial", FontWeight.BOLD, FontPosture.REGULAR,10));
        number.setMinWidth(170);
        number.setMinHeight(30);
        number.setFont(Font.font("微軟雅黑", FontWeight.BOLD, FontPosture.REGULAR,20));        //設定顯示數字格式
        number.setLayoutY(20);
        number.setAlignment(Pos.BASELINE_RIGHT);

        Rectangle rectangle =new Rectangle(0,0,173,50);
        rectangle.setFill(Color.WHITE);
        rectangle.setStroke(Color.BLACK);
        rectangle.setStrokeWidth(0.1);
        box.getChildren().add(rectangle);
        box.getChildren().add(number);
        box.getChildren().add(exp);

    }
    //按鍵事件
    public void loadKey(){
        pane.setOnKeyPressed(e->{
            if(e.getCode()== KeyCode.SHIFT)
                shift=true;
            if(shift){
                if(e.getCode()==KeyCode.DIGIT9) {
                    m_exp.add("(");
                    exp.setText(exp.getText()+"(");
                }
                else if(e.getCode()==KeyCode.DIGIT0) {
                    if(havePut==false)
                        m_exp.add(number.getText());
                    m_exp.add(")");
                    lastIsNumber=false;
                    havePut=true;
                    exp.setText(getExp());
                }
            }
            else{
                switch(e.getCode()){
                    case DIGIT0:case NUMPAD0: putNum("0"); break;
                    case DIGIT1:case NUMPAD1: putNum("1"); break;
                    case DIGIT2:case NUMPAD2: putNum("2"); break;
                    case DIGIT3:case NUMPAD3: putNum("3"); break;
                    case DIGIT4:case NUMPAD4: putNum("4"); break;
                    case DIGIT5:case NUMPAD5: putNum("5"); break;
                    case DIGIT6:case NUMPAD6: putNum("6"); break;
                    case DIGIT7:case NUMPAD7: putNum("7"); break;
                    case DIGIT8:case NUMPAD8: putNum("8"); break;
                    case DIGIT9:case NUMPAD9: putNum("9"); break;
                    case BACK_SPACE:
                        if(number.getText().length()>1)
                            number.setText(number.getText().substring(0,number.getText().length()-1));
                        else{
                            number.setText("0");
                            lastIsNumber=true;
                        }
                        havePut=false;
                        break;

                    case ADD:putExp("+");break;
                    case SUBTRACT:putExp("-");break;
                    case MULTIPLY:putExp("*");break;
                    case DIVIDE:putExp("/"); break;
                    case EQUALS:case ENTER:
                        exp.setText("");
                        if(havePut==false)
                            m_exp.add(number.getText());
                        trans();
                        if(counter()==0)
                            number.setText(String.valueOf(result));
                        else
                            number.setText("除數不能為0");
                        havePut=true;
                        lastIsNumber=true;
                        m_exp.clear();
                        break;
                }
            }
        });
        pane.setOnKeyReleased(e->{if(e.getCode()== KeyCode.SHIFT)
            shift=false;});
    }

    //事件
    public void loadAction(){
        other[5].setOnMouseClicked(e->{
            if(couldBack) {
                if (number.getText().length() > 1)
                    number.setText(number.getText().substring(0, number.getText().length() - 1));
                else {
                    number.setText("0");
                    lastIsNumber = true;
                }
                havePut = false;
            }
        });
        other[6].setOnMouseClicked(e->{number.setText("0");});
        other[7].setOnMouseClicked(e->{m_exp.clear();result=0;havePut=false;lastIsNumber=false;number.setText("0");exp.setText("");});
        other[8].setOnMouseClicked(e->{
            if(number.getText().charAt(0)=='-')
                number.setText(number.getText().substring(1,number.getText().length()));
            else
                number.setText("-"+number.getText());
            havePut=false;
            couldBack=true;
        });
        other[12].setOnMouseClicked(e->{
            exp.setText("");
            if(havePut==false)
                m_exp.add(number.getText());
            trans();
            if(counter()==0)
                number.setText(String.valueOf(result));
            else {
                number.setText("除數不能為0");
                couldBack = false;
            }
            havePut=true;
            lastIsNumber=true;
            m_exp.clear();
        });
    }

    //輸入數字
    public void putNum(String str){
            if(havePut||number.getText().equals("0")||(havePut&&number.getText().length()>12))
                if(str.equals("."))
                    number.setText(number.getText()+str);
                else
                    number.setText(str);
            else if(number.getText().length()<=12)
                number.setText(number.getText()+str);
            lastIsNumber=true;
            havePut=false;
            couldBack=true;
    }

    //輸入符號
    public void putExp(String str){
        if(lastIsNumber){
            m_exp.add(number.getText());
            trans();
            if(counter()==0) {
                number.setText(String.valueOf(result));
            }
            else {
                number.setText("除數不能為0");
                couldBack=false;
            }

            m_exp.add(str);;
        }
        else if(m_exp.lastElement().equals("(")||m_exp.lastElement().equals(")")){
            m_exp.add(str);
        }
        else {
            m_exp.remove(m_exp.size() - 1);
            m_exp.add(str);
        }

        lastIsNumber=false;
        havePut=true;
        exp.setText(getExp());
    }

    //退格
    public void putBracket(String str){
        if(lastIsNumber){
            m_exp.add(str);
            lastIsNumber=false;
            havePut=true;
            exp.setText(getExp());
        }
    }

    //計算
    int counter(){
        double a,b;
        Stack<Double> stack=new Stack<>();
        for(int i=0;i<p_exp.size();i++){
            if(p_exp.get(i).charAt(0)>='0'&&p_exp.get(i).charAt(0)<='9'||p_exp.get(i).length()>1){
                stack.push(Double.valueOf(p_exp.get(i)));
            }
            else{
                switch (p_exp.get(i)) {
                    case "+":
                        a = stack.pop();
                        b = stack.pop();
                        stack.push(a+b);
                        break;
                    case "*":
                        a = stack.pop();
                        b = stack.pop();
                        stack.push(a*b);
                        break;
                    case "-":
                        a = stack.pop();
                        b = stack.pop();
                        stack.push(b-a);
                        break;
                    case "/":
                        a = stack.pop();
                        b = stack.pop();
                        if(a==0)
                            return 1;
                        stack.push(b/a);
                        break;
                }

            }
        }
        if(stack.size()!=1)
            return 1;
        DecimalFormat df = new DecimalFormat("#.0000");
        result=Double.valueOf(df.format(stack.peek()));
        if(String.valueOf(result).length()>12){
            result=(double)((int)(result/Math.pow(10,String.valueOf(result).length()-12))*Math.pow(10,String.valueOf(result).length()-12));
        }
        return 0;
    }

    Vector<String> trans(){
        p_exp.clear();
        Stack<String> stack=new Stack<>();
        String operators=new String("+-*/(");
        for (int i = 0; i < m_exp.size(); i++) {
            if (operators.indexOf(m_exp.get(i).charAt(0)) != -1&&m_exp.get(i).length()==1) {      //出現操作符
                if (m_exp.get(i).charAt(0) == '(')         //棧中新增左括號
                    stack.push(m_exp.get(i));
                else {                      //操作符的優先順序判斷
                    while ((!stack.empty()) && (priority(m_exp.get(i).charAt(0)) <= priority(stack.peek().charAt(0)))) {    //當棧不為空時,進行優先順序判斷
                        p_exp.add(stack.pop());   //若當前操作符優先順序低於棧頂,彈出棧頂,放到字尾式中
                    }
                    stack.push(m_exp.get(i));
                }
            }
            else if (m_exp.get(i).charAt(0) == ')') {            //出現右括號時,將棧中元素一直彈出,直至彈出左括號
                while (stack.peek().charAt(0) != '(') {
                    p_exp.add(stack.pop());
                }
                stack.pop();                       //彈出左括號
            }
            else {           //把運算元加入到字尾式中
                p_exp.add(m_exp.get(i));
            }
        }
        while (!stack.empty()) {    //將棧中剩餘操作符放到字尾式中
            p_exp.add(stack.pop());
        }
        return p_exp;
    }
    //獲取表示式
    String getExp(){
        out=new String();
        for(int j =0;j<m_exp.size();j++){
            out+=m_exp.get(j);
            if(j!=m_exp.size()-1)
                out+=" ";
        }
        if(out.length()>25)
            out="<"+out.substring(out.length()-25);
        return out;
    }

    //獲取運算子優先順序
    int priority(char ch){
        if (ch == '*'||ch=='/')
            return 2;
        if (ch == '+'||ch=='-')
            return 1;
        if (ch == '(')
            return -1;
        return 0;
    }

    public void start(Stage stage){
        loadPane();
        loadAction();
        loadKey();
        Scene scene=new Scene(pane,195,260);
        stage.setScene(scene);
        stage.setResizable(false);
        stage.setTitle("計算器—Italink");
        stage.show();
    }
}