You are on page 1of 29

МІНІСТЕРСТВО ОСВІТИ ТА НАУКИ УКРАЇНИ

НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ “ЛЬВІВСЬКА ПОЛІТЕХНІКА”


КАФЕДРА ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ

КУРСОВА РОБОТА
з дисципліни «Об'єктно-орієнтоване програмування»
на тему: «Обчислення математичних виразів»

Студента ПЗ - 23
спеціальності 121
«Програмне забезпечення»
Воляник М.В.

Науковий керівник
доцент кафедри ПЗ, доцент, к.т.н.
Дяконюк Л.М.

Національна шкала ________________

Кількість балів: __________Оцінка: ECTS _____

Члени комісії ________________ ___________________________


(підпис) (прізвище та ініціали)
________________ ___________________________
(підпис) (прізвище та ініціали)
________________ ___________________________
(підпис) (прізвище та ініціали

Львів — 2017 рік


Зміст

1. Технічне завдання. 3
2. Алгоритми розв’язку задачі. 4
3. Діаграми. 6
4. Текст програми. 7
5. Протокол роботи програми. 22
6. Виняткові ситуації. 24
7. Інструкція користувача. 27
8. Використана література. 28
9. Висновок 29

2
Технічне завдання
I. Загальні положення:
 Найменування роботи: «Обчислення математичних виразів».
 Умовне позначення. “Calculator of mathematical expression”
 Замовник: Дяконюк Лілія Миколаївна.
 Розробник: Воляник Микола Васильович.
 Терміни початку та закінчення робіт: 01.10.2017 р. – 01.12. 2017 р.
II. Призначення системи: програма призначена для обчислення математичних
виразів. Ціль програми полягає у перетворення вхідного виразу у польський і
зворотній польський вирази, обчисленні даних виразів і порівнянні результатів.
Результатом роботи програми є польський і зворотній польський вирази та
результати їх обчислення.
III. Об’єкти даних: з допомогою розробленого ПЗ має опрацьовуватись вхідна стрічка
(інфіксний вираз), введена у відповідне поле або зчитана з файлу. У виразі можуть
бути присутні дужки, довільні ідентифікатори (записані латинськими літерами та
цифрами (не можуть починатися з цифри)), дійсні числа (записані через крапку)
та такі операції: додавання, віднімання, множення, ділення та піднесення до
степеня. Вважається, що вираз задано правильно, без помилок. Перед
обчисленням значення виразу користувач ініціалізує ідентифікатори (якщо вони
присутні у виразі).
Приклад: (3+5.6)/4-3^2-4*5.
(a1+1)^b1-f5
IV. Вимоги до ПЗ:
 Програма повинна складатися з таких файлів:
mathematicalexpression.h, mathematicalexpression.cpp, calculator.h, calcula-
tor.cpp, additional.h, additional.cpp, exceptions.h, exceptions.cpp;
 Перелік функції, що виконуватиме програма (функціональні вимоги):
1) перетворює вхідний вираз у польський та зворотній польські вирази;
2) виводить на екран таблицю з ідентифікаторами;
3) зчитує ідентифікатори з таблиці;
4) перевіряє на коректність область допустимих значень функцій;
5) обчислює значення виразів.
 Нефункціональні вимоги:
1) надійність;
2) ефективність;
3) зручність;
4) портативність..
V. Перелік етапів ЖЦ ПЗ:
1. Специфікація вимог: було складено технічне завдання згідно з
методичними вказівками з курсу «Вступ до інженерії ПЗ»
2. Аналіз: поставлена задача була проаналізована, були прийняті до уваги
специфікації завдання, розглянуті алгоритми для виконання поставленої
задачі та були обрані найбільш оптимальні з погляду продуктивність/
зручність.
3. Реалізація: програма була написана мовою С++.
4. Тестування: програмний продукт був тестований (перевіний на
лексичні/семантичні/логічні помилки, відбулося тестування на виконання
поставлених вимог). Програма відповідає всім вимогам.
5. Експлуатація та супровід: програма ще не введена в експлуатацію.
6. Зняття системи з експлуатації: програма ще не введена в експлуатацію.

3
Алгоритм побудови зворотнього польського виразу
Посимвольно проглядаємо вхідну стрічку (інфіксний вираз) з початку до кінця.
Операнди записуємо у вихідну стрічку у порядку зустрічі, а знаки операцій і дужки
записуємо у стек за такими правилами:
- якщо поточний символ є відкриваючою дужкою ‘(‘, то заносимо її у стек;
- якщо поточний символ є закриваючою дужкою ‘)’, то виштовхуємо всі операції зі
стеку у вихідну стрічку до найближчої відкриваючої дужки (відкриваючу дужку
видаляємо зі стеку, а самі дужки у вихідну стрічку не записуємо);
- якщо поточний символ є операцією, то виштовхуємо зі стека всі операції з більшим
або таким самим пріоритетом у вихідну стрічку; після цього записуємо поточний
символ у стек;
- якщо ми проглянули всю вхідну стрічку і в стеку залишися операції, то виштовхуємо
їх у вихідну стрічку.

Алгоритм побудови польського виразу


Реверсуємо вхідну стрічку (інфіксний вираз). Посимвольно проглядаємо її з початку до
кінця. Операнди записуємо у вихідну стрічку у порядку зустрічі, а знаки операцій і дужки
записуємо у стек за такими правилами:
- якщо поточний символ є закриваючою дужкою ‘)‘, то заносимо її у стек;
- якщо поточний символ є відкриваючою дужкою ‘(’, то виштовхуємо всі операції зі
стеку у вихідну стрічку до найближчої закриваючої дужки(закриваючу дужку
видаляємо зі стеку, а самі дужки у вихідну стрічку не записуємо);
- якщо поточний символ є операцією, то виштовхуємо зі стека всі операції з більшим
пріоритетом у вихідну стрічку; після цього записуємо поточний символ у стек;
- якщо ми проглянули всю вхідну стрічку і в стеку залишися операції, то виштовхуємо
їх у вихідну стрічку.
- реверсуємо вихідну стрічку.

Алгоритм обчислення зворотнього польського виразу


Посимвольно проглядаємо зворотній польський запис з початку до кінця. Операнди
записуємо у стек у порядку зустрічі. Якщо зустрічаємо знак операції, то:
- якщо операція унарна, то виштовхуємо зі стеку один операнд і рахуємо значення
функції, якій відповідає дана операція;
- якщо операція бінарна, то виштовхуємо зі стеку два операнди (причому перший
виштовхнутий операнд буде відповідати другому числу, а другий – першому) і
рахуємо значення функції, якій відповідає дана операція;
- результат записуємо у стек;

Результатом обчислення виразу буде єдине значення, яке знаходиться в стекові.

4
Алгоритм обчислення польського виразу
Посимвольно проглядаємо польський запис з кінця до початку. Операнди записуємо у
стек у порядку зустрічі. Якщо зустрічаємо знак операції, то:
- якщо операція унарна, то виштовхуємо зі стеку один операнд і рахуємо значення
функції, якій відповідає дана операція;
- якщо операція бінарна, то виштовхуємо зі стеку два операнди (причому перший
виштовхнутий операнд буде відповідати першому числу, а другий – першому) і
рахуємо значення функції, якій відповідає дана операція;
- результат записуємо у стек;

Результатом обчислення виразу буде єдине значення, яке знаходиться в стекові.

5
Діаграма класів

Рисунок 1. Діаграма класів

Діаграма послідовності

Рисунок 2. Діаграма послідовності

6
Текст програми
<additional.h>
#ifndef ADDITIONAL_H
#define ADDITIONAL_H

#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <QTableWidget>

//-------------------------------------------------------------------------------
// class which includes additional function
class Additional
{
public:
// deletes gaps in string
static void deleteGaps(std::string &_expression);
// checks correctnes of power
static bool checkingPower(long double _number, long double _power);
// find the greatest common divider
static long long int gcd(long long int _firstNumber, long long int _secondNumber);
// find ids in string and write them in form
static void writeIds(const std::string& _expression, QTableWidget *_table);
// read ids from form
static std::map<std::string, long double> readIds(QTableWidget *_table);
};
//-------------------------------------------------------------------------------
#endif // ADDITIONAL_H

<calculator.h>
#ifndef CALCULATOR_H
#define CALCULATOR_H

#include <map>
#include <functional>
#include <string>

//-------------------------------------------------------------------------------
// class which calculate functions
class Calculator
{
// operations
std::map<char, std::function<long double(long double, long double)>> operations;
// priority of operations
std::map<char, int> priority;

public:
// add operations
void defineOperation(char _operation, std::function<long double(long double, long double)> _function);
// perform operation
long double performOperation(char _operation, long double _firstNumber, long double _secondNumber);
// set priority of operations
void setPriority(char _operation, int _priority);
// get priority of operation
int getPriority(char _operation);
};
//-------------------------------------------------------------------------------
#endif // CALCULATOR_H

<exceptions.h>
#ifndef EXCEPTIONS_H
#define EXCEPTIONS_H

#include <string>
//-------------------------------------------------------------------------------
// basic classs of exceptions
7
class Error
{
protected:
std::string Msg;
public:
Error(const std::string& _msg);
const std::string& info();
};
//-------------------------------------------------------------------------------
// divide by zero exception
class DivideByZero : public Error
{
public:
DivideByZero();
};
//-------------------------------------------------------------------------------
// emtty string exception
class EmptyExpression : public Error
{
public:
EmptyExpression();
};
//-------------------------------------------------------------------------------
// not defined id exception
class NotDefinedId : public Error
{
public:
NotDefinedId();
};
//-------------------------------------------------------------------------------
// incorrect powet exception
class BadPower : public Error
{
public:
BadPower();
};
//-------------------------------------------------------------------------------
// not defined operation exception
class NotDefinedOperation : public Error
{
public:
NotDefinedOperation(char _operation);
};
//-------------------------------------------------------------------------------
// not defined priority of operation exception
class NotDefinedOperationPriority : public Error
{
public:
NotDefinedOperationPriority(char _operation);
};
//-------------------------------------------------------------------------------
// error opening file exception
class ErrorOpeningFile : public Error
{
public:
ErrorOpeningFile(const std::string &_file);
};
//-------------------------------------------------------------------------------
#endif // EXCEPTIONS_H

<mathematicalexpression.h>
#ifndef MATHEMATICALEXPRESSION_H
#define MATHEMATICALEXPRESSION_H

#include "calculator.h"
#include "additional.h"
#include <string>
#include <map>
#include <stack>
#include <vector>

8
//-------------------------------------------------------------------------------
// main class
class MathematicalExpression
{
private:
// main, prefix and postfix expression
std::string mExpression;
std::string mPostfixExpression;
std::string mPrefixExpression;

// ids with value of expression


std::map<std::string, long double> mIds;

// pointers on calculator class


Calculator *mCalculator;

// results of calculations
long double mResultOfPostfixExpression;
long double mResultOfPrefixExpression;

public:
// constructors of class
MathematicalExpression();
MathematicalExpression(const std::string &_expression);

// destructor
~MathematicalExpression();

// set expression, ids and pointers on calculator class


void setIds(const std::map<std::string, long double> &_ids);
void setExspression(const std::string &_expression);
void setCalculator(Calculator *_calc);

// make prefix and postfix expressions


void makePostfixExpression();
void makePrefixExpression();

// get main, prefix and postfix expressions


const std::string& getExpression() const;
const std::string& getPostfixExpression() const;
const std::string& getPrefixExpression() const;

// calculate prefix and postfix expressions


void calculatePostfixExpression();
void calculatePrefixExpression();

// get results of calculation postfix and prefix expression


long double getResultOfPostfixExpression() const;
long double getResultOfPrefixExpression() const;

private:
// find unary minuses
void findUnaryMinuses();

// calculate some function


long double calculateFunction(char _function, std::stack<long double> &_numbers, bool _post);
};
//-------------------------------------------------------------------------------
#endif // MATHEMATICALEXPRESSION_H

<additional.cpp>
#include "additional.h"
#include "exceptions.h"
#include <algorithm>
//-------------------------------------------------------------------------------
void Additional::deleteGaps(std::string &_expression)
{
_expression.erase(remove_if(_expression.begin(), _expression.end(),
[](char _ch) { return _ch == ' ' || _ch == '\n' || _ch == '\r'; }), _expression.end());

9
}
//-------------------------------------------------------------------------------
bool Additional::checkingPower(long double _number, long double _power)
{
long long int numerator, denominatorm = 1, _nsd;
std::string powerString = std::to_string(_power);
bool result;
int positionOfPoint, positionOfFirstNotZero;
long double fractionalPart;

if (_number >= 0)
result = true;
else
{
if (_power - floor(_power) == 0)
result = true;
else
{
for (int i = powerString.size() - 1; i >= 0; --i)
{
if (powerString[i] != '0')
{
positionOfFirstNotZero = i;
break;
}
}

for (int i = 0, _size = powerString.size(); i < _size; ++i)


{
if (powerString[i] == '.')
{
positionOfPoint = i;
break;
}
}

int count = positionOfFirstNotZero - positionOfPoint;


fractionalPart = _power - floor(_power);

numerator = fractionalPart * pow(10, count);


denominatorm *= pow(10, count);

_nsd = gcd(numerator, denominatorm);

numerator /= _nsd;
denominatorm /= _nsd;

if (denominatorm % 2 == 1)
result = true;
else
result = false;
}
}

return result;
}
//-------------------------------------------------------------------------------
long long int Additional::gcd(long long int _firstNumber, long long int _secondNumber)
{
if (_secondNumber == 0)
return _firstNumber;
else
gcd(_secondNumber, _firstNumber % _secondNumber);
}
//-------------------------------------------------------------------------------
void Additional::writeIds(const std::string &_expression, QTableWidget *_table)
{
std::vector<std::string> Ids;
std::string sId = "";
int rows = 0;

10
for (int i = 0, _size = _expression.size(); i < _size; ++i)
{
while (i != _size && (isalpha(_expression[i]) || (isdigit(_expression[i]) && !sId.empty())))
{
sId += _expression[i];
++i;
}

if (!sId.empty())
{
if (!Ids.empty())
{
if(std::find(Ids.begin(), Ids.end(), sId) == Ids.end())
{
_table->setRowCount(_table->rowCount() + 1);
_table->setItem(rows++, 0, new QTableWidgetItem(QString::fromStdString(sId)));
Ids.push_back(sId);
}
}
else
{
_table->setRowCount(_table->rowCount() + 1);
_table->setItem(rows++, 0, new QTableWidgetItem(QString::fromStdString(sId)));
Ids.push_back(sId);
}

sId.clear();
}
}
}
//-------------------------------------------------------------------------------
std::map<std::string, long double> Additional::readIds(QTableWidget *_table)
{
std::map<std::string, long double> ids;
for(int i = 0, _size = _table->rowCount(); i < _size; ++i)
{
if(_table->item(i, 1) == NULL)
throw NotDefinedId();
else
ids[_table->item(i, 0)->text().toStdString()] = _table->item(i, 1)->text().toDouble();
}

return ids;
}
//-------------------------------------------------------------------------------

<calculator.cpp>
#include "calculator.h"
#include "exceptions.h"

//-------------------------------------------------------------------------------
void Calculator::defineOperation(char _operation, std::function<long double(long double, long double)> _function)
{
if (operations.find(_operation) == operations.end())
operations.insert(std::pair<char, std::function<long double(long double, long double)>>(_operation, _function));
}
//-------------------------------------------------------------------------------
long double Calculator::performOperation(char _operation, long double _firstNumber, long double _secondNumber)
{
if (operations.find(_operation) == operations.end())
throw NotDefinedOperation(_operation);
else
return operations[_operation](_firstNumber, _secondNumber);
}
//-------------------------------------------------------------------------------
void Calculator::setPriority(char _operation, int _priority)
{
if (priority.find(_operation) == priority.end())
priority.insert(std::pair<char, int>(_operation, _priority));

11
}
//-------------------------------------------------------------------------------
int Calculator::getPriority(char _operation)
{
if (priority.find(_operation) == priority.end())
throw NotDefinedOperationPriority(_operation);
else
return priority[_operation];
}
//-------------------------------------------------------------------------------

<exceptions.cpp>
#include "exceptions.h"

//-------------------------------------------------------------------------------
Error::Error(const std::string &_msg) : Msg(_msg)
{

}
//-------------------------------------------------------------------------------
const std::string& Error::info()
{
return Msg;
}
//-------------------------------------------------------------------------------
DivideByZero::DivideByZero() : Error("Divide by zero!!!")
{

}
//-------------------------------------------------------------------------------
BadPower::BadPower() : Error("Bad power")
{

}
//-------------------------------------------------------------------------------
EmptyExpression::EmptyExpression() : Error("Empty expression")
{
}
//-------------------------------------------------------------------------------
NotDefinedId::NotDefinedId() : Error("Some ids not defined")
{
}
//-------------------------------------------------------------------------------
NotDefinedOperation::NotDefinedOperation(char _operation) : Error("Not defined operation")
{
Msg.append(" ");
Msg.append(1, _operation);
}
//-------------------------------------------------------------------------------
NotDefinedOperationPriority::NotDefinedOperationPriority(char _operation) : Error("Not defined priority of operation")
{
Msg.append(" ");
Msg.append(1, _operation);
}
//-------------------------------------------------------------------------------
ErrorOpeningFile::ErrorOpeningFile(const std::string &_file) : Error("Error openin file")
{
Msg.append(" " + _file);
}
//-------------------------------------------------------------------------------

<mathematicalexpression.cpp>
#include "mathematicalexpression.h"
#include "exceptions.h"
#include <stack>
#include <cmath>
#include <algorithm>

//-------------------------------------------------------------------------------

12
MathematicalExpression::MathematicalExpression() : mExpression(""), mCalculator(NULL)
{

}
//-------------------------------------------------------------------------------
MathematicalExpression::MathematicalExpression(const std::string &_expression) : mExpression(_expression), mCalculator(NULL)
{
if(mExpression.empty())
throw EmptyExpression();
Additional::deleteGaps(mExpression);
if(mExpression.empty())
throw EmptyExpression();

findUnaryMinuses();
}
//-------------------------------------------------------------------------------
MathematicalExpression::~MathematicalExpression()
{

}
//-------------------------------------------------------------------------------
void MathematicalExpression::setExspression(const std::string &_expression)
{
mExpression = _expression;

if(mExpression.empty())
throw EmptyExpression();
Additional::deleteGaps(mExpression);
if(mExpression.empty())
throw EmptyExpression();

findUnaryMinuses();
}
//-------------------------------------------------------------------------------
void MathematicalExpression::setCalculator(Calculator *_calc)
{
mCalculator = _calc;
}
//-------------------------------------------------------------------------------
void MathematicalExpression::setIds(const std::map<std::string, long double> &_ids)
{
mIds = _ids;
}
//-------------------------------------------------------------------------------
void MathematicalExpression::findUnaryMinuses()
{
for (int i = 0, _size = mExpression.size(); i < _size; ++i)
{
if (mExpression[i] == '-' && (i == 0 || (i > 0 && mExpression[i - 1] == '(')))
{
mExpression[i] = '#';
}
}

for (int i = 0, _size = mExpression.size(); i < _size; ++i)


{
int firstPosition = i, countOfOpenBracket = 0, secondPosition = 0;
if (mExpression[i] == '#')
{
if (isalnum(mExpression[i + 1]))
{
++i;
while (isalnum(mExpression[i]))
++i;

if (mExpression[i] == '*' || mExpression[i] == '/')


{
mExpression.insert(mExpression.begin() + firstPosition, '(');
mExpression.insert(mExpression.begin() + i + 1, ')');
}
}
13
else if (mExpression[i + 1] == '(')
{
countOfOpenBracket = 1;
for (int j = i + 2; j < mExpression.size(); ++j)
{
if (mExpression[j] == ')')
{
--countOfOpenBracket;

if (countOfOpenBracket == 0)
{
secondPosition = j + 1;
break;
}
}
if (mExpression[j] == '(')
++countOfOpenBracket;
}

if (mExpression[secondPosition] == '*' || mExpression[secondPosition] == '/')


{
mExpression.insert(mExpression.begin() + firstPosition, '(');
mExpression.insert(mExpression.begin() + secondPosition + 1, ')');
}
++i;
}
}
}
}
//-------------------------------------------------------------------------------
long double MathematicalExpression::calculateFunction(char _function, std::stack<long double> &_numbers, bool _isPostfix)
{
double firstNumber, secondNumber, result;

if (_function == '#')
{
firstNumber = _numbers.top();
_numbers.pop();
result = mCalculator->performOperation(_function, firstNumber, -1.);
}
else
{
_isPostfix ? secondNumber = _numbers.top() : firstNumber = _numbers.top();
_numbers.pop();
_isPostfix ? firstNumber = _numbers.top() : secondNumber = _numbers.top();
_numbers.pop();
if (_function == '/' && secondNumber == 0)
throw DivideByZero();
else if (_function == '^' && !Additional::checkingPower(firstNumber, secondNumber))
throw BadPower();
else if(_function == '^' && firstNumber < 0 && secondNumber - floor(secondNumber) != 0)
result = -mCalculator->performOperation(_function, fabs(firstNumber), secondNumber);
else
result = mCalculator->performOperation(_function, firstNumber, secondNumber);
}

return result;
}
//-------------------------------------------------------------------------------
void MathematicalExpression::makePostfixExpression()
{
std::stack<char> operations;
std::string value = "";
mPostfixExpression = "";

for (int i = 0, _size = mExpression.size(); i < _size; ++i)


{
if (mExpression[i] == '(')
{
operations.push(mExpression[i]);
continue;
14
}

while (isalnum(mExpression[i]) || mExpression[i] == '.')


{
value += mExpression[i];
i++;
}

if (value.size() != 0)
{
mPostfixExpression += value;
mPostfixExpression += " ";
value.clear();
}

if (!isalnum(mExpression[i]) && mExpression[i] != '(' &&


mExpression[i] != ')' && mExpression[i] != '\0')
{
while (!operations.empty() &&
(mCalculator->getPriority(operations.top()) >= mCalculator->getPriority(mExpression[i])))
{
mPostfixExpression += operations.top();
mPostfixExpression += " ";
operations.pop();
}
operations.push(mExpression[i]);
}

if (mExpression[i] == ')')
{
while (operations.top() != '(')
{
mPostfixExpression += operations.top();
mPostfixExpression += " ";
operations.pop();
}
operations.pop();
}
}

while (!operations.empty())
{
mPostfixExpression += operations.top();
mPostfixExpression += " ";
operations.pop();
}
}
//-------------------------------------------------------------------------------
void MathematicalExpression::makePrefixExpression()
{
std::stack<char> operations;
std::string value = "";
mPrefixExpression = "";
std::string reverseExpression = mExpression;
std::reverse(reverseExpression.begin(), reverseExpression.end());

for (int i = 0, _size = reverseExpression.size(); i < _size; ++i)


{
if (reverseExpression[i] == ')')
{
operations.push(reverseExpression[i]);
continue;
}

while (isalnum(reverseExpression[i]) || reverseExpression[i] == '.')


{
value += reverseExpression[i];
i++;
}

if (value.size() != 0)
15
{
mPrefixExpression += value;
mPrefixExpression += " ";
value.clear();
}

if (!isalnum(reverseExpression[i]) && reverseExpression[i] != '(' &&


reverseExpression[i] != ')' && reverseExpression[i] != '\0')
{
while (!operations.empty() && (mCalculator->getPriority(operations.top()) > mCalculator-
>getPriority(reverseExpression[i])))
{
mPrefixExpression += operations.top();
mPrefixExpression += " ";
operations.pop();
}

operations.push(reverseExpression[i]);
}

if (reverseExpression[i] == '(')
{
while (operations.top() != ')')
{
mPrefixExpression += operations.top();
mPrefixExpression += " ";
operations.pop();
}
operations.pop();
}
}

while (!operations.empty())
{
mPrefixExpression += operations.top();
mPrefixExpression += " ";
operations.pop();
}

std::reverse(mPrefixExpression.begin(), mPrefixExpression.end());
}
//-------------------------------------------------------------------------------
const std::string& MathematicalExpression::getExpression() const
{
return mExpression;
}
//-------------------------------------------------------------------------------
const std::string& MathematicalExpression::getPostfixExpression() const
{
return mPostfixExpression;
}
//-------------------------------------------------------------------------------
const std::string& MathematicalExpression::getPrefixExpression() const
{
return mPrefixExpression;
}
//-------------------------------------------------------------------------------
void MathematicalExpression::calculatePostfixExpression()
{
long double value = 0;
long double result;
std::string stringValue = "";
std::stack<long double> numbers;

for (int i = 0, _size = mPostfixExpression.size(); i < _size; ++i)


{
if (isalnum(mPostfixExpression[i]) || mPostfixExpression[i] == '.')
{
while (mPostfixExpression[i] != ' ')
{
stringValue += mPostfixExpression[i];
16
i++;
}

if (isdigit(stringValue[0]) || stringValue[0] == '.')


{
value = atof(stringValue.c_str());
numbers.push(value);
stringValue.clear();
}
else
{
numbers.push(mIds[stringValue]);
stringValue.clear();
}
}
else
{
if (!isalnum(mPostfixExpression[i]) && mPostfixExpression[i] != '(' &&
mPostfixExpression[i] != ')' && mPostfixExpression[i] != '\0' && mPostfixExpression[i] != ' ')
{
result = calculateFunction(mPostfixExpression[i], numbers, true);

numbers.push(result);
}
}
}

if (!numbers.empty())
mResultOfPostfixExpression = numbers.top();
}
//-------------------------------------------------------------------------------
void MathematicalExpression::calculatePrefixExpression()
{
long double value = 0;
long double result;
std::string stringValue = "";
std::stack<long double> numbers;

for (int i = mPrefixExpression.size() - 1; i >= 0; --i)


{
if (isalnum(mPrefixExpression[i]) || mPrefixExpression[i] == '.')
{
while (mPrefixExpression[i] != ' ')
{
stringValue += mPrefixExpression[i];
i--;
}

if (isdigit(stringValue[stringValue.size() - 1]) || stringValue[stringValue.size() - 1] == '.')


{
std::reverse(stringValue.begin(), stringValue.end());
value = atof(stringValue.c_str());
numbers.push(value);
stringValue.clear();
}
else
{
std::reverse(stringValue.begin(), stringValue.end());
numbers.push(mIds[stringValue]);
stringValue.clear();
}
}
else
{
if (!isalnum(mPrefixExpression[i]) && mPrefixExpression[i] != '(' &&
mPrefixExpression[i] != '(' && mPrefixExpression[i] != '\0'&& mPrefixExpression[i] != ' ')
{
result = calculateFunction(mPrefixExpression[i], numbers, false);

numbers.push(result);
}
17
}
}

if (!numbers.empty())
mResultOfPrefixExpression = numbers.top();
}
//-------------------------------------------------------------------------------
long double MathematicalExpression::getResultOfPostfixExpression() const
{
return mResultOfPostfixExpression;
}
//-------------------------------------------------------------------------------
long double MathematicalExpression::getResultOfPrefixExpression() const
{
return mResultOfPrefixExpression;
}
//-------------------------------------------------------------------------------

<mainwindow.cpp>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "calculator.h"
#include "additional.h"
#include "exceptions.h"
#include <QMessageBox>
#include <QFile>
#include <cmath>
#include <sstream>
#include <QByteArray>
#include <QFileDialog>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

setWindowTitle("Calculator of mathematical expression");

ui->idLabel->setVisible(false);
ui->idsTableWidget->setVisible(false);
ui->pushButton->setVisible(false);

calc = new Calculator;


calc->defineOperation('+', [](long double a, long double b) { return a + b; });
calc->defineOperation('-', [](long double a, long double b) { return a - b; });
calc->defineOperation('*', [](long double a, long double b) { return a * b; });
calc->defineOperation('/', [](long double a, long double b) { return a / b; });
calc->defineOperation('^', [](long double a, long double b) { return pow(a, b); });
calc->defineOperation('#', [](long double a, long double b) { return a * b; });

calc->setPriority('(', 0);
calc->setPriority(')', 1);
calc->setPriority('+', 2);
calc->setPriority('-', 2);
calc->setPriority('#', 2);
calc->setPriority('*', 3);
calc->setPriority('/', 3);
calc->setPriority('^', 4);

myExp = new MathematicalExpression;


myExp->setCalculator(calc);
setFixedSize(470, 340);
}

MainWindow::~MainWindow()
{
delete ui;
}

18
void MainWindow::on_pushButton_2_clicked()
{
try
{
setFixedSize(470, 340);

ui->idLabel->setVisible(false);
ui->idsTableWidget->setVisible(false);
ui->pushButton->setVisible(false);

ui->postExpressionEdit->clear();
ui->prefExpressionEdit->clear();
ui->postResult->clear();
ui->prefResult->clear();

ui->idsTableWidget->setRowCount(0);
std::string expression = ui->expressionEdit->text().toStdString();

myExp->setExspression(expression);

Additional::writeIds(expression, ui->idsTableWidget);

myExp->setExspression(expression);

myExp->makePostfixExpression();
myExp->makePrefixExpression();

ui->postExpressionEdit->setText(QString::fromStdString(myExp->getPostfixExpression()));
ui->prefExpressionEdit->setText(QString::fromStdString(myExp->getPrefixExpression()));

if(ui->idsTableWidget->rowCount() == 0)
{
on_pushButton_clicked();
}
else
{
setFixedSize(700, 340);

ui->idLabel->setVisible(true);
ui->idsTableWidget->setVisible(true);
ui->pushButton->setVisible(true);
}
}
catch(EmptyExpression exc)
{
QMessageBox::warning(this, "Ypppsss", exc.info().c_str());
}
catch(NotDefinedOperation exc)
{
QMessageBox::warning(this, "Ypppsss", exc.info().c_str());
}
catch(NotDefinedOperationPriority exc)
{
QMessageBox::warning(this, "Ypppsss", exc.info().c_str());
}
}

void MainWindow::on_pushButton_clicked()
{
try
{
std::stringstream out;
out.setf(std::ios::fixed);

std::map<std::string, long double> ids;


ids = Additional::readIds(ui->idsTableWidget);
myExp->setIds(ids);

myExp->calculatePostfixExpression();
myExp->calculatePrefixExpression();

19
if(myExp->getResultOfPostfixExpression() - floor(myExp->getResultOfPostfixExpression()) != 0)
out << myExp->getResultOfPostfixExpression();
else
out << int(myExp->getResultOfPostfixExpression());

ui->postResult->setText(QString::fromStdString(out.str()));

out.str("");

if(myExp->getResultOfPrefixExpression() - floor(myExp->getResultOfPrefixExpression()) != 0)
out << myExp->getResultOfPrefixExpression();
else
out << int(myExp->getResultOfPrefixExpression());

ui->prefResult->setText(QString::fromStdString(out.str()));
}
catch(DivideByZero exc)
{
QMessageBox::warning(this, "Ypppsss", exc.info().c_str());
}
catch(NotDefinedId exc)
{
QMessageBox::warning(this, "Ypppsss", exc.info().c_str());
}
catch(NotDefinedOperation exc)
{
QMessageBox::warning(this, "Ypppsss", exc.info().c_str());
}
catch(NotDefinedOperationPriority exc)
{
QMessageBox::warning(this, "Ypppsss", exc.info().c_str());
}
catch(BadPower exc)
{
QMessageBox::warning(this, "Ypppsss", exc.info().c_str());
}
}

void MainWindow::on_pushButton_3_clicked()
{
try
{
setFixedSize(470, 340);

ui->idLabel->setVisible(false);
ui->idsTableWidget->setVisible(false);
ui->pushButton->setVisible(false);

ui->postExpressionEdit->clear();
ui->prefExpressionEdit->clear();
ui->expressionEdit->clear();
ui->postResult->clear();
ui->prefResult->clear();

std::string expression;
std::string fileName = QFileDialog::getOpenFileName(0, "Open File", "", "*.txt *.doc *.docx").toStdString();
if(!fileName.empty())
{
QFile file(QString::fromStdString(fileName));
if (!file.open(QIODevice::ReadOnly))
throw ErrorOpeningFile(fileName);

QByteArray data;
data = file.readAll();
expression = data.toStdString();
file.close();

ui->idsTableWidget->setRowCount(0);

myExp->setExspression(expression);

20
Additional::writeIds(expression, ui->idsTableWidget);

myExp->setExspression(expression);
ui->expressionEdit->setText(QString::fromStdString(expression));
}

}
catch(EmptyExpression exc)
{
QMessageBox::warning(this, "Ypppsss", exc.info().c_str());
}
catch(ErrorOpeningFile exc)
{
QMessageBox::warning(this, "Ypppsss", exc.info().c_str());
}
}

21
Протокол роботи програми
- Якщо ми хочемо зчитати вираз з файлу, то натискаємо на кнопку Load from file.
З’являється вікно, в якому вибираємо потрібний файл.

Рисунок 3. Зчитування виразу з файлу

Відкриваємо його. Вираз з файлу з’являється в полі для введення виразу.


- Інакше вводимо вираз у дане поле з клавіатури.
- Натискаємо на кнопку Calculate.
- Якщо у виразі є ідентифікатори, то з’являється таблиця з ідентифікаторами. Інакше
відразу показуються результати.

Рисунок 4. Введення ідентифікаторів

22
- Вводимо значення ідентифікаторів. Натискаємо на кнопку SetId. У відповідних полях
бачимо результати роботи програми.

Рисунок 5. Результати роботи програми

23
Виняткові ситуації
У програмі передбачені такі виняткові ситуації :
1. Ділення на нуль.
2. Порожній вхідний вираз.
3. Парний корінь з від’ємного числа.
4. Помилка відкриття файлу.
5. Не введено значення ідентифікатора.
6. Не задано операцію(в коді програми).
7. Не задано пріоритет операції(в коді програми).

Рисунок 6. Ділення на нуль

24
Рисунок 7. Порожній вираз

Рисунок 8. Парний корінь з від’ємного числа

Рисунок 9. Не введено значення ідентифікатора

25
Якщо в коді програми ми не задамо операцію “+”.

Рисунок 10. Не задано операцію

Якщо в коді програми ми не задамо пріоритет операції “+”.

Рисунок 10. Не задано пріоритет операції

26
Інструкція користувача

Рисунок 11. Меню програми

1(Load from file) – кнопка для завантаження даних з файлу. При натисненні на кнопку
з’являється вікно, в якому ми вибираємо файл, з якого хочемо зчитати математичний вираз.
2 – поле для введення математичного виразу(після вибору файлу вираз автоматично
записується в дане полу).
3(Calculate) – кнопка для підрахунку значення математичного виразу. Якщо вираз містить
невизначенні ідентифікатори, то після натиснення на дану кнопку з’являється поле 4 та
кнопка 9. Якщо невизначені ідентифікатори відсутні, то проводяться обчислення і результати
записуються у поля 5, 6, 7, 8.
4 – поле для введення значень невизначених ідентифікаторів.
5 – поле для виведення результату польського виразу.
6 – поле для введення результату зворотнього польського виразу.
7 – поле для виведення польського виразу.
8 – поле для виведення зворотнього польського виразу.
9 (SetId) – кнопка для підрахунку значення математичного виразу, що містить невизначені
ідентифікатори. Після натиснення проводиться обчислення і результати записуються у поля
5, 6, 7, 8.

27
Використана література
1. Буч Г. UML. Руководство пользователя / Г. Буч, Дж. Рамбо, А. Джекобсон –
М.: МЦНМО, 2005. – 257 с.
2. Прата С. Язык программирования C++ / С. Прата – М.: ООО "И. Д. Вильямс", 2012. –
1244 с.
3. Коротєєва Т. О. Алгоритми та структури даних : навч. посібник / Т. О. Коротєєва. –
Львів : Видавництво Львівської політехніки, 2014. – 280 с.
4.Шилдт Г. Самоучитель С++ : 3 издание / Г. Шилдт – К.: БТХ – Петербург, 2003. – 687с.

28
Висновок
В ході виконання даної курсової роботи я створив програму для обчислення
математичних виразів. Дана програма перетворює інфіксний вираз в польський і зворотній
польський вирази, а потім рахує їхні значення. Також створив діаграми класів і послідовності
для демонстрації структури програми.
В результаті виконання даної курсової роботи я покращив свої знання з алгоритмічного і
об’єктно – орієнтованого програмування.

29

You might also like