科學計算器(windows標準)—C++&Java
阿新 • • 發佈:2018-12-11
模擬Windows系統自帶的標準計算器
完成功能:
多位數(小數預設最多保留4位小數)加減乘除、括號、取反、退格、CE清空數字、C重置——鍵盤輸入或滑鼠點選都可
開方、求倒未實現(擴充套件很容易),M系按鍵未實現(不知道幹嘛用的)
若還存在輸入bug,請評論指出=.=,我來修改
執行效果:
實現方式:
計算器核心:
1、表示式儲存->
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();
}
}