Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //////////////// КЛАСС MAIN //////////////////////
- package lab;
- import java.util.Scanner;
- /*Основной класс программы.*/
- public class Main {
- public static void main(String[] args) {
- try {
- // Создаётся объект сканнера для считывания переменных.
- Scanner sc = new Scanner(System.in);
- // Считываем выражение.
- String line = sc.nextLine();
- // Сохраняем выражение для вывода в конце.
- String lineCopy = new String(line);
- // Добавляем ноль в конец, чтобы избежать ошибок.
- line = line+"+0";
- // Создаём объект калькулятора для подсчёта значения выражения.
- Calculator calc = new Calculator();
- // Заменяем значение всех ф-ций в строке на численные значения.
- line = calc.countFunctions(line);
- // Подсчитываем значение выражения.
- calc.calculate(line);
- // Выводим значение выражения.
- System.out.println(lineCopy+" = "+calc.popVal());
- } catch (Exception ex)
- {
- // По стечению обстоятельств, ф-ция будет работать всегда
- // если строка введена корректно. В иных случаях
- // она и не должна работать.
- System.out.println("Ошибка при вычислениях/вводе данных. ");
- }
- }
- }
- //////////////// КЛАСС CUSTOMSTACK //////////////////////
- /* Класс для стека строк. (Понадобится в классе Calculator при подсчёте значений функций.) */
- package lab;
- public class CustomStack
- {
- String[] stack = new String[200];
- int ptr = 0;
- // Добавление элемента в стек.
- public void push(String par)
- {
- stack[ptr++]=par;
- }
- // Ф-ция возвращает элемент с вершины стека. Элемент удаляется из стека.
- public String pop()
- {
- return stack[--ptr];
- }
- // Просмотр элемента в вершине стека.
- public String peek()
- {
- return stack[ptr-1];
- }
- // Проверка стека на пустоту.
- public boolean isEmpty()
- {
- return (ptr==0);
- }
- }
- //////////////// КЛАСС CALCULATOR //////////////////////
- /*Класс содержит основные функции для работы с введённым выражением.*/
- package lab;
- import java.util.HashMap;
- import java.util.Scanner;
- public class Calculator {
- // в HashMap сохраняются значения конкретных переменных.
- public static HashMap<String, Double> variables = new HashMap<String, Double>();
- String Lex[]; // Массив содержит элементы введённого выражения. Например для выражения
- // "1+10+z" массив будет содержать Lex[0] = "1", Lex[1] = "+", Lex[2]="10", Lex[3]="+", Lex[4] = "z"
- int ptrL; // Указатель для работы с массивом Lex[].
- String opStack[]; // Стек для сохранения операторов.
- int ptrOp; // Указатель стека (индекс текущего элемента, с которым работаем.)
- String valStack[]; // Стек для подсчёта значений.
- int ptrVal; // Указатель стека значений.
- // Функция инициализации стеков.
- public void Init()
- {
- opStack=new String[200];
- ptrOp=0;
- valStack=new String[200];
- ptrVal=0;
- }
- // Определение приоритета операций.
- public int Prty(String o)
- {
- int r=-1;
- switch (o)
- {
- case "(":
- r=0;
- break;
- case "+":
- case "-":
- r=1;
- break;
- case "*":
- case "/":
- r=2;
- break;
- case "^":
- r=3;
- }
- return r;
- }
- // Функция для работы со стеком. Возвращает элемент в "верхушке" стека.
- public String peekOp()
- {
- return opStack[ptrOp-1];
- }
- // Проверка стека операторов на пустоту.
- public boolean isEmptyOp()
- {
- return (ptrOp==0);
- }
- // Проверка стека значений на пустоту
- public boolean isEmptyVal()
- {
- return (ptrVal==0);
- }
- // Поместить в стек операторов значение.
- public void pushOp(String op)
- {
- opStack[ptrOp++]=op;
- }
- // Аналогично ф-ции выше
- public void pushVal(String v)
- {
- valStack[ptrVal++]=v;
- }
- // Вернуть значение вверху стека и изменить значение указателя.
- public String popOp()
- {
- return opStack[--ptrOp];
- }
- public String popVal()
- {
- return valStack[--ptrVal];
- }
- // Ф-ция получает два значения из стека значений и выполняет операцию, полученную из
- // стека операций. Возвращаемое значение заносится обратно в стек значений.
- public void exec()
- {
- double a1,a2,r;
- String v1,v2;
- String op;
- v2=popVal();
- v1=popVal();
- op=popOp();
- a1=Double.parseDouble(v1);
- a2=Double.parseDouble(v2);
- r=0.0;
- switch (op)
- {
- case "+":
- r=a1+a2;
- break;
- case "-":
- r=a1-a2;
- break;
- case "*":
- r=a1*a2;
- break;
- case "/":
- r=a1/a2;
- break;
- case "^":
- r=Math.pow(a1,a2);
- break;
- }
- v1=Double.toString(r);
- pushVal(v1);
- }
- // Основная ф-ция, с которой начинается разбор выражения.
- // Ф-ция инициализирует стеки;
- // с помощью ф-ции parse(String) разбивает её на элементы, которые заносит в массив Lex[]
- // с помощью ф-ции findVariables() ищет переменные и запрашивает их значения
- // после чего в цикле по каждому элементу (элементы = числа, знаки операций
- // и скобки) выражения начинается работа со стеками значений и операторов, в результате которой
- // в стеке значений остаётся численное значение введённого выражения.
- public void calculate(String l)
- {
- int i;
- String curr,top;
- Init();
- parse(l);
- findVariables();
- for (i=0; i<= ptrL; i++)
- {
- curr=Lex[i];
- switch (curr)
- {
- case "(":
- pushOp(curr);
- break;
- case "+":
- case "-":
- case "*":
- case "/":
- case "^":
- if (isEmptyOp())
- {
- pushOp(curr);
- break;
- }
- top=peekOp();
- if (Prty(curr) > Prty(top))
- {
- pushOp(curr);
- break;
- }
- else
- {
- exec();
- pushOp(curr);
- break;
- }
- case ")":
- while (true)
- {
- top=peekOp();
- if (top.equals("("))
- {
- top=popOp();
- break;
- }
- exec();
- }
- break;
- default:
- pushVal(curr);
- }
- }
- while (! isEmptyOp())
- {
- exec();
- }
- }
- // Функция идёт посимвольно по выражению и разбивает его на элементы, заполняя массив Lex[]
- // элементами являются знаки операций, числа, скобки.
- public void parse(String formula)
- {
- char s;
- int i;
- String Tmp="";
- Lex=new String[200];
- for (i=0; i<200; i++) Lex[i]="";
- ptrL=0;
- for (i=0; i<formula.length(); i++)
- {
- s=formula.charAt(i);
- switch (s)
- {
- case '+':
- case '-':
- case '*':
- case '^':
- case '/':
- case '(':
- case ')':
- if (Tmp.length() > 0)
- {
- Lex[ptrL++]=Tmp;
- Tmp="";
- }
- Lex[ptrL++]=""+s;
- break;
- case ' ':
- break;
- default:
- Tmp=Tmp+s;
- }
- }
- if (Tmp.length() > 0) Lex[ptrL]=Tmp;
- // for (int j =0; j<formula.length(); j++)
- // System.out.println(Lex[j]+"\n");
- }
- // Ф-ция проверяет, содержит ли строка какие-либо символы латинского алфавита.
- public boolean containsChars(String str)
- {
- boolean flag = false;
- for (int i =0; i<str.length(); i++)
- {
- if ((str.charAt(i) >= 'a' && str.charAt(i) <= 'z') || (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z'))
- {
- flag = true;
- }
- }
- return flag;
- }
- // Ф-ция проверяет выражение на наличие переменных.
- // Для этого каждый элемент строки проверяется на наличие букв.
- // если элемент содержит букву, значит является переменной.
- // При обнаружении переменной, ф-ция запрашивает у пользователя её значение.
- public void findVariables()
- {
- for (int i =0; i<200; i++)
- {
- String lex = Lex[i];
- if (containsChars(lex))
- {
- if (variables.containsKey(lex))
- {
- Lex[i] = ""+variables.get(lex);
- } else
- {
- Scanner sc = new Scanner(System.in);
- System.out.print(lex+" >> ");
- Double value = sc.nextDouble();
- Lex[i] = ""+value;
- variables.put(lex, value);
- }
- }
- }
- }
- // Рекурсивная ф-ция для подсчёта значений найденных функций. (в примере только sin)
- // Алгоритм работы:
- // В строке находится опредление функции, например, "sin("
- // после чего находится скобка, которая её закрывает и выделяется выражение внутри скобки.
- // (т.е. для выражения "1+sin(sin(x)+2)" будет выделено "sin(x)+2")
- // если выражение внутри не содержит ф-ций, то считается его значение, после чего находится значение ф-ции по посчитанному значению.
- // если выражение содержит ф-ции, то алгоритм продолжается рекурсивно, вызовом ф-ции countFuntions от выделенной строки.
- public String countFunctions(String l)
- {
- while (l.contains("sin("))
- {
- CustomStack st = new CustomStack();
- String newstr = new String(l);
- int ptr = newstr.indexOf("sin(");
- newstr = newstr.substring(ptr+4, newstr.length());
- //System.out.println(newstr);
- int i =0;
- while (i < newstr.length())
- {
- if (newstr.charAt(i) == '(')
- st.push("(");
- if (newstr.charAt(i) == ')')
- {
- if (st.isEmpty())
- {
- ptr = i;
- break;
- }
- if (st.peek() == "(")
- st.pop();
- else
- { ptr = i;
- break;
- }
- }
- i++;
- }
- newstr = newstr.substring(0, ptr);
- String savedStr = new String(newstr);
- // System.out.println(newstr+" saved="+savedStr);
- newstr = countFunctions(newstr);
- // System.out.println("-> "+newstr);
- calculate(newstr);
- // System.out.println("--> "+newstr);
- Double value = Double.parseDouble(popVal());
- value = Math.sin(value);
- String formattedDouble = String.format("%.4f", value);
- if (value<0) formattedDouble = "0"+formattedDouble;
- formattedDouble = formattedDouble.replaceAll(",", ".");
- l = l.replace("sin("+savedStr+")", formattedDouble);
- }
- return l;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement