Автор работы: Пользователь скрыл имя, 25 Августа 2013 в 18:52, курсовая работа
Задачей курсовой работы является написание строкового калькулятора. Строковый калькулятор позволяет вычислять математические выражения, введенные пользователем в строку, например: (12-34)*5+19/4.
Строковый калькулятор поддерживает операции сложения (+), вычитания (-), умножения (*), деления (/) и возведения в степень (^).
В основе работы строкового калькулятора лежит преобразование выражения в обратную польскую запись и дальнейшее его вычисление.
// если в итоге стек оказался пустым, приоритет его символов = 0
if (stck == "")
else
// если стек не пустой, переопределяем приоритет последнего символа
}
// исключаем открывающую скобку из стека
stck = stck.substr(0, stck.length() - 1);
if (stck == "")
priorStack = 0;
else
priorStack = priorOfSymbol(stck[stck.
}
// если символ не является закрывающей скобкой
else
{
// если открывающая скобка, записываем ее в стек
if (prior == 1)
{
stck += chS;
priorStack = prior;
}
// если другой символ
else
{
// до тех пор, пока приоритет символа меньше приоритета последнего
// символа в стеке, переносим символы из стека в строку результата
while (prior <= priorStack)
{
}
stck += chS;
priorStack = prior;
}
}
}
}
// в конце переписывем все оставшиеся в стеке символы в строку результата
for (int f = 0; f < stck.length(); f++)
{
poland += stck[stck.length() - 1 - f];
}
return poland;
}
//----------------------------
// функция вычисления результата
//----------------------------
// в качестве параметров передается строка соответствующего выражения и массив
// элементов типа Symbol, который хранит соответствие между символами в выражении и
// их численными значениями
//----------------------------
double calcResult(string str,Symbol *sym,int n)
{
double r = 0; // результат
double r1 = 0; // первый операнд
double r2 = 0; // второй операнд
char operation; // операция
int sInt = 0; // индекс элемента массива, в котором хранится результат
// выполнения текущей операции
for (int i = 0; i < str.length(); i++)
{
// определение типа операции
if (str[i] == '+' || str[i] == '-' || str[i] == '*' ||
str[i] == '/' || str[i] == '^')
{
operation = str[i];
// получение первого и второго операндов
for (int l = 0; l <= n; l++)
{
if (sym[l].symb == str[i - 2])
{
r1 = sym[l].val;
}
if (sym[l].symb == str[i - 1])
{
r2 = sym[l].val;
// результат записывается на место второго операнда
sInt = l;
}
}
// в зависимости от операции, выполняем соответствующее действие
switch (operation)
{
case '+':
r = r1 + r2;
break;
case '-':
r = r1 - r2;
break;
case '*':
r = r1 * r2;
break;
case '/':
r = r1 / r2;
break;
case '^':
// при попытке вычислить дробную степень из отрицательного числа (т.е. корень)
// в результат записывается значение NULL, что в последствие приведет к выводу
// сообщения об ошибке
if ((r1 < 0)&&((r2>-1)&&(r2<1)))
r = NULL;
else
r = pow(r1, r2);
break;
}
// последняя операция производится, когда остается 3 элемента в массиве (2 операнда
// и символ операции, далее вычисления не производятся
if (str.length() == 3)
break;
// после выполнения текущей операции, записываем результат на место второго
// операнда и получаем новую строку вычисляемого выражения
if (i > 2)
str = str.substr(0, i - 2) + str[i - 1] + str.substr(i + 1, str.length() - i - 1);
else
str = str[i - 1] + str.substr(i + 1, str.length() - 3);
sym[sInt].val = r;
i = 0;
}
}
return r;
}
//----------------------------
// функция преобразования строки в выражение и вычисления его значения
//----------------------------
double convertAndCalc(string str)
{
// массив для хранения данных о символах в выражении и их числовых значениях
Symbol *sym = new Symbol[str.length()];
int j = 0;
// first char = 'a', fNum, lNum - bounds of values
char ch = 'a'; // первый символ равен 'a'
int fNum = 0, lNum = -1; // первый и последний элементы в строке,
string result = ""; // результат преобразования строки пользователя в
for (int i = 0; i < str.length(); i++)
{
// допустимые символы в выражении – цифры и символы операций, если выражение
// содержит иные символы или два символа операции подряд, результат будет равен
// NULL, а пользователю выведется сообщение об ошибке
if(((str[i]<40)||(str[i]==44)|
||(isOperation(str[i])&&
{
return NULL;
}
// если символ – операция, получаем предшествующее ей число (границы числа fNum и
// lNum. Если символ не операция, правая граница числа (lNum) = текущему символу
if (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/' ||
str[i] == '^' || str[i] == '(' || str[i] == ')')
{
if (lNum >= fNum)
{
// записываем информацию о числе в массив
double val = atof(str.substr(fNum, lNum - fNum + 1).c_str());
sym[j].symb = ch;
sym[j].val = val;
ch++;
j++;
}
// записываем информация об операции в массив
sym[j].symb = str[i];
sym[j].val = 0;
j++;
fNum = i + 1;
}
else
lNum = i;
}
// записываем информацию о последнем числе в массив
if (lNum >= fNum)
{
double v = atof(str.substr(fNum, lNum - fNum + 1).c_str());
sym[j].symb = ch;
sym[j].val = v;
ch++;
j++;
}
// записываем полученное выражение в строку результата
for (int i = 0; i < j; i++)
{
result += sym[i].symb;
}
// если выражение содержит участки вида ‘(-a’ или начинается с ‘-а’, они заменяются
// на 'a', но при этом числовое значение меняет знак на противоположный
for (int i = 0; i < result.length() - 2; i++)
{
if (result[i] == '(' && result[i + 1] == '-')
{
sym[i + 2].val = -sym[i + 2].val;
result = result.substr(0, i + 1) + result.substr(i + 2, result.length() - i - 2);
}
}
if (result[0] == '-')
{
sym[1].val = -sym[1].val;
result = result.substr(1);
}
// если число открытых скобок не равно числу закрытых скобок, возвращаем NULL
// (выводим сообщение об ошибке в выражении)
int numOfOpen = 0, numOfClosed = 0;
for (int i = 0; i < result.length(); i++)
{
if (result[i] == '(')
numOfOpen++;
if (result[i] == ')')
numOfClosed++;
}
if (numOfOpen != numOfClosed)
return NULL;
// полученное выражение преобразуем в обратную польскую запись
string poland = convertToPoland(result);
// вычисляем значение выражения
double r = calcResult(poland,sym,j);
// освобождаем память выделенную под массив sym
delete[] sym;
return r;
}