Загрузка данных
// FormulaCalculator.cpp
#include "FormulaCalculator.h"
#include <QDebug>
#include <cmath>
#include <QMapIterator>
#include <QStringList>
// Token implementation
Token::Token(Type type, const QString& value) : m_type(type), m_value(value) {}
Token::Type Token::getType() const { return m_type; }
QString Token::getValue() const { return m_value; }
// CalculationResult implementation
CalculationResult::CalculationResult(double value, const QString& table)
: m_value(value), m_table(table) {}
double CalculationResult::getValue() const { return m_value; }
QString CalculationResult::getTable() const { return m_table; }
bool CalculationResult::hasTable() const { return !m_table.isEmpty(); }
// FormulaCalculator implementation
FormulaCalculator::FormulaCalculator() {
// Инициализация зависимостей (вариант 4 - Dependency)
m_variables = std::make_unique<QMap<QString, double>>();
m_functions = std::make_unique<QMap<QString, std::function<double(double)>>>();
m_binaryOperators = std::make_unique<QMap<QString, std::function<double(double, double)>>>();
// Регистрация стандартных функций из math.h
(*m_functions)["sin"] = [](double x) { return sin(x); };
(*m_functions)["cos"] = [](double x) { return cos(x); };
(*m_functions)["tan"] = [](double x) { return tan(x); };
(*m_functions)["asin"] = [](double x) { return asin(x); };
(*m_functions)["acos"] = [](double x) { return acos(x); };
(*m_functions)["atan"] = [](double x) { return atan(x); };
(*m_functions)["sinh"] = [](double x) { return sinh(x); };
(*m_functions)["cosh"] = [](double x) { return cosh(x); };
(*m_functions)["tanh"] = [](double x) { return tanh(x); };
(*m_functions)["exp"] = [](double x) { return exp(x); };
(*m_functions)["log"] = [](double x) { return log(x); };
(*m_functions)["log10"] = [](double x) { return log10(x); };
(*m_functions)["sqrt"] = [](double x) { return sqrt(x); };
(*m_functions)["fabs"] = [](double x) { return fabs(x); };
(*m_functions)["ceil"] = [](double x) { return ceil(x); };
(*m_functions)["floor"] = [](double x) { return floor(x); };
// Регистрация операторов
(*m_binaryOperators)["+"] = [](double a, double b) { return a + b; };
(*m_binaryOperators)["-"] = [](double a, double b) { return a - b; };
(*m_binaryOperators)["*"] = [](double a, double b) { return a * b; };
(*m_binaryOperators)["/"] = [](double a, double b) { return a / b; };
(*m_binaryOperators)["^"] = [](double a, double b) { return pow(a, b); };
}
FormulaCalculator::~FormulaCalculator() = default;
void FormulaCalculator::setVariable(const QString& name, double value) {
(*m_variables)[name] = value;
}
double FormulaCalculator::getVariable(const QString& name) const {
return m_variables->value(name, 0.0);
}
bool FormulaCalculator::hasVariable(const QString& name) const {
return m_variables->contains(name);
}
QMap<QString, double> FormulaCalculator::getAllVariables() const {
return *m_variables;
}
void FormulaCalculator::clearVariables() {
m_variables->clear();
}
bool FormulaCalculator::isNumber(const QString& token) const {
bool ok;
token.toDouble(&ok);
return ok;
}
bool FormulaCalculator::isVariable(const QString& token) const {
// Переменная должна начинаться с буквы и содержать только буквы, цифры и _
if (token.isEmpty() || !token[0].isLetter())
return false;
for (const QChar& ch : token) {
if (!ch.isLetterOrNumber() && ch != '_')
return false;
}
return true;
}
bool FormulaCalculator::isOperator(const QString& token) const {
return m_binaryOperators->contains(token);
}
bool FormulaCalculator::isFunction(const QString& token) const {
return m_functions->contains(token);
}
bool FormulaCalculator::isCommand(const QString& token) const {
return token == "table" || token == "clear";
}
bool FormulaCalculator::isSpecialSymbol(const QChar& ch) const {
return ch == '(' || ch == ')' || ch == ',' || ch == '=';
}
QVector<Token> FormulaCalculator::tokenize(const QString& formula) {
QVector<Token> tokens;
QString current;
int i = 0;
while (i < formula.length()) {
QChar ch = formula[i];
// Пропускаем пробелы
if (ch.isSpace()) {
i++;
continue;
}
// Числа (включая десятичные точки)
if (ch.isDigit() || ch == '.') {
current.clear();
while (i < formula.length() && (formula[i].isDigit() || formula[i] == '.' ||
formula[i] == 'e' || formula[i] == 'E' || formula[i] == '+' || formula[i] == '-')) {
if ((formula[i] == '+' || formula[i] == '-') && !current.isEmpty() &&
!current.contains('e') && !current.contains('E')) {
break;
}
current += formula[i];
i++;
}
tokens.append(Token(Token::Type::NUMBER, current));
continue;
}
// Идентификаторы (переменные, функции, команды)
if (ch.isLetter()) {
current.clear();
while (i < formula.length() && (formula[i].isLetterOrNumber() || formula[i] == '_')) {
current += formula[i];
i++;
}
if (isCommand(current)) {
tokens.append(Token(Token::Type::COMMAND, current));
} else if (isFunction(current)) {
tokens.append(Token(Token::Type::FUNCTION, current));
} else if (isVariable(current)) {
tokens.append(Token(Token::Type::VARIABLE, current));
} else {
// Неизвестный идентификатор
tokens.append(Token(Token::Type::VARIABLE, current));
}
continue;
}
// Операторы и спецсимволы
if (isOperator(QString(ch)) || isSpecialSymbol(ch)) {
tokens.append(Token(Token::Type::OPERATOR, QString(ch)));
i++;
continue;
}
// Неизвестный символ
tokens.append(Token(Token::Type::SPECIAL, QString(ch)));
i++;
}
return tokens;
}
double FormulaCalculator::applyFunction(const QString& funcName, double arg) {
if (m_functions->contains(funcName)) {
return (*m_functions)[funcName](arg);
}
throw std::runtime_error("Unknown function: " + funcName.toStdString());
}
double FormulaCalculator::applyOperator(const QString& op, double left, double right) {
if (m_binaryOperators->contains(op)) {
return (*m_binaryOperators)[op](left, right);
}
throw std::runtime_error("Unknown operator: " + op.toStdString());
}
int FormulaCalculator::getPrecedence(const QString& op) const {
if (op == "+" || op == "-") return 1;
if (op == "*" || op == "/") return 2;
if (op == "^") return 3;
return 0;
}
bool FormulaCalculator::isRightAssociative(const QString& op) const {
return op == "^";
}
double FormulaCalculator::parseExpression(const QVector<Token>& tokens, int& pos) {
double left = parseTerm(tokens, pos);
while (pos < tokens.size()) {
Token token = tokens[pos];
if (token.getType() == Token::Type::OPERATOR) {
QString op = token.getValue();
if (op == "+" || op == "-") {
pos++;
double right = parseTerm(tokens, pos);
left = applyOperator(op, left, right);
continue;
}
}
break;
}
return left;
}
double FormulaCalculator::parseTerm(const QVector<Token>& tokens, int& pos) {
double left = parseFactor(tokens, pos);
while (pos < tokens.size()) {
Token token = tokens[pos];
if (token.getType() == Token::Type::OPERATOR) {
QString op = token.getValue();
if (op == "*" || op == "/") {
pos++;
double right = parseFactor(tokens, pos);
left = applyOperator(op, left, right);
continue;
}
}
break;
}
return left;
}
double FormulaCalculator::parseFactor(const QVector<Token>& tokens, int& pos) {
if (pos >= tokens.size()) {
throw std::runtime_error("Unexpected end of expression");
}
Token token = tokens[pos];
pos++;
if (token.getType() == Token::Type::NUMBER) {
return token.getValue().toDouble();
}
if (token.getType() == Token::Type::VARIABLE) {
QString varName = token.getValue();
if (hasVariable(varName)) {
return getVariable(varName);
}
throw std::runtime_error("Undefined variable: " + varName.toStdString());
}
if (token.getType() == Token::Type::FUNCTION) {
if (pos < tokens.size() && tokens[pos].getValue() == "(") {
pos++; // пропускаем (
double arg = parseExpression(tokens, pos);
if (pos < tokens.size() && tokens[pos].getValue() == ")") {
pos++; // пропускаем )
return applyFunction(token.getValue(), arg);
}
}
throw std::runtime_error("Invalid function syntax");
}
if (token.getType() == Token::Type::OPERATOR && token.getValue() == "(") {
double expr = parseExpression(tokens, pos);
if (pos < tokens.size() && tokens[pos].getValue() == ")") {
pos++;
return expr;
}
throw std::runtime_error("Missing closing parenthesis");
}
if (token.getType() == Token::Type::OPERATOR && token.getValue() == "-") {
return -parseFactor(tokens, pos);
}
throw std::runtime_error("Unexpected token: " + token.getValue().toStdString());
}
double FormulaCalculator::evaluate(const QVector<Token>& tokens, CalculationResult& result) {
int pos = 0;
double value = parseExpression(tokens, pos);
// Проверка на команды в конце
while (pos < tokens.size()) {
if (tokens[pos].getType() == Token::Type::COMMAND) {
QString cmd = tokens[pos].getValue();
if (cmd == "table") {
// Ожидается таблица для переменной x
// Формат: выражение table x start end steps
// Упрощенная реализация
result = CalculationResult(value, generateTable("x", "x", -10, 10, 20));
} else if (cmd == "clear") {
clearVariables();
}
}
pos++;
}
return value;
}
QString FormulaCalculator::generateTable(const QString& formula, const QString& variable,
double start, double end, int steps) {
QString table;
table += QString("Table for %1 from %2 to %3 (%4 steps):\n")
.arg(formula).arg(start).arg(end).arg(steps);
table += "----------------------------------------\n";
table += QString("%1\t|\tValue\n").arg(variable);
table += "----------------------------------------\n";
double step = (end - start) / steps;
for (int i = 0; i <= steps; i++) {
double x = start + i * step;
// Сохраняем текущее значение переменной
double oldValue = getVariable(variable);
setVariable(variable, x);
try {
QVector<Token> tokens = tokenize(formula);
CalculationResult tempResult;
double result = evaluate(tokens, tempResult);
table += QString("%1\t|\t%2\n").arg(x).arg(result);
} catch (const std::exception& e) {
table += QString("%1\t|\tError: %2\n").arg(x).arg(e.what());
}
// Восстанавливаем значение
if (oldValue != 0.0 || hasVariable(variable)) {
setVariable(variable, oldValue);
} else {
clearVariables();
}
}
return table;
}
CalculationResult FormulaCalculator::parseAndCalculate(const QString& formula) {
try {
QVector<Token> tokens = tokenize(formula);
CalculationResult result;
double value = evaluate(tokens, result);
if (!result.hasTable()) {
result = CalculationResult(value);
}
return result;
} catch (const std::exception& e) {
return CalculationResult(0.0, QString("Error: %1").arg(e.what()));
}
}