解決double型別資料四則運算精度丟失問題
阿新 • • 發佈:2021-02-08
技術標籤:程式碼
直接對double型別的資料進行計算,很容易發生精度丟失問題
使用BigDecimal類計算,可以避免精度丟失
//Double num2 = Double.parseDouble(numStack.pop());
//Double num1 = Double.parseDouble(numStack.pop());
BigDecimal num2 = new BigDecimal(numStack.pop());
BigDecimal num1 = new BigDecimal( numStack.pop());
if(arrays[i].equals("+")){
BigDecimal result = num1.add(num2);
numStack.push(result.toString());
}
else if(arrays[i].equals("-")){
BigDecimal result = num1.subtract (num2);
numStack.push(result.toString());
}
else if(arrays[i].equals("*")){
BigDecimal result = num1.multiply(num2);
numStack.push(result.toString());
}
else if(arrays[i] .equals("/")){
BigDecimal result = num1.divide(num2);
numStack.push(result.toString());
}
為了完成多個數據的組合運算,這裡使用棧對運算子和運算數進行管理
設計一個存放字串物件的棧類
public class Stack {
private ArrayList<String> stack = new ArrayList<>();
public boolean isEmpty(){
return stack.size() == 0;
}
public int getSize(){
return stack.size();
}
public String peek(){
if(!isEmpty()) {
return stack.get(stack.size() -1 );
}
else {
return "false";
}
}
public String pop(){
if(!isEmpty()){
String top = stack.get(stack.size() - 1);
stack.remove(stack.size() - 1);
return top;
}
else{
return "false";
}
}
public void push(String o){
stack.add(o);
}
@Override
public String toString(){
return "Stack:" + stack.toString();
}
}
計算類
public class Compute {
public static void main(String[] args){
Scanner input = new Scanner(System.in);
String str = input.nextLine();
String[] inOrderArrays = strToArrays(str);
System.out.println(Arrays.toString(inOrderArrays));
String[] postOrderArrays = toPostOrder(inOrderArrays);
System.out.println(Arrays.toString(inOrderArrays));
BigDecimal result = toCompute(postOrderArrays);
System.out.println(result);
}
/*
將字串分割成運算元和操作符的字串陣列
*/
public static String[] strToArrays(String str){
int strLength = str.length();
int beginIndex = 0; int endIndex = 0;
String[] Arrays = new String[strLength];
int arraysIndex = 0;
for(int i = 0; i < strLength; i++){
if(str.charAt(i)=='*'||str.charAt(i)=='/'||str.charAt(i)=='+'||str.charAt(i)=='-'||str.charAt(i)=='('||str.charAt(i)==')'){
endIndex = i -1 ;
if(beginIndex <= endIndex ){
Arrays[arraysIndex] = str.substring(beginIndex, endIndex+1);
Arrays[arraysIndex + 1] = String.valueOf(str.charAt(i));
arraysIndex += 2;
beginIndex = i + 1;
}
else{
Arrays[arraysIndex] = String.valueOf(str.charAt(i));
arraysIndex += 1;
beginIndex = i + 1;
}
}
}
Arrays[arraysIndex] = str.substring(beginIndex, str.length());
String[] Arrays2 = new String[arraysIndex+1];
for(int i = 0; i < arraysIndex+1; i++) {
Arrays2[i] = Arrays[i];
}
return Arrays2;
}
/*
將中綴表示式轉為字尾表示式,返回的是字串陣列
*/
public static String[] toPostOrder(String[] arrays){
/*規則:
*1,運算數直接輸出
*2,左括號壓入堆疊
*3,右括號 將棧頂的運算子彈出並輸出,括號出棧不輸出
*4,運算子:
* 若優先順序大於棧頂運算子,壓入棧
* 若優先順序小於或等於棧頂運算子,棧頂運算子彈出並輸出,
* 繼續和新棧頂比較,直到比棧頂運算子優先順序大,將它壓入棧
*5,物件處理完畢後,將棧中運算子彈出並輸出
*/
Stack operStack = new Stack();//建立了一個操作符的棧
int arraysLength = arrays.length;
String[] arrays2 = new String[arraysLength];//輸出後的字元陣列
int tempIndex = 0;
//將字串陣列遍歷
for(int i = 0; i < arraysLength; i++){
//操作符入棧
if(isOper(arrays[i])){
//棧為空時直接入棧
if(operStack.isEmpty()){
operStack.push(arrays[i]);
}
else{
//操作符為"("時直接入棧
if( arrays[i].equals("(") ){
operStack.push(arrays[i]);
}
//操作符為")"時棧頂出棧並輸出,直到遇到"(", "("出棧,")"不入棧
else if( arrays[i].equals(")") ){
while(operStack.peek().equals("(") == false ){
arrays2[tempIndex] = operStack.pop();
tempIndex += 1;
}
operStack.pop();//"("出棧
}
//其他操作符需要比較與棧頂的優先順序
else{
//棧頂是"(", 直接入棧
if(operStack.peek().equals("(") ){
operStack.push(arrays[i]);
}
else{
//優先順序高,直接入棧
if(getPriority(arrays[i].charAt(0)) > getPriority(operStack.peek().charAt(0))
&& operStack.isEmpty() == false ){
operStack.push(arrays[i]);
}
//優先順序低或者相等,棧頂出棧並輸出,直到優先順序比棧頂高
else{
while(getPriority(arrays[i].charAt(0)) <= getPriority(operStack.peek().charAt(0))
&& operStack.isEmpty() == false){
arrays2[tempIndex] = operStack.pop();
tempIndex += 1;
//若棧頂全部彈出,則直接入棧
if(operStack.isEmpty()) {
operStack.push(arrays[i]);
break;
}
}
if(getPriority(arrays[i].charAt(0)) > getPriority(operStack.peek().charAt(0))){
operStack.push(arrays[i]);
}
}
}
}
}
}
//運算元直接新增到 字串陣列2
else if(isNum(arrays[i])){
arrays2[tempIndex] = arrays[i];
tempIndex += 1;
}
else{
}
}
while(!operStack.isEmpty()){
arrays2[tempIndex] = operStack.pop();
tempIndex += 1;
}
String[] arrays3 = new String[tempIndex];
for(int i = 0; i < tempIndex ;i++){
arrays3[i] = arrays2[i];
}
return arrays3;
}
/*
得到操作符的優先順序
*/
public static int getPriority(char c){
if(c == '*' || c == '/'){
return 2;
}
else if (c == '+' || c == '-'){
return 1;
}
else{
return 999;
}
}
/*
由字尾表示式計算得值
*/
public static BigDecimal toCompute(String[] arrays){
/*規則:
*中綴表示式不用比較優先順序
*將運算數入棧,每讀到一個運算子
*就彈出棧頂的兩個運算數,運算完畢後將結果壓入棧
*/
Stack numStack = new Stack();//建立了一個運算元的棧
int arraysLength = arrays.length;
//遍歷字尾表示式的字串陣列
for(int i = 0; i < arraysLength; i++){
if(isNum(arrays[i])){
numStack.push(arrays[i]);
}
else if(isOper(arrays[i])){
//Double num2 = Double.parseDouble(numStack.pop());
//Double num1 = Double.parseDouble(numStack.pop());
BigDecimal num2 = new BigDecimal(numStack.pop());
BigDecimal num1 = new BigDecimal(numStack.pop());
if(arrays[i].equals("+")){
BigDecimal result = num1.add(num2);
numStack.push(result.toString());
}
else if(arrays[i].equals("-")){
BigDecimal result = num1.subtract(num2);
numStack.push(result.toString());
}
else if(arrays[i].equals("*")){
BigDecimal result = num1.multiply(num2);
numStack.push(result.toString());
}
else if(arrays[i].equals("/")){
BigDecimal result = num1.divide(num2);
numStack.push(result.toString());
}
else{
}
}
else{
}
}
//Double result = Double.parseDouble(numStack.pop());
BigDecimal result = new BigDecimal(numStack.pop());
return result;
}
/*
判斷該字串是否為操作符
*/
public static boolean isOper(String str){
if(str.equals("*")||str.equals("/")||
str.equals("+")||str.equals("-")||
str.equals("(")||str.equals(")")){
return true;
}
else{
return false;
}
}
/*
判斷該字串是否為運算元
*/
public static boolean isNum(String str){
if(str.equals("*")||str.equals("/")||
str.equals("+")||str.equals("-")||
str.equals("(")||str.equals(")")){
return false;
}
else{
return true;
}
}
}