Graphic Calculator: FIDocalcus
Проект трёх первокурсников (по инженерному практикуму в первом семестре) по созданию графического калькулятора на FLTK C++
Loading...
Searching...
No Matches
Math_func::function Class Reference

Математическая функция More...

#include <function.h>

Collaboration diagram for Math_func::function:

Public Member Functions

 function ()=default
 
 function (const function &)
 
 function (std::string _func_str)
 Инициализирует новый экземпляр function.
 
 ~function ()=default
 
std::string get_func_str () const
 Возвращает значение мат. функции в виде строки
 
bool has_var () const
 
double operator() (double x) const
 : Значение мат. функции
 
functionoperator= (const function &)
 

Public Attributes

const std::function< double(double)> calculate
 Значение мат. функции
 
const std::function< double(double)> differentiate
 Значение производной мат. функции
 

Private Member Functions

double calc (double x) const
 Значение мат. функции
 
void func_lexs_validation () const
 Проверяет вектор лексем от мат. функции на валидность
 
void func_str_validation () const
 Проверяет мат. функцию в виде строки, на валидность
 
std::vector< std::string > lexemes () const
 
std::vector< std::string > reverse_polish () const
 

Private Attributes

std::string func_str
 Мат. функция в виде строки
 
std::vector< std::string > lexs
 Вектор лексем от мат. функции
 
std::vector< std::string > rev_pol
 Вектор лексем, записанный в обратной польской нотации
 

Detailed Description

Математическая функция

Constructor & Destructor Documentation

◆ function() [1/3]

Math_func::function::function ( )
default

◆ function() [2/3]

Math_func::function::function ( std::string _func_str)

Инициализирует новый экземпляр function.

Parameters
_func_strстрока, представляющая собой мат. функцию
21 : func_str{spaces_deleted(_func_str)},
22 lexs{lexemes()},
std::vector< std::string > rev_pol
Вектор лексем, записанный в обратной польской нотации
Definition function.h:75
std::vector< std::string > reverse_polish() const
Definition function.cpp:116
std::vector< std::string > lexemes() const
Definition function.cpp:40
std::string func_str
Мат. функция в виде строки
Definition function.h:69
std::vector< std::string > lexs
Вектор лексем от мат. функции
Definition function.h:72
string spaces_deleted(const string &s)
Definition utilities.cpp:27

◆ function() [3/3]

Math_func::function::function ( const function & func)
26 : func_str{func.func_str}, lexs{func.lexs}, rev_pol{func.rev_pol} {}

◆ ~function()

Math_func::function::~function ( )
default

Member Function Documentation

◆ calc()

double Math_func::function::calc ( double x) const
private

Значение мат. функции

Parameters
x
Returns
double

Стек, куда складываем уже посчитанные числа

Последний символ в стеке

Предпоследний символ в стеке (последний после удаления l)

Символ, обозначающий текущую лексему в обратной польской записи

223 {
224 /// @brief Стек, куда складываем уже посчитанные числа
225 // IDK: а это точно так?
226 stack<double> calced_numbs;
227
228 // TODO: написать комментарии по работе этого цикла
229
230 // раскрываем обратную польскую нотацию, подставляя x
231 for (const auto& lex : rev_pol) {
232 /// @brief Последний символ в стеке
233 double l;
234
235 /// @brief Предпоследний символ в стеке (последний после удаления l)
236 double p;
237
238 /// @brief Символ, обозначающий текущую лексему в обратной польской записи
239 // (нужен для switch-case)
240 char l_c = s_to_c(lex);
241
242 if (c_in_s(l_c, math_func_chars)) {
243 l = calced_numbs.top(); // запоминаем только последний
244 // (так как элем. мат. функции унарны)
245 calced_numbs.pop();
246 switch (l_c) {
247 case c_sin:
248 calced_numbs.push(sin(l));
249 break;
250 case c_cos:
251 calced_numbs.push(cos(l));
252 break;
253 case c_tan:
254 calced_numbs.push(tan(l));
255 break;
256 case c_exp:
257 calced_numbs.push(exp(l));
258 break;
259 case c_ln:
260 calced_numbs.push(log(l));
261 break;
262 case uminus:
263 calced_numbs.push(-l);
264 break;
265 }
266 } else if (c_in_s(l_c, math_oper_chars)) {
267 l = calced_numbs.top();
268 calced_numbs.pop();
269 p = calced_numbs.top(); // также запоминаем предпоследний
270 // (так как мат. операции бинарны)
271 calced_numbs.pop();
272 switch (l_c) {
273 case plus:
274 calced_numbs.push(p + l);
275 break;
276 case minus:
277 calced_numbs.push(p - l);
278 break;
279 case mul:
280 calced_numbs.push(p * l);
281 break;
282 case divi:
283 calced_numbs.push(p / l);
284 break;
285 case power:
286 calced_numbs.push(pow(p, l));
287 break;
288 }
289 } else {
290 switch (l_c) {
291 case number:
292 calced_numbs.push(stod(lex));
293 break;
294 case var_x:
295 calced_numbs.push(x);
296 break;
297 default:
298 throw std::runtime_error("Oops");
299 break;
300 }
301 }
302
303 // получили математически недопустимое число
304 if (std::isnan(calced_numbs.top()) || std::isinf(calced_numbs.top()))
305 throw invalid_argument("violation of feasible region");
306 }
307
308 // последнее, что осталось в стеке после всех действий - и есть ответ
309 return calced_numbs.top();
310}
constexpr char plus
Definition constants.h:10
constexpr char number
Definition constants.h:17
constexpr char c_exp
Definition constants.h:23
const std::string math_oper_chars
Строка с разрешенными мат. операциями
Definition constants.h:31
constexpr char c_cos
Definition constants.h:21
constexpr char power
Definition constants.h:14
constexpr char divi
Definition constants.h:13
constexpr char c_ln
Definition constants.h:24
constexpr char mul
Definition constants.h:12
constexpr char c_tan
Definition constants.h:22
const std::string math_func_chars
Строка с разрешенными элементарным мат. функциями
Definition constants.h:28
constexpr char c_sin
Definition constants.h:20
constexpr char minus
Definition constants.h:11
constexpr char uminus
Definition constants.h:25
constexpr char var_x
Definition constants.h:18
char s_to_c(const string &s)
Definition utilities.cpp:11
bool c_in_s(char c, const string &s)
Definition utilities.cpp:9
Here is the call graph for this function:
Here is the caller graph for this function:

◆ func_lexs_validation()

void Math_func::function::func_lexs_validation ( ) const
private

Проверяет вектор лексем от мат. функции на валидность

Правильное использование элементарной мат. функций (типа exp, sin, ln), отсутствие лишних переменных

Exceptions
std::invalid_argumentв том случае, если ввод инвалиден

Вектор, со всеми разреш. лекс., обозначающими элем. мат. функции

Символ, обозначающий текущую лексему

Символ, обозначающий следующую лексему

135 {
136 /// @brief Вектор, со всеми разреш. лекс., обозначающими элем. мат. функции
137 const vector<string> functions{"sin", "cos", "tan", "exp", "ln", "um"};
138
139 for (size_t i = 0; i < lexs.size(); i++) {
140 // string l = lexs[i];
141 /// @brief Символ, обозначающий текущую лексему
142 char l_c = s_to_c(lexs[i]);
143
144 /// @brief Символ, обозначающий следующую лексему
145 char n_c = ' ';
146
147 // (вычисление этого символа)
148 if (i < (lexs.size() - 1)) n_c = s_to_c(lexs[i + 1]);
149
150 // FIXME: дальше какая-то дичь творится..
151
152 // проверка использования постороннего имени
153 if (isalpha(l_c) && !(is_double(lexs[i]))) {
154 if (c_in_s(l_c, math_func_chars)) {
155 size_t j = math_func_chars.find(l_c);
156 if (lexs[i] != functions[j]) {
157 if (lexs.size() > 1) {
158 // если есть скобка, то это посторонняя элем. мат. функция
159 if (lexs[i + 1] == "(")
160 throw invalid_argument("invalid function name '" + lexs[i] + "'");
161 else
162 throw invalid_argument("extra variable '" + lexs[i] + "'");
163 } else
164 throw invalid_argument("extra variable '" + lexs[i] + "'");
165 }
166 // ситуации рода: tan | x + tan
167 else if (l_c != uminus && (lexs.size() < 4 || i == lexs.size() - 1))
168 throw invalid_argument("wrong function usage");
169
170 // ситуация рода: x + tan + x
171 else if (l_c != uminus && n_c != open_br)
172 throw invalid_argument("wrong function usage");
173 } else if (l_c != var_x) // если имя начинается не с разрешенной буквы и
174 // не является x, то оно постороннее
175 throw invalid_argument("extra variable '" + string{l_c} + "'");
176
177 else if (l_c == var_x) {
178 if (lexs.size() > 1 && i != lexs.size() - 1) {
179 // если есть скобка, то это посторонняя элем. мат. функция
180 // (ситуация рода: "x(x)")
181 if (lexs[i + 1] == "(")
182 throw invalid_argument("invalid function name '" + lexs[i] + "'");
183 }
184 // ситуация рода: "xx"
185 if (lexs[i].size() > 1)
186 throw invalid_argument("extra variable '" + lexs[i] + "'");
187 }
188 }
189 }
190}
constexpr char open_br
Definition constants.h:15
bool is_double(const std::string &str)
Definition utilities.cpp:18
Here is the call graph for this function:
Here is the caller graph for this function:

◆ func_str_validation()

void Math_func::function::func_str_validation ( ) const
private

Проверяет мат. функцию в виде строки, на валидность

Правильное кол-во скобок, отсутствие лишних символов, правильное использование знаков, точек, цифр)

Exceptions
std::invalid_argumentв том случае, если ввод инвалиден

Строка со всеми разрешенными символами

Строка с разрешенными мат. операциями

Счетчик незакрытых скобочек

Текущий символ

Предыдущий символ

Следующий символ

Строка с почти всеми символами, которые могут быть возле цифры

Левый (предыдущий) символ валиден

Правый (следующий) символ валиден

21 {
22 // проверка на пустую строку
23 if (func_str == "") throw invalid_argument("empty expression");
24
25 /// @brief Строка со всеми разрешенными символами
26 const string calc_chars = ".1234567890+-*/^()cosinexptal";
27 /// @brief Строка с разрешенными мат. операциями
28 const string math_oper_chars = "+-*/^";
29
30 // проверка на количество скобочек
31 if (count(func_str.begin(), func_str.end(), open_br) !=
32 count(func_str.begin(), func_str.end(), closed_br))
33 throw invalid_argument("brackets number mismatch");
34
35 // первый и последний символы не должны быть знаками или точками
36 // (кроме минуса спереди)
37 if ((c_in_s(func_str[0], math_oper_chars + point) && func_str[0] != minus) ||
39 throw invalid_argument("invalid syntax at edges");
40
41 /// @brief Счетчик незакрытых скобочек
42 int count_brackets = 0;
43
44 // проходимся по всей строке
45 for (size_t i = 0; i < func_str.size(); i++) {
46 /// @brief Текущий символ
47 char c = func_str[i];
48
49 /// @brief Предыдущий символ
50 char p_c = ' ';
51
52 /// @brief Следующий символ
53 char n_c = ' ';
54
55 // (вычисление значений этих символов)
56 if (i > 0) p_c = func_str[i - 1];
57 if (i < (func_str.size() - 1)) n_c = func_str[i + 1];
58
59 // проверка на отсутствие лишних символов
60 if (!c_in_s(c, calc_chars)) {
61 if (isalpha(c))
62 throw invalid_argument("extra variable '" + string{c} + "'");
63 else
64 throw invalid_argument("unknown character '" + string{c} + "'");
65 }
66
67 // возле знака операции не должно быть других операций и точек,
68 // а также открытой скобки слева или закрытой скобки справа
69 // (минус на это мы не проверяем, так как он может быть унарный)
70 if (c_in_s(c, math_oper_chars) && c != minus) {
71 if ((c_in_s(p_c, math_oper_chars + point) ||
72 c_in_s(n_c, math_oper_chars + point)) &&
73 n_c != minus) // но после знака минус стоять может
74 throw invalid_argument("invalid syntax near sign");
75
76 // минус не может стоять по обе стороны от знака
77 else if (p_c == minus && n_c == minus)
78 throw invalid_argument("invalid syntax near sign");
79
80 // проверка на правильность скобок возле знака
81 if (p_c == open_br || n_c == closed_br)
82 throw invalid_argument("invalid brackets near sign");
83 }
84
85 // возле точки должны быть только числа
86 if (c == point) {
87 if ((!isdigit(p_c) || !isdigit(n_c)))
88 throw invalid_argument("invalid syntax near point");
89 }
90
91 // считаем скобки
92 else if (c == open_br) {
93 count_brackets += 1;
94 // и проверяем, что нету пустых
95 if (n_c == closed_br) throw invalid_argument("empty brackets");
96 } else if (c == closed_br) {
97 count_brackets -= 1;
98 // случай, когда после очередной закрытой скобки
99 // - закрытых скобок оказывается больше
100 if (count_brackets < 0) throw invalid_argument("extra bracket");
101 }
102
103 // возле числа должен стоять либо знак, либо точка, либо скобка
104 // (при строке из одной цифры, эта проверка не подходит)
105 else if (isdigit(c) && func_str.size() > 1) {
106 /// @brief Строка с почти всеми символами, которые могут быть возле цифры
107 // (почти, так как еще скобки с разных сторон, но мы их считаем далее)
108 string valid_chars_near_digit = "0123456789" + math_oper_chars + point;
109
110 /// @brief Левый (предыдущий) символ валиден
111 // (у цифры слева может быть: цифра, точка, знак или открытая скобка)
112 bool is_left_valid = 1;
113
114 /// @brief Правый (следующий) символ валиден
115 // (у цифры справа может быть: цифра, точка, знак или закрытая скобка)
116 bool is_right_valid = 1;
117
118 // (вычисление значений этих флагов)
119 if (i == 0)
120 is_right_valid = c_in_s(n_c, valid_chars_near_digit + closed_br);
121 else if (i == func_str.size() - 1)
122 is_left_valid = c_in_s(p_c, valid_chars_near_digit + open_br);
123 else {
124 is_right_valid = c_in_s(n_c, valid_chars_near_digit + closed_br);
125 is_left_valid = c_in_s(p_c, valid_chars_near_digit + open_br);
126 }
127
128 // если хотя бы с одной стороны мы имеем не валидный символ
129 if (!is_left_valid || !is_right_valid)
130 throw invalid_argument("invalid syntax near digit");
131 }
132 }
133}
constexpr char point
Definition constants.h:9
constexpr char closed_br
Definition constants.h:16
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_func_str()

std::string Math_func::function::get_func_str ( ) const
inline

Возвращает значение мат. функции в виде строки

Returns
std::string: строка
59{ return func_str; }
Here is the caller graph for this function:

◆ has_var()

bool Math_func::function::has_var ( ) const
38{ return c_in_s('x', func_str); }
Here is the call graph for this function:

◆ lexemes()

vector< string > Math_func::function::lexemes ( ) const
private

Текущая лексема

Текущий символ строки

40 {
42
43 vector<string> res;
44
45 /// @brief Текущая лексема
46 string lex;
47
48 // TODO: написать комментарии по работе этого цикла
49
50 for (size_t i = 0; i < func_str.size(); i++) {
51 /// @brief Текущий символ строки
52 char ch = func_str[i];
53 switch (ch) {
54 case minus: {
55 if (lex.size() > 0) {
56 res.push_back(lex);
57 lex = "";
58 }
59 if (i == 0)
60 res.push_back("um");
61 else if (c_in_s(s_to_c(res[res.size() - 1]),
62 math_oper_chars + "(" + "u"))
63 res.push_back("um");
64 else
65 res.push_back("-");
66 break;
67 }
68 case open_br:
69 case closed_br:
70 case plus:
71 case mul:
72 case divi:
73 case power: {
74 if (lex.size() > 0) {
75 res.push_back(lex);
76 lex = "";
77 }
78 lex = ch;
79 res.push_back(lex);
80 lex = "";
81 break;
82 }
83 case point:
84 case '0':
85 case '1':
86 case '2':
87 case '3':
88 case '4':
89 case '5':
90 case '6':
91 case '7':
92 case '8':
93 case '9': {
94 if (lex.size() > 0 && !isdigit(lex[0])) {
95 res.push_back(lex);
96 lex = "";
97 }
98 lex += ch;
99 break;
100 }
101 default: {
102 if (!isblank(ch)) {
103 if (lex.size() > 0 && isdigit(lex[0])) {
104 res.push_back(lex);
105 lex = "";
106 }
107 lex += ch;
108 }
109 }
110 }
111 }
112 if (lex.size() > 0) res.push_back(lex);
113 return (res);
114}
void func_str_validation() const
Проверяет мат. функцию в виде строки, на валидность
Definition function_validation.cpp:21
Here is the call graph for this function:

◆ operator()()

double Math_func::function::operator() ( double x) const
inline

: Значение мат. функции

Parameters
x
Returns
double
42{ return calc(x); }
double calc(double x) const
Значение мат. функции
Definition function.cpp:223
Here is the call graph for this function:

◆ operator=()

function & Math_func::function::operator= ( const function & func)
28 {
29 if (this != &func) {
30 func_str = func.func_str;
31 lexs = func.lexs;
32 rev_pol = func.rev_pol;
33 }
34
35 return *this;
36}

◆ reverse_polish()

vector< string > Math_func::function::reverse_polish ( ) const
private

Вектор, куда записывается итоговая обратная польская запись

Стек с записанными операциями

Символ, обозначающий текущую лексему

Символ, обозначающий последний элемент в стеке с операциями

116 {
118
119 /// @brief Вектор, куда записывается итоговая обратная польская запись
120 vector<string> res;
121
122 /// @brief Стек с записанными операциями
123 // (нужен для хранения операций в правильном порядке)
124 stack<string> st_oper;
125 st_oper.push("\0");
126
127 for (const auto& lex : lexs) {
128 /// @brief Символ, обозначающий текущую лексему
129 // (нужен для switch-case)
130 char l_c = s_to_c(lex);
131
132 /// @brief Символ, обозначающий последний элемент в стеке с операциями
133 char last = s_to_c(st_oper.top());
134
135 // TODO: написать комментарии по работе этого свитча
136
137 switch (l_c) {
138 case number:
139 case var_x: {
140 res.push_back(lex);
141 if (st_oper.size() > 0 && last == uminus) {
142 res.push_back(st_oper.top());
143 st_oper.pop();
144 }
145 break;
146 }
147
148 case power: {
149 while (last == power || c_in_s(last, math_func_chars)) {
150 res.push_back(st_oper.top());
151 st_oper.pop();
152 last = s_to_c(st_oper.top());
153 }
154 st_oper.push(lex);
155 break;
156 }
157
158 case mul:
159 case divi: {
160 while (last == mul || last == divi || last == power ||
161 c_in_s(last, math_func_chars)) {
162 res.push_back(st_oper.top());
163 st_oper.pop();
164 last = s_to_c(st_oper.top());
165 }
166 st_oper.push(lex);
167 break;
168 }
169
170 case plus:
171 case minus: {
172 while (c_in_s(last, math_oper_chars) || c_in_s(last, math_func_chars)) {
173 res.push_back(st_oper.top());
174 st_oper.pop();
175 last = s_to_c(st_oper.top());
176 }
177 st_oper.push(lex);
178 break;
179 }
180
181 case open_br: {
182 st_oper.push(lex);
183 break;
184 }
185
186 case closed_br: {
187 while (true) {
188 if (last == open_br) {
189 st_oper.pop();
190 break;
191 } else {
192 res.push_back(st_oper.top());
193 st_oper.pop();
194 }
195 last = s_to_c(st_oper.top());
196 }
197 break;
198 }
199 case c_sin:
200 case c_cos:
201 case c_tan:
202 case c_exp:
203 case c_ln:
204 case uminus: {
205 st_oper.push(lex);
206 break;
207 }
208 default: {
209 throw std::runtime_error("Oops");
210 break;
211 }
212 }
213 }
214
215 // перевод оставшихся в стеке знаков в обратную польскую запись
216 while (st_oper.top() != "\0") {
217 res.push_back(st_oper.top());
218 st_oper.pop();
219 }
220 return res;
221}
void func_lexs_validation() const
Проверяет вектор лексем от мат. функции на валидность
Definition function_validation.cpp:135
Here is the call graph for this function:

Member Data Documentation

◆ calculate

const std::function<double(double)> Math_func::function::calculate
Initial value:
= [this](double x) {
return calc(x);
}

Значение мат. функции

33 {
34 return calc(x);
35 };

◆ differentiate

const std::function<double(double)> Math_func::function::differentiate
Initial value:
= [this](double x) {
}
constexpr double delta_x
"Сколь угодно малое" приращение x
Definition constants.h:34

Значение производной мат. функции

45 {
46 return (calc(x + Backend_consts::delta_x) -
49 };

◆ func_str

std::string Math_func::function::func_str
private

Мат. функция в виде строки

◆ lexs

std::vector<std::string> Math_func::function::lexs
private

Вектор лексем от мат. функции

◆ rev_pol

std::vector<std::string> Math_func::function::rev_pol
private

Вектор лексем, записанный в обратной польской нотации


The documentation for this class was generated from the following files: