Skip to content

Commit eef023f

Browse files
committed
task 12.20: calculator
1 parent 28b3c0b commit eef023f

File tree

4 files changed

+77
-51
lines changed

4 files changed

+77
-51
lines changed

week-15/task-12-20/CMakeLists.txt

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
include_directories(include)
22

33
add_subdirectory(test)
4-
5-
add_executable(ae main.cpp)

week-15/task-12-20/include/calculator.hpp

+33-20
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,41 @@
11
#pragma once
22

3-
#include <stack>
3+
#include <cassert>
44
#include <sstream>
5+
#include <stack>
56

6-
bool is_operator(char c) {
7+
inline bool is_operator(const std::string& str) {
8+
if (str.size() != 1) {
9+
return false;
10+
}
11+
const char c = str[0];
712
return c == '+' || c == '-' || c == '*' || c == '/';
813
}
914

10-
int calculate(const std::string& str) {
11-
std::stack<int> stack;
12-
for (auto it = std::cbegin(str); it != std::cend(str);) {
13-
if (static_cast<bool>(std::isspace(*it))) {
14-
while (it != std::cend(str) && static_cast<bool>(std::isspace(*it))) { ++it; }
15-
} else if (static_cast<bool>(std::isdigit(*it))) {
16-
std::istringstream iss(std::string(it, std::cend(str)));
17-
int val;
18-
iss >> val;
19-
stack.push(val);
20-
std::advance(it, iss.tellg());
21-
} else if (is_operator(*it)) {
22-
const int b = stack.top(); stack.pop();
23-
const int a = stack.top(); stack.pop();
24-
switch (*it) {
15+
inline bool may_be_number(const std::string& str) {
16+
return (str[0] == '-' && str.size() > 1) || static_cast<bool>(std::isdigit(str[0]));
17+
}
18+
19+
double calculate(const std::string& str) {
20+
if (str.empty()) {
21+
throw std::invalid_argument("empty string");
22+
}
23+
std::stack<double> stack;
24+
std::istringstream iss(str);
25+
std::string token;
26+
while (iss >> token) {
27+
assert(!token.empty());
28+
if (may_be_number(token)) {
29+
stack.push(std::stod(token));
30+
} else if (is_operator(token)) {
31+
if (stack.size() < 2) {
32+
throw std::invalid_argument("too few arguments for operation");
33+
}
34+
const double b = stack.top();
35+
stack.pop();
36+
const double a = stack.top();
37+
stack.pop();
38+
switch (token[0]) {
2539
case '+':
2640
stack.push(a + b);
2741
break;
@@ -35,11 +49,10 @@ int calculate(const std::string& str) {
3549
stack.push(a / b);
3650
break;
3751
default:
38-
throw std::runtime_error("unexpected operator");
52+
throw std::invalid_argument("unexpected operator");
3953
}
40-
++it;
4154
} else {
42-
throw std::runtime_error("unexpected symbol");
55+
throw std::invalid_argument("unexpected token");
4356
}
4457
}
4558
return stack.top();

week-15/task-12-20/main.cpp

-5
This file was deleted.
+44-24
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,63 @@
1-
#include "gtest/gtest.h"
21
#include "calculator.hpp"
2+
#include "gtest/gtest.h"
33

44
TEST(RPNCalculatorTest, BasicOperations) {
5-
EXPECT_EQ(calculate("3 4 +"), 7); // 3 + 4
6-
EXPECT_EQ(calculate("5 2 -"), 3); // 5 - 2
7-
EXPECT_EQ(calculate("2 3 *"), 6); // 2 * 3
8-
EXPECT_EQ(calculate("6 2 /"), 3); // 6 / 2
5+
EXPECT_DOUBLE_EQ(calculate("3 4 +"), 7.0);
6+
EXPECT_DOUBLE_EQ(calculate("5 2 -"), 3.0);
7+
EXPECT_DOUBLE_EQ(calculate("2 3 *"), 6.0);
8+
EXPECT_DOUBLE_EQ(calculate("6 2 /"), 3.0);
9+
}
10+
11+
TEST(RPNCalculatorTest, FloatingPointOperations) {
12+
EXPECT_DOUBLE_EQ(calculate("3.5 4.2 +"), 7.7);
13+
EXPECT_DOUBLE_EQ(calculate("5.1 2.3 -"), 2.8);
14+
EXPECT_DOUBLE_EQ(calculate("2.5 3.2 *"), 8.0);
15+
EXPECT_DOUBLE_EQ(calculate("7.5 2.5 /"), 3.0);
916
}
1017

1118
TEST(RPNCalculatorTest, ComplexExpressions) {
12-
EXPECT_EQ(calculate("3 4 2 * +"), 11); // 3 + (4 * 2)
13-
EXPECT_EQ(calculate("5 1 2 + 4 * + 3 -"), 14); // 5 + ((1+2)*4) - 3
14-
EXPECT_EQ(calculate("4 2 5 * + 1 3 - /"), -7); // (4 + 2*5) / (1-3)
19+
EXPECT_DOUBLE_EQ(calculate("3 4 2 * +"), 11.0);
20+
EXPECT_DOUBLE_EQ(calculate("5 1 2 + 4 * + 3 -"), 14.0);
21+
EXPECT_DOUBLE_EQ(calculate("4 2 5 * + 1 3 - /"), -7.0);
1522
}
1623

1724
TEST(RPNCalculatorTest, EdgeCases) {
18-
EXPECT_EQ(calculate("0 5 +"), 5); // 0 + 5
19-
EXPECT_EQ(calculate("1 1 -"), 0); // 1 - 1
20-
EXPECT_EQ(calculate("999 1 +"), 1000); // large number
21-
EXPECT_EQ(calculate("-5 3 +"), -2); // negative number
25+
EXPECT_DOUBLE_EQ(calculate("0 5 +"), 5.0);
26+
EXPECT_DOUBLE_EQ(calculate("1 1 -"), 0.0);
27+
EXPECT_DOUBLE_EQ(calculate("999 1 +"), 1000.0);
28+
EXPECT_DOUBLE_EQ(calculate("-5 3 +"), -2.0);
2229
}
2330

2431
TEST(RPNCalculatorTest, InvalidInput) {
25-
EXPECT_THROW(calculate(""), std::invalid_argument); // empty
26-
EXPECT_THROW(calculate("3 +"), std::invalid_argument); // missing operand
27-
EXPECT_THROW(calculate("3 4 + -"), std::invalid_argument); // extra operator
28-
EXPECT_THROW(calculate("a b +"), std::invalid_argument); // non-numbers
29-
EXPECT_THROW(calculate("3 0 /"), std::runtime_error); // division by zero
32+
EXPECT_THROW(calculate(""), std::invalid_argument);
33+
EXPECT_THROW(calculate("3 +"), std::invalid_argument);
34+
EXPECT_THROW(calculate("3 4 + -"), std::invalid_argument);
35+
EXPECT_THROW(calculate("a b +"), std::invalid_argument);
3036
}
3137

3238
TEST(RPNCalculatorTest, WhitespaceHandling) {
33-
EXPECT_EQ(calculate(" 3 4 + "), 7); // extra spaces
34-
EXPECT_EQ(calculate("3\n4\t+"), 7); // different whitespace
35-
EXPECT_EQ(calculate("3 4 + "), 7); // trailing space
39+
EXPECT_DOUBLE_EQ(calculate(" 3 4 + "), 7.0);
40+
EXPECT_DOUBLE_EQ(calculate("3\n4\t+"), 7.0);
41+
EXPECT_DOUBLE_EQ(calculate("3 4 + "), 7.0);
3642
}
3743

3844
TEST(RPNCalculatorTest, MultiDigitNumbers) {
39-
EXPECT_EQ(calculate("10 20 +"), 30); // 10 + 20
40-
EXPECT_EQ(calculate("100 50 -"), 50); // 100 - 50
41-
EXPECT_EQ(calculate("12 34 *"), 408); // 12 * 34
42-
EXPECT_EQ(calculate("100 5 /"), 20); // 100 / 5
45+
EXPECT_DOUBLE_EQ(calculate("10 20 +"), 30.0);
46+
EXPECT_DOUBLE_EQ(calculate("100 50 -"), 50.0);
47+
EXPECT_DOUBLE_EQ(calculate("12 34 *"), 408.0);
48+
EXPECT_DOUBLE_EQ(calculate("100 5 /"), 20.0);
49+
}
50+
51+
TEST(RPNCalculatorTest, PrecisionHandling) {
52+
EXPECT_DOUBLE_EQ(calculate("0.1 0.2 +"), 0.3);
53+
EXPECT_DOUBLE_EQ(calculate("1.234 2.345 +"), 3.579);
54+
EXPECT_NEAR(calculate("1.0 3.0 /"), 0.333333, 1e-6);
55+
EXPECT_NEAR(calculate("2.0 3.0 /"), 0.666666, 1e-6);
56+
}
57+
58+
TEST(RPNCalculatorTest, MixedIntegerAndFloatingPoint) {
59+
EXPECT_DOUBLE_EQ(calculate("3 4.5 +"), 7.5);
60+
EXPECT_DOUBLE_EQ(calculate("5.2 2 -"), 3.2);
61+
EXPECT_DOUBLE_EQ(calculate("2 3.5 *"), 7.0);
62+
EXPECT_DOUBLE_EQ(calculate("6.6 2.2 /"), 3.0);
4363
}

0 commit comments

Comments
 (0)