#pragma once #include #include #include #include #include #include "pow.h" #include "rational.h" // Все ошибки вычислений using Error = std::string; namespace calculator_detail { // Сравнивает значение с 0 template bool IsZero(const Number& value) { return value == Number{}; } // Вынесение 0 в отдельную перегрузку для Rational inline bool IsZero(const Rational& value) { return value == Rational{}; } // Преобразует число в текст для отображения на экране template 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 Calculator { public: // Устанавливает новое текущее значение void Set(Number value) { current_ = value; } // Возвращает текущее значение Number GetNumber() const { return current_; } // Сложение std::optional Add(Number value) { current_ += value; return std::nullopt; } // Вычитание std::optional Sub(Number value) { current_ -= value; return std::nullopt; } // Умножение std::optional Mul(Number value) { current_ *= value; return std::nullopt; } // Деление провряет 0 только для типов без NaN std::optional Div(Number value) { if constexpr (std::is_integral_v || std::is_same_v) { if (calculator_detail::IsZero(value)) { return "Division by zero"; } } current_ /= value; return std::nullopt; } // Возведение в степень выбирает нужную функцию и проверяет ошибки std::optional Pow(Number value) { if constexpr (std::is_floating_point_v) { 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) { if constexpr (std::is_signed_v) { if (value < 0) { return "Integer negative power"; } } current_ = ::Pow(current_, value); return std::nullopt; } if constexpr (std::is_same_v) { 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 mem_ = std::nullopt; };