213 lines
6.8 KiB
C++
Executable File
213 lines
6.8 KiB
C++
Executable File
#include <cmath>
|
||
#include <stdexcept>
|
||
#include "calculator.h"
|
||
#include "./ui_calculator.h"
|
||
|
||
Calculator::Calculator(QWidget *parent)
|
||
: QMainWindow(parent), ui(new Ui::Calculator)
|
||
{
|
||
ui->setupUi(this);
|
||
connect(ui->buttonAdd, &QPushButton::clicked, this, &Calculator::operationClicked);
|
||
connect(ui->buttonSubtract, &QPushButton::clicked, this, &Calculator::operationClicked);
|
||
connect(ui->buttonMultiply, &QPushButton::clicked, this, &Calculator::operationClicked);
|
||
connect(ui->buttonDivide, &QPushButton::clicked, this, &Calculator::operationClicked);
|
||
connect(ui->buttonSin, &QPushButton::clicked, this, &Calculator::trigonometricOperationClicked);
|
||
connect(ui->buttonCos, &QPushButton::clicked, this, &Calculator::trigonometricOperationClicked);
|
||
connect(ui->buttonTan, &QPushButton::clicked, this, &Calculator::trigonometricOperationClicked);
|
||
connect(ui->buttonCot, &QPushButton::clicked, this, &Calculator::trigonometricOperationClicked);
|
||
connect(ui->buttonArcsin, &QPushButton::clicked, this, &Calculator::trigonometricOperationClicked);
|
||
connect(ui->buttonArccos, &QPushButton::clicked, this, &Calculator::trigonometricOperationClicked);
|
||
connect(ui->buttonArctan, &QPushButton::clicked, this, &Calculator::trigonometricOperationClicked);
|
||
}
|
||
|
||
Calculator::~Calculator()
|
||
{
|
||
delete ui;
|
||
}
|
||
|
||
double Calculator::performOperation(double num1, double num2, const string &operation)
|
||
{
|
||
if (operation == "+")
|
||
return num1 + num2;
|
||
if (operation == "-")
|
||
return num1 - num2;
|
||
if (operation == "*")
|
||
return num1 * num2;
|
||
if (operation == "/")
|
||
{
|
||
if (num2 == 0)
|
||
{
|
||
throw invalid_argument("Деление на ноль.");
|
||
}
|
||
return num1 / num2;
|
||
}
|
||
throw invalid_argument("Неизвестная операция.");
|
||
}
|
||
|
||
double Calculator::validateTrigonometricInput(double value, const string &function)
|
||
{
|
||
if (function == "ARCSIN" || function == "ARCCOS" || function == "ARCTAN")
|
||
{
|
||
if (value < -1 || value > 1)
|
||
{
|
||
throw invalid_argument("Ввод вне диапазона для arcsin/arccos/arctan.");
|
||
}
|
||
}
|
||
return value;
|
||
}
|
||
|
||
double Calculator::convertToRadians(double value)
|
||
{
|
||
return value * M_PI / 180.0;
|
||
}
|
||
|
||
double Calculator::convertToDegrees(double value)
|
||
{
|
||
return value * 180.0 / M_PI;
|
||
}
|
||
|
||
bool Calculator::useRadians()
|
||
{
|
||
return ui->radioButtonRadians->isChecked();
|
||
}
|
||
|
||
double Calculator::handleSpecialAngles(double value, const string &function)
|
||
{
|
||
if (useRadians())
|
||
{
|
||
value = convertToDegrees(value);
|
||
}
|
||
|
||
if (fmod(value, 360.0) == 0.0)
|
||
{
|
||
if (function == "SIN") return 0.0;
|
||
if (function == "COS") return 1.0;
|
||
if (function == "TAN") return 0.0;
|
||
if (function == "COT") throw invalid_argument("Котангенс не определен.");
|
||
}
|
||
else if (fmod(value, 90.0) == 0.0 && fmod(value, 180.0) != 0.0)
|
||
{
|
||
if (function == "SIN") return 1.0;
|
||
if (function == "COS") return 0.0;
|
||
if (function == "TAN") throw invalid_argument("Тангенс не определен.");
|
||
if (function == "COT") return 0.0;
|
||
}
|
||
else if (fmod(value, 180.0) == 0.0)
|
||
{
|
||
if (function == "SIN") return 0.0;
|
||
if (function == "COS") return -1.0;
|
||
if (function == "TAN") return 0.0;
|
||
if (function == "COT") throw invalid_argument("Котангенс не определен.");
|
||
}
|
||
else if (fmod(value, 270.0) == 0.0)
|
||
{
|
||
if (function == "SIN") return -1.0;
|
||
if (function == "COS") return 0.0;
|
||
if (function == "TAN") throw invalid_argument("Тангенс не определен.");
|
||
if (function == "COT") return 0.0;
|
||
}
|
||
|
||
return nan("");
|
||
}
|
||
|
||
void Calculator::operationClicked()
|
||
{
|
||
QPushButton *clickedButton = qobject_cast<QPushButton *>(sender());
|
||
string operation = clickedButton->text().toStdString();
|
||
double num1 = ui->firstNumberInput->text().toDouble();
|
||
double num2 = ui->secondNumberInput->text().toDouble();
|
||
try
|
||
{
|
||
double result = performOperation(num1, num2, operation);
|
||
|
||
if (std::isnan(result))
|
||
{
|
||
ui->plainTextEdit->setText("Не число (NaN).");
|
||
}
|
||
else if (std::isinf(result))
|
||
{
|
||
ui->plainTextEdit->setText("Бесконечность.");
|
||
}
|
||
else
|
||
{
|
||
ui->plainTextEdit->setText(QString::number(result));
|
||
}
|
||
}
|
||
catch (const invalid_argument &e)
|
||
{
|
||
ui->plainTextEdit->setText(e.what());
|
||
}
|
||
}
|
||
|
||
void Calculator::trigonometricOperationClicked()
|
||
{
|
||
QPushButton *clickedButton = qobject_cast<QPushButton *>(sender());
|
||
string function = clickedButton->text().toStdString();
|
||
double value = ui->firstNumberInput->text().toDouble();
|
||
try
|
||
{
|
||
double specialValue = handleSpecialAngles(value, function);
|
||
if (!std::isnan(specialValue))
|
||
{
|
||
ui->plainTextEdit->setText(QString::number(specialValue));
|
||
return;
|
||
}
|
||
|
||
if (!useRadians() && function != "ARCSIN" && function != "ARCCOS" && function != "ARCTAN")
|
||
{
|
||
value = convertToRadians(value);
|
||
}
|
||
|
||
if (function == "SIN")
|
||
value = sin(value);
|
||
else if (function == "COS")
|
||
value = cos(value);
|
||
else if (function == "TAN")
|
||
{
|
||
if (fmod(value, M_PI / 2) == 0 && fmod(value, M_PI) != 0)
|
||
{
|
||
throw invalid_argument("Тангенс не определен.");
|
||
}
|
||
value = tan(value);
|
||
}
|
||
else if (function == "COT")
|
||
{
|
||
if (fmod(value, M_PI) == 0)
|
||
{
|
||
throw invalid_argument("Котангенс не определен.");
|
||
}
|
||
value = 1 / tan(value);
|
||
}
|
||
else if (function == "ARCSIN")
|
||
value = asin(validateTrigonometricInput(value, function));
|
||
else if (function == "ARCCOS")
|
||
value = acos(validateTrigonometricInput(value, function));
|
||
else if (function == "ARCTAN")
|
||
value = atan(validateTrigonometricInput(value, function));
|
||
else
|
||
throw invalid_argument("Неизвестная тригонометрическая функция.");
|
||
|
||
if (!useRadians() && (function == "ARCSIN" || function == "ARCCOS" || function == "ARCTAN"))
|
||
{
|
||
value = convertToDegrees(value);
|
||
}
|
||
|
||
if (std::isnan(value))
|
||
{
|
||
ui->plainTextEdit->setText("Не число (NaN).");
|
||
}
|
||
else if (std::isinf(value))
|
||
{
|
||
ui->plainTextEdit->setText("Бесконечность.");
|
||
}
|
||
else
|
||
{
|
||
ui->plainTextEdit->setText(QString::number(value));
|
||
}
|
||
}
|
||
catch (const invalid_argument &e)
|
||
{
|
||
ui->plainTextEdit->setText(e.what());
|
||
}
|
||
}
|