/**
* Copyright (c) 2024, Harry Huang
* @ MIT License
*/
#include <iostream>
#include <iomanip>
#include <cmath>
#include <string>
#include <sstream>
using namespace std;
namespace Calculator {
const long double MAX_NUM = LLONG_MAX;
const int MAX_DIGITS = (int)floor(log10(MAX_NUM)) - 2;
const int MAX_PRECISION = numeric_limits<long double>::digits10;
/**
* @brief Number status.
*/
enum NumberStatus {
ZERO_DIVISION = -2,
OVERFLOWED = -1,
NONE = 0,
OKAY = 1
};
/**
* @brief Wrapped long double number.
*/
struct Number {
public:
NumberStatus status;
long double value;
Number(NumberStatus status, long double value) {
this->status = status;
this->value = value;
}
Number(long double value) {
this->status = NumberStatus::OKAY;
this->value = value;
}
inline Number add(Number other) {
if (status != NumberStatus::OKAY || other.status != NumberStatus::OKAY) {
return Number(NumberStatus::NONE, 0);
}
long double a = value;
long double b = other.value;
bool of = (a > 0 && b > 0 && a > MAX_NUM - b) ||
(a < 0 && b < 0 && a < b - MAX_NUM);
return Number(of ? NumberStatus::OVERFLOWED : NumberStatus::OKAY, a + b);
}
inline Number minus(Number other) {
if (status != NumberStatus::OKAY || other.status != NumberStatus::OKAY) {
return Number(NumberStatus::NONE, 0);
}
long double a = value;
long double b = other.value;
bool of = (a > 0 && -b > 0 && a > MAX_NUM - -b) ||
(a < 0 && -b < 0 && a < MAX_NUM - -b);
return Number(of ? NumberStatus::OVERFLOWED : NumberStatus::OKAY, a - b);
}
inline Number multiply(Number other) {
if (status != NumberStatus::OKAY || other.status != NumberStatus::OKAY) {
return Number(NumberStatus::NONE, 0);
}
long double a = value;
long double b = other.value;
bool of = fabs(b) > fabs(MAX_NUM / a);
return Number(of ? NumberStatus::OVERFLOWED : NumberStatus::OKAY, a * b);
}
inline Number divide(Number other) {
if (status != NumberStatus::OKAY || other.status != NumberStatus::OKAY) {
return Number(NumberStatus::NONE, 0);
}
long double a = value;
long double b = other.value;
if (b == 0) {
return Number(NumberStatus::ZERO_DIVISION, 0);
}
bool of = fabs(b) < fabs(a / MAX_NUM);
return Number(of ? NumberStatus::OVERFLOWED : NumberStatus::OKAY, a / b);
}
inline string toString() {
if (value == 0) {
return "0";
}
int intDigits = max(0, (int)floor(log10(fabs(value)))) + 1;
int precision = max(0, MAX_PRECISION - intDigits);
ostringstream oss;
oss << fixed << setprecision(precision) << value;
string formatted = oss.str();
int dotIdx = formatted.find('.');
if (dotIdx != std::string::npos) {
int lastNonZero = formatted.find_last_not_of('0');
if (lastNonZero == dotIdx) {
formatted.erase(dotIdx);
}
else {
formatted.erase(lastNonZero + 1);
}
}
return formatted;
}
};
/**
* @brief Char-by-char number parser.
*/
struct NumberReader {
private:
long long value;
int digitLeft;
int digitRight;
bool isStarted;
bool isEnded;
bool isNegative;
bool isDecimal;
public:
NumberReader() {
value = 0;
digitLeft = 0;
digitRight = 0;
isStarted = false;
isEnded = false;
isNegative = false;
isDecimal = false;
}
inline bool read(char c) {
if (c == ' ') {
flush();
return true;
}
if (!isEnded) {
if ('0' <= c && c <= '9') {
value = value * 10 + (c - '0');
digitLeft += !isDecimal;
digitRight += isDecimal;
isStarted = true;
return true;
}
if (c == '.' && !isDecimal) {
isDecimal = true;
isStarted = true;
return true;
}
if (c == '-' && !isStarted) {
isNegative = !isNegative;
return true;
}
}
return false;
}
inline bool flush() {
if (isStarted) {
isEnded = true;
}
return isEnded;
}
inline bool isFlushed() {
return isStarted && isEnded;
}
inline bool isOverflowed() {
return digitLeft + digitRight > MAX_DIGITS;
}
inline Number get() {
long double rst = value;
for (int i = 0; i < digitRight; i++) {
rst /= 10.0;
}
if (isNegative) {
rst = -rst;
}
return Number(isOverflowed() ? NumberStatus::OVERFLOWED : NumberStatus::OKAY, rst);
}
};
/**
* @brief The type indicator for Expression.
*/
enum ExpressionType {
ERR_OVERFLOW = -3,
ERR_SYNTAX = -2,
EXIT = -1,
UNSET = 0,
OP_ADD = 1,
OP_MINUS = 2,
OP_MULTIPLY = 3,
OP_DIVIDE = 4,
MEM_ADD = 5,
MEM_MINUS = 6,
MEM_CLEAR = 7,
MEM_RECALL = 8
};
/**
* @brief The expression parser for input streams.
*/
struct Expression {
public:
ExpressionType type;
NumberReader num1;
NumberReader num2;
Expression(istream& is) {
type = ExpressionType::UNSET;
num1 = NumberReader();
num2 = NumberReader();
char input[1024];
is.getline(input, 1024);
int inputLen = strlen(input);
for (int i = 0; i < inputLen; i++) {
char c = input[i];
char nextC = i + 1 < inputLen ? input[i + 1] : '\0';
if (!num1.read(c) && !(num1.flush() && num2.read(c))) {
switch (c) {
case '+':
case '-':
case '*':
case '/':
if (type || !num1.flush()) {
type = ExpressionType::ERR_SYNTAX;
return;
}
switch (c) {
case '+':
type = ExpressionType::OP_ADD;
break;
case '-':
type = ExpressionType::OP_MINUS;
break;
case '*':
type = ExpressionType::OP_MULTIPLY;
break;
case '/':
type = ExpressionType::OP_DIVIDE;
break;
}
break;
case ' ':
case '\t':
break;
case '#':
if (type) {
type = ExpressionType::ERR_SYNTAX;
return;
}
type = ExpressionType::EXIT;
yanglamei1962
- 粉丝: 2603
- 资源: 902
最新资源
- CC2530无线zigbee裸机代码实现液晶LCD显示.zip
- CC2530无线zigbee裸机代码实现中断唤醒系统.zip
- 车辆、飞机、船检测24-YOLO(v5至v11)、COCO、CreateML、Paligemma、TFRecord、VOC数据集合集.rar
- 基于51单片机的火灾烟雾红外人体检测声光报警系统(protues仿真)-毕业设计
- 高仿抖音滑动H5随机短视频源码带打赏带后台 网站引流必备源码
- 车辆、飞机、船检测25-YOLO(v5至v11)、COCO、CreateML、Paligemma、TFRecord、VOC数据集合集.rar
- 四足机器人示例代码pupper-example-master.zip
- Python人工智能基于深度学习的农作物病虫害识别项目源码.zip
- 基于MIT mini-cheetah 的四足机器人控制quadruped-robot-master.zip
- 菠萝狗四足机器人py-apple-bldc-quadruped-robot-main.zip
- 基于51单片机的篮球足球球类比赛计分器设计(protues仿真)-毕业设计
- 第3天实训任务--电子22级.pdf
- 基于FPGA 的4位密码锁矩阵键盘 数码管显示 报警仿真
- 车辆、飞机、船检测5-YOLO(v5至v11)、COCO、CreateML、Paligemma、VOC数据集合集.rar
- 河南大学(软工免浪费时间)
- NOIP-学习建议-C++
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈