Upload to git
This commit is contained in:
+157
@@ -0,0 +1,157 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "pow.h"
|
||||
#include "rational.h"
|
||||
|
||||
// Все ошибки вычислений
|
||||
using Error = std::string;
|
||||
|
||||
namespace calculator_detail {
|
||||
|
||||
// Сравнивает значение с 0
|
||||
template<class Number>
|
||||
bool IsZero(const Number& value) {
|
||||
return value == Number{};
|
||||
}
|
||||
|
||||
// Вынесение 0 в отдельную перегрузку для Rational
|
||||
inline bool IsZero(const Rational& value) {
|
||||
return value == Rational{};
|
||||
}
|
||||
|
||||
// Преобразует число в текст для отображения на экране
|
||||
template<class Number>
|
||||
std::string NumberToString(const Number& value) {
|
||||
std::ostringstream out;
|
||||
out << value;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
// Вывод uint8_t как число
|
||||
inline std::string NumberToString(std::uint8_t value) {
|
||||
std::ostringstream out;
|
||||
out << +value;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<class Number>
|
||||
class Calculator {
|
||||
public:
|
||||
// Устанавливает новое текущее значение
|
||||
void Set(Number value) {
|
||||
current_ = value;
|
||||
}
|
||||
|
||||
// Возвращает текущее значение
|
||||
Number GetNumber() const {
|
||||
return current_;
|
||||
}
|
||||
|
||||
// Сложение
|
||||
std::optional<Error> Add(Number value) {
|
||||
current_ += value;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Вычитание
|
||||
std::optional<Error> Sub(Number value) {
|
||||
current_ -= value;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Умножение
|
||||
std::optional<Error> Mul(Number value) {
|
||||
current_ *= value;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Деление провряет 0 только для типов без NaN
|
||||
std::optional<Error> Div(Number value) {
|
||||
if constexpr (std::is_integral_v<Number> || std::is_same_v<Number, Rational>) {
|
||||
if (calculator_detail::IsZero(value)) {
|
||||
return "Division by zero";
|
||||
}
|
||||
}
|
||||
|
||||
current_ /= value;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Возведение в степень выбирает нужную функцию и проверяет ошибки
|
||||
std::optional<Error> Pow(Number value) {
|
||||
if constexpr (std::is_floating_point_v<Number>) {
|
||||
current_ = ::Pow(current_, value);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (calculator_detail::IsZero(current_) && calculator_detail::IsZero(value)) {
|
||||
return "Zero power to zero";
|
||||
}
|
||||
|
||||
if constexpr (std::is_integral_v<Number>) {
|
||||
if constexpr (std::is_signed_v<Number>) {
|
||||
if (value < 0) {
|
||||
return "Integer negative power";
|
||||
}
|
||||
}
|
||||
|
||||
current_ = ::Pow(current_, value);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<Number, Rational>) {
|
||||
if (value.GetDenominator() != 1) {
|
||||
return "Fractional power is not supported";
|
||||
}
|
||||
if (calculator_detail::IsZero(current_) && value.GetNumerator() < 0) {
|
||||
return "Division by zero";
|
||||
}
|
||||
|
||||
current_ = ::Pow(current_, value);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Сохраняет текущее значение в память
|
||||
void Save() {
|
||||
mem_ = current_;
|
||||
}
|
||||
|
||||
// Загружает текущее значение из памяти
|
||||
void Load() {
|
||||
if (mem_) {
|
||||
current_ = *mem_;
|
||||
}
|
||||
}
|
||||
|
||||
// Очищает память калькулятора
|
||||
void ClearMem() {
|
||||
mem_ = std::nullopt;
|
||||
}
|
||||
|
||||
// Значение сохранено в памяти? Если Да выводить индикатор
|
||||
bool GetHasMem() const {
|
||||
return mem_.has_value();
|
||||
}
|
||||
|
||||
// Возвращает текущее значение в том же формате, что используется в интерфейсе
|
||||
std::string GetNumberRepr() const {
|
||||
return calculator_detail::NumberToString(current_);
|
||||
}
|
||||
|
||||
private:
|
||||
// Текущее значение
|
||||
Number current_ = {};
|
||||
// Ячейка памяти
|
||||
std::optional<Number> mem_ = std::nullopt;
|
||||
};
|
||||
Reference in New Issue
Block a user