Загрузка данных


ef MATH_H
#define MATH_H

// ОТДЕЛЬНЫЙ ЗАГОЛОВОЧНЫЙ ФАЙЛ MATH.H ПО ЗАДАНИЮ

double math_sin(double x);
double math_cos(double x);
double math_sqrt(double x);
double math_pow(double x, double y);

#endif



#include "math.h"
#include <cmath>

double math_sin(double x) {
    return sin(x);
}

double math_cos(double x) {
    return cos(x);
}

double math_sqrt(double x) {
    if (x < 0) return 0;
    return sqrt(x);
}

double math_pow(double x, double y) {
    return pow(x, y);
}



#ifndef CALCULATOR_H
#define CALCULATOR_H

#include <QString>
#include <QMap>
#include "math.h"

// ЛЕКСЕМА (пункт 1)
struct Lexeme {
    QString type;
    QString value;
    int position;
};

// ПАРСЕР
class Parser {
public:
    double evaluate(const QString& expression, QMap<QString, double>& variables, QString& error);
};

// КАЛЬКУЛЯТОР С ЗАВИСИМОСТЬЮ (вариант 4)
class Calculator {
public:
    explicit Calculator(Parser* parser);
    
    bool setFormula(const QString& formula);
    bool compute(double x, double y);
    double getResult() const { return result; }
    QString getTable();
    QString getError() const { return errorMsg; }
    
    // Копирование и перемещение
    Calculator(const Calculator& other);
    Calculator(Calculator&& other) noexcept;
    Calculator& operator=(const Calculator& other);
    Calculator& operator=(Calculator&& other) noexcept;
    
private:
    Parser* parser;
    QString formula;
    double result;
    QString errorMsg;
    QMap<QString, double> variables;
};

#endif



#include "calculator.h"
#include <cmath>
#include <functional>

double Parser::evaluate(const QString& expr, QMap<QString, double>& vars, QString& error) {
    QString str = expr;
    
    // ПОДСТАНОВКА ПЕРЕМЕННЫХ
    for (auto it = vars.begin(); it != vars.end(); ++it) {
        str.replace(it.key(), "(" + QString::number(it.value()) + ")");
    }
    
    int pos = 0;
    
    auto skipSpaces = [&]() {
        while (pos < str.length() && str[pos].isSpace()) pos++;
    };
    
    auto readNumber = [&]() -> double {
        skipSpaces();
        int start = pos;
        while (pos < str.length() && (str[pos].isDigit() || str[pos] == '.')) pos++;
        if (start == pos) return 0;
        return str.mid(start, pos - start).toDouble();
    };
    
    auto readName = [&]() -> QString {
        skipSpaces();
        int start = pos;
        while (pos < str.length() && str[pos].isLetter()) pos++;
        return str.mid(start, pos - start);
    };
    
    std::function<double()> parseExpr;
    std::function<double()> parseTerm;
    std::function<double()> parseFactor;
    
    parseFactor = [&]() -> double {
        skipSpaces();
        if (pos >= str.length()) return 0;
        
        QChar ch = str[pos];
        
        if (ch.isDigit() || ch == '.') {
            return readNumber();
        }
        
        if (ch == '(') {
            pos++;
            double val = parseExpr();
            skipSpaces();
            if (pos < str.length() && str[pos] == ')') pos++;
            return val;
        }
        
        if (ch.isLetter()) {
            QString name = readName();
            
            // ФУНКЦИИ ИЗ MATH.H
            if (name == "sin" || name == "cos" || name == "sqrt" || name == "pow") {
                skipSpaces();
                if (pos < str.length() && str[pos] == '(') {
                    pos++;
                    double arg1 = parseExpr();
                    double arg2 = 0;
                    
                    skipSpaces();
                    if (name == "pow" && pos < str.length() && str[pos] == ',') {
                        pos++;
                        arg2 = parseExpr();
                    }
                    
                    skipSpaces();
                    if (pos < str.length() && str[pos] == ')') pos++;
                    
                    if (name == "sin") return math_sin(arg1);
                    if (name == "cos") return math_cos(arg1);
                    if (name == "sqrt") {
                        if (arg1 < 0) {
                            error = "Корень из отрицательного";
                            return 0;
                        }
                        return math_sqrt(arg1);
                    }
                    if (name == "pow") return math_pow(arg1, arg2);
                }
            }
            
            return vars.value(name, 0);
        }
        
        return 0;
    };
    
    parseTerm = [&]() -> double {
        double value = parseFactor();
        skipSpaces();
        while (pos < str.length() && (str[pos] == '*' || str[pos] == '/')) {
            char op = str[pos].toLatin1();
            pos++;
            double next = parseFactor();
            if (op == '*') value *= next;
            else if (op == '/') {
                if (next == 0) {
                    error = "Деление на ноль";
                    return 0;
                }
                value /= next;
            }
            skipSpaces();
        }
        return value;
    };
    
    parseExpr = [&]() -> double {
        double value = parseTerm();
        skipSpaces();
        while (pos < str.length() && (str[pos] == '+' || str[pos] == '-')) {
            char op = str[pos].toLatin1();
            pos++;
            double next = parseTerm();
            if (op == '+') value += next;
            else value -= next;
            skipSpaces();
        }
        return value;
    };
    
    return parseExpr();
}

// ============ CALCULATOR ============

Calculator::Calculator(Parser* p) : parser(p), result(0) {}

Calculator::Calculator(const Calculator& other)
    : parser(other.parser), formula(other.formula),
      result(other.result), errorMsg(other.errorMsg), variables(other.variables) {}

Calculator::Calculator(Calculator&& other) noexcept
    : parser(other.parser), formula(std::move(other.formula)),
      result(other.result), errorMsg(std::move(other.errorMsg)), variables(std::move(other.variables)) {
    other.parser = nullptr;
}

Calculator& Calculator::operator=(const Calculator& other) {
    if (this != &other) {
        parser = other.parser;
        formula = other.formula;
        result = other.result;
        errorMsg = other.errorMsg;
        variables = other.variables;
    }
    return *this;
}

Calculator& Calculator::operator=(Calculator&& other) noexcept {
    if (this != &other) {
        parser = other.parser;
        formula = std::move(other.formula);
        result = other.result;
        errorMsg = std::move(other.errorMsg);
        variables = std::move(other.variables);
        other.parser = nullptr;
    }
    return *this;
}

bool Calculator::setFormula(const QString& f) {
    formula = f;
    variables.clear();
    
    // ОПРЕДЕЛЕНИЕ ПЕРЕМЕННЫХ
    if (formula.contains("x")) variables["x"] = 0;
    if (formula.contains("y")) variables["y"] = 0;
    
    // ВЫДЕЛЕНИЕ КОМАНД
    if (formula.startsWith("calc ")) formula = formula.mid(5);
    if (formula.startsWith("table ")) formula = formula.mid(6);
    if (formula == "help") errorMsg = "Команды: sin, cos, sqrt, pow, +, -, *, /";
    
    errorMsg.clear();
    return true;
}

bool Calculator::compute(double x, double y) {
    if (!parser) {
        errorMsg = "Парсер не задан";
        return false;
    }
    
    variables["x"] = x;
    variables["y"] = y;
    result = parser->evaluate(formula, variables, errorMsg);
    return errorMsg.isEmpty();
}

QString Calculator::getTable() {
    QString table = "═══════════════════════════════════\n";
    table += "     ТАБЛИЦА ЗНАЧЕНИЙ (y = 1)\n";
    table += "═══════════════════════════════════════\n";
    table += "      x      │      F(x, y)\n";
    table += "─────────────┼─────────────────\n";
    
    for (int x = -5; x <= 5; x++) {
        Calculator temp = *this;
        Calculator moved = std::move(temp);
        
        if (moved.compute(x, 1.0)) {
            table += QString("     %1      │     %2\n").arg(x, 3).arg(moved.getResult(), 8, 'f', 4);
        } else {
            table += QString("     %1      │   ошибка\n").arg(x, 3);
        }
    }
    table += "═══════════════════════════════════════\n";
    
    return table;
}



#include <QCoreApplication>
#include <QTextStream>
#include "calculator.h"

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    QTextStream cin(stdin);
    QTextStream cout(stdout);
    
    cout << "\n╔══════════════════════════════════════╗\n";
    cout << "║     ФОРМЕННЫЙ КАЛЬКУЛЯТОР          ║\n";
    cout << "║     Вариант 4 - ЗАВИСИМОСТЬ        ║\n";
    cout << "╚══════════════════════════════════════╝\n\n";
    
    Parser parser;
    Calculator calc(&parser);
    
    cout << "Функции: sin, cos, sqrt, pow\n";
    cout << "Переменные: x, y\n";
    cout << "Операции: +, -, *, /, (, )\n\n";
    
    cout << "Введите формулу: ";
    cout.flush();
    QString formula;
    formula = cin.readLine();
    
    if (!calc.setFormula(formula)) {
        cout << "Ошибка: " << calc.getError() << "\n";
        return 1;
    }
    
    cout << "Введите x и y: ";
    double x, y;
    cin >> x >> y;
    
    if (calc.compute(x, y)) {
        cout << "\n▶ РЕЗУЛЬТАТ: " << calc.getResult() << "\n\n";
        cout << calc.getTable() << "\n";
    } else {
        cout << "Ошибка: " << calc.getError() << "\n";
    }
    
    return 0;
}



#include <QtTest>
#include "calculator.h"

class CalculatorTest : public QObject {
    Q_OBJECT

private slots:
    void testAddition() {
        Parser parser;
        Calculator calc(&parser);
        calc.setFormula("2+3");
        QVERIFY(calc.compute(0, 0));
        QCOMPARE(calc.getResult(), 5.0);
    }
    
    void testSin() {
        Parser parser;
        Calculator calc(&parser);
        calc.setFormula("sin(0)");
        QVERIFY(calc.compute(0, 0));
        QVERIFY(qAbs(calc.getResult() - 0.0) < 0.001);
    }
    
    void testCos() {
        Parser parser;
        Calculator calc(&parser);
        calc.setFormula("cos(0)");
        QVERIFY(calc.compute(0, 0));
        QVERIFY(qAbs(calc.getResult() - 1.0) < 0.001);
    }
    
    void testSqrt() {
        Parser parser;
        Calculator calc(&parser);
        calc.setFormula("sqrt(16)");
        QVERIFY(calc.compute(0, 0));
        QCOMPARE(calc.getResult(), 4.0);
    }
    
    void testPow() {
        Parser parser;
        Calculator calc(&parser);
        calc.setFormula("pow(2,3)");
        QVERIFY(calc.compute(0, 0));
        QCOMPARE(calc.getResult(), 8.0);
    }
    
    void testVariables() {
        Parser parser;
        Calculator calc(&parser);
        calc.setFormula("x + y");
        QVERIFY(calc.compute(3, 4));
        QCOMPARE(calc.getResult(), 7.0);
    }
    
    void testCopySemantics() {
        Parser parser;
        Calculator calc1(&parser);
        calc1.setFormula("x * 2");
        calc1.compute(5, 0);
        
        Calculator calc2 = calc1;
        calc2.compute(10, 0);
        
        QCOMPARE(calc2.getResult(), 20.0);
        QCOMPARE(calc1.getResult(), 10.0);
    }
    
    void testMoveSemantics() {
        Parser parser;
        Calculator calc1(&parser);
        calc1.setFormula("x * 3");
        calc1.compute(4, 0);
        
        Calculator calc2 = std::move(calc1);
        calc2.compute(5, 0);
        
        QCOMPARE(calc2.getResult(), 15.0);
    }
    
    void testTable() {
        Parser parser;
        Calculator calc(&parser);
        calc.setFormula("x");
        QString table = calc.getTable();
        QVERIFY(table.contains("x"));
        QVERIFY(table.contains("-5"));
    }
    
    void testDivisionByZero() {
        Parser parser;
        Calculator calc(&parser);
        calc.setFormula("5/0");
        QVERIFY(!calc.compute(0, 0));
        QVERIFY(!calc.getError().isEmpty());
    }
};

QTEST_APPLESS_MAIN(CalculatorTest)
#include "tst_calculatortest.moc"