Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.84/25: Рейтинг темы: голосов - 25, средняя оценка - 4.84
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 91
1

Как преобразовать обычный калькулятор в калькулятор использующий класс стек?

02.06.2018, 13:12. Просмотров 4994. Ответов 12
Метки нет (Все метки)

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
 
int main(){
    int a = 0;
    int b = 0;
    char operation;
    std::cout << "Enter first number: ";
    std::cin >> a;
    std::cout << "Enter second number: ";
    std::cin >> b;
    std::cout << "Enter operation: ";
    std::cin >> operation;
 
    switch (operation){
    case '-':
        std::cout << "a - b = " << a - b <<'\n';
        break;
    case '+':
        std::cout << "a + b = " << a + b << '\n';
        break;
    case '*':
        std::cout << "a * b = " << a * b << '\n';
        break;
    case '/':
        std::cout << "a / b = " << a / b << '\n';
        break;
    default:
        std::cout << "Error\n";
    }
    return 0;
}
Помогите преобразовать обычный калькулятор в калькулятор использующий шаблон класса stack чтобы учитывал очередность действий скобки и все в этом духе.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
02.06.2018, 13:12
Ответы с готовыми решениями:

Как создать калькулятор, использующий для выбора арифметических действий переключатели
и с учетом коэффицента,

Обычный калькулятор: как возвести число в степень
Всем привет! Возникла проблема при создании обычного калькулятора. Не могу найти проблему при...

Как сделать идентичный обычный калькулятор Виндовса в делфи
Как сделать идентичный обычный калькулятор Виндовса в делфи, чтобы можно было вводить с цифровой...

Обычный калькулятор
Привет! Помогите пожалуйста сделать калькулятор на Visual Studio 2008, допустим вводишь числа в...

12
73 / 73 / 18
Регистрация: 29.11.2011
Сообщений: 356
02.06.2018, 13:25 2
А скобки тоже будут по одной вводиться с клавиатуры?
0
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 91
02.06.2018, 13:41  [ТС] 3
Добавлено через 56 секунд
Цитата Сообщение от Praktolock Посмотреть сообщение
А скобки тоже будут по одной вводиться с клавиатуры?
без разницы
скорее всего это должно выглядеть так записывается выражение допустим "2+4-5*1(1/2)+1^1" и калькулятор все это высчитывает используя приоритетность
0
73 / 73 / 18
Регистрация: 29.11.2011
Сообщений: 356
02.06.2018, 14:17 4
Тогда у тебя даже не близко "обычный калькулятор"
0
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 91
02.06.2018, 14:41  [ТС] 5
Спасибо, что подметили, я просто как пример скинул..
0
73 / 73 / 18
Регистрация: 29.11.2011
Сообщений: 356
02.06.2018, 14:43 6
А тебе прям обязательно стек использовать, или просто нужен рабочий калькулятор?
0
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 91
02.06.2018, 15:00  [ТС] 7
Ну задание звучит: "С помощью шаблона класса стек написать программу калькулятор с операциями сложения, вычитания, деления, умножения, возведения в степень." Так что да, обязательно.
0
2702 / 1872 / 553
Регистрация: 05.06.2014
Сообщений: 5,423
02.06.2018, 15:26 8
Цитата Сообщение от SANTA000 Посмотреть сообщение
Ну задание звучит: "С помощью шаблона класса стек написать программу калькулятор с операциями сложения, вычитания, деления, умножения, возведения в степень."
"С помощью метода "копипаста" написать задачник, не вникая какую дичь ты несешь".
Если появилось слово "стек", значит спрашивают польскую запись. Если появилось слово "шаблон", значит не понимают что реализация на обычном стеке проста как мычание. И вообще, не понимают что бывают стеки отличные от шаблонов. Ну, короче тебе нужно взять вот такой код и куда-то там воткнуть стек. Куда именно - надо уточнять у ведущих конструкторов велосипедов. Желательно, индусов по национальности.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
 
long polishNotation()
{
    while(std::cin.peek()==' ')
        std::cin.get();
    switch(std::cin.peek())
    {
    case'-':
        std::cin.get();
        return polishNotation()-polishNotation();
    case'+':
        std::cin.get();
        return polishNotation()+polishNotation();
    default:
    {
        long value;
        std::cin>>value;
        return value;
    }
    }
}
 
int main()
{
    //вводим +3 5, получаем 8
    std::cout<<polishNotation()<<std::endl;
    return 0;
}
0
469 / 422 / 290
Регистрация: 10.03.2015
Сообщений: 1,782
02.06.2018, 15:36 9
Цитата Сообщение от Renji Посмотреть сообщение
Если появилось слово "шаблон", значит не понимают что реализация на обычном стеке проста как мычание
Если я правильно понял посыл, то мб имеется ввиду не template, а конкретно stl - stack? Типо юзать не самописный стек, а шаблонный.
Про ОПН всё логично, тоже писал "калькулятор" применяя ее.
Цитата Сообщение от Renji Посмотреть сообщение
И вообще, не понимают что бывают стеки отличные от шаблонов
А вот тут, если честно, я вообще не понял, что тут имеется ввиду. Если можете, поясните, пожалуйста.
0
2702 / 1872 / 553
Регистрация: 05.06.2014
Сообщений: 5,423
02.06.2018, 16:58 10
Цитата Сообщение от SuperKir Посмотреть сообщение
А вот тут, если честно, я вообще не понял, что тут имеется ввиду. Если можете, поясните, пожалуйста.
Имеется ввиду аппаратный стек в котором хранятся автоматические переменные и адрес возврата из функции. Реализация стекового калькулятора через "шаблона класса стек" делает ровно тоже самое что в моем решении, только аппаратный стек меняется на программный велосипед с квадратными колесами.
0
220 / 147 / 79
Регистрация: 14.03.2016
Сообщений: 459
02.06.2018, 17:55 11
Вот мой вариант, немного неказистый, однако рабочий и с переменными, но без возможности возведения в степень, это ты сам попробуй, только учти, что эта операция имеет больший приоритет чем * и /.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#include <iostream>
#include <conio.h>
#include <string>
#include <stack>
#include <queue>
 
using namespace std;
 
int end() { cout << "\nEND\n"; _getch(); return 0; }
 
queue<char> to_revpol(const string& in)
{
    stack<char> stk;//создаем стак для хранения временных операция
    queue<char> gen;//создаем очередь, куда все будем пихать
    for(auto i : in)//идем по строке
    {
        if(i == '.')//если это просто точка, т.е. пользователь ввел число по типу 0.2,
            gen.push(i);//то тупо пихаем её внутрь
        else if((i >= '0' && i <= '9') ||//если это число или переменная, то тоже просто запихиваем
                (i >= 'a' && i <= 'z') ||
                (i >= 'A' && i <= 'Z'))
        {
            if(gen.empty() != true &&
               (gen.back() >= '0' && gen.back() <= '9') &&
               !(i >= '0' && i <= '9'))
            { stk.push('*'); gen.push(';'); }//эта хрень нужна чтобы можно было не ставить знак умножения перед переменной при вводе 5x, например
            gen.push(i);
        }
        else if
            (i == '+' || i == '-' ||//если же это операция
             i == '*' || i == '/')
        {
            if(stk.empty() != true && (stk.top() == '*' || stk.top() == '/'))//если у нас что-то есть и последняя оперцаия была * или /, то...
            {
                if(i == '*' || i == '/')//если сейчас умножаем или делим
                {
                    gen.push(stk.top());//то можно выгрузить предыдущую операцию
                    stk.top() = i;//и заменить её
                }
                else if(i == '+' || i == '-')//если же это была оперция меньшего приоритета, т.е. + или -
                {
                    while(stk.empty() != true && stk.top() != '(')//следует выгрузить все до открывающейся скобки, либо пока стек не опустеет
                    {//зачем? А переведите на ОПН такое: a * b + c. Тут роль скобочки играет главное тело.
                        gen.push(stk.top());
                        stk.pop();
                    }
                    stk.push(i);
                }
            }
            else//если же стек пуст или последняя операция была не * или /, то...
            {
                if(gen.empty() != true && (
                    (gen.back() >= '0' && gen.back() <= '9') ||
                    (gen.back() >= 'a' && gen.back() <= 'z') ||
                    (gen.back() >= 'A' && gen.back() <= 'Z')))//если последнее, что было в gen - переменная или цифра, 
                    gen.push(';');//то следует поставить ограничивающий знак
                else if(((stk.empty() != true && stk.top() == '(') || gen.empty() == true) && i == '-')//иначе,
                    gen.push('_');//если стек не пуст и последнее, что в него запили была открывающая скобка, либо у нас вообще пока ничего нет, а i == -, то я вставляю знак _
                    //зачем? Ну, для того чтобы все не ломалось при таком вводе: -5 + 3 или 4 * (-2 + 1)
                if(gen.back() != '_')//если последнее в gen не _, которые мы могли только что записать => это какая-то операция
                    stk.push(i);
            }
        }
        else if(i == '(')//если же у нас не цифра, не переменная и не операция, а откр. скобка, то...
        {
            if(gen.empty() != true && (
                (gen.back() >= '0' && gen.back() <= '9') ||
                (gen.back() >= 'a' && gen.back() <= 'z') ||
                (gen.back() >= 'A' && gen.back() <= 'Z')))//если последнее что было в gen - переменная или цифра, 
            {
                gen.push(';');//ставим ограничивающий знак, а в стек записываем *
                stk.push('*');//Опять же, зачем? А затем, чтобы не ставить его самим при записи типа: 23(13 + 1), например
            }
            stk.push(i);//запихиваем ( в стэк
        }
        else if(i == ')')//если же у нас закрылась скобка, следует выгрущить все операции из stk в gen
        {
            while(stk.empty() != true && stk.top() != '(')//пока стек не пустой (если он опустел значит пользователь ввел неправильное выражение) и до, конечно, открывающийся скобки 
            {
                gen.push(stk.top());
                stk.pop();
            }
            if(stk.empty() != true)
                stk.pop();
            else
                throw "WRONG INPUT! Missing (";//кидаем исключение, если пользователь был не очень внимателен
        }
    }
 
    while(stk.empty() != true)//по окончанию работы со строкой в стеке может что-то остаться, потому
    {//выносим все что осталось.
        gen.push(stk.top());
        stk.pop();
    }
    return gen;//и возвращаем результат
}
 
double calc(queue<char> in)
{
    stack<double> res;//временное хранилище значений
    bool minus = false, op = false;//флаги на минус, либо на оперцию
    size_t fl = 0;//переменная для правильного ввода значений с плавающей точкой
    double temp;//и просто временная переменная
 
    res.push(0.0);//добавляем одно значение
    while(in.empty() != true)//пока очередь не опустеет
    {
        if(in.front() == '_')//если встретился знак _, значит был ввод типа: -3 + 2 или 5 * (-4 + 3) и т.д.
        {   
            minus = true;//поднимаем флаг минуса 
            in.pop();//убираем эл.
        }
        else if(in.front() >= '0' && in.front() <= '9')//если получили цифру
        {
            if(op == true) { res.push(0.0); op = false; }//если была какая-то операция и сейчас нам нужно записать новое значение, то добавляем память и опускаем флаг
            while(in.empty() != true && in.front() >= '0' && in.front() <= '9')//пока в очереди что-то есть и пока это цифры
            {
                if((in.front() == '0' && res.top() == 0.0) == false)//чтобы не умножать 0 на 10 и не прибавлять (48 - 48)
                {
                    if(fl == 0)//если не встречалось ., т.е. пока у нас обычное, целое число
                    {
                        res.top() = res.top() * 10 + in.front() - 48;
                    }
                    else//иначе
                    {
                        temp = in.front() - 48;//переводим символьное число в обычное
                        for(size_t i = 0; i < fl; i++)//и по счетчику разряда делим на 10
                            temp /= 10;
                        res.top() += temp;//и просто добавляем к текущему
                        fl++;//увеличиваем разряд
                    }
                }
                in.pop();//убираем эл.
                if(in.empty() != true && in.front() == '.')//если встретилась точка и очередь не пуста, то
                {
                    fl = 1;//счетчик разряда ставим в 1
                    in.pop();//и удаляем .
                }
            }
            fl = 0;//после считывания числа, обнуляем счетчик разрядов
        }
        else if((in.front() >= 'a' && in.front() <= 'z') || (in.front() >= 'A' && in.front() <= 'Z'))//если же нам встретилась переменная
            {
                cout << "Please enter the variable \'";//просим пользователя её ввести
                do
                {//выводим название переменной. А выводим в цикле за тем, чтобы можно было писать переменные не в одну букву
                    cout << in.front();
                    in.pop();
                }while(in.empty() != true && (in.front() >= 'a' && in.front() <= 'z') || (in.front() >= 'A' && in.front() <= 'Z'));
                cout << "\': ";
                if(op == true) { res.push(0.0); op = false;}//если до этого была операция, а теперь нам нужно ввести новое значение, то выделяем память
                cin >> res.top();//вводим значение переменной с клавиатуры
            }
            else if(in.front() == ';' ||
                    in.front() == '+' || in.front() == '-' ||
                    in.front() == '*' || in.front() == '/')//если же нам наконец попалась операция
            {
                if(minus == true)//если флаг минуса поднят
                {
                    minus = false;//опускаем флаг
                    res.top() = -res.top();//умножаем текущее значение на -1
                }
                if(in.front() == ';')//если это знак разделитель, значит надо добавить памяти
                {
                    res.push(0.0);//добавляем 
                    in.pop();//убираем знак
                }
                else if(res.size() > 1)//иначе, если у нас уже что-то есть в стеке
                {
                    temp = res.top();//пихаем в temp последнее значение
                    res.pop();//убираем его из стека
                    switch(in.front())//смотрим что это и делаем необходимые операции
                    {
                        case '+':
                            res.top() += temp;
                            break;
                        case '-':
                            res.top() -= temp;
                            break;
                        case '*':
                            res.top() *= temp;
                            break;
                        case '/':
                            res.top() /= temp;
                            break;
                    }
                    op = true;//ставим флаг операции
                    in.pop();//убираем символ операции из очереди
                }
            }
    }
    if(res.size() > 1)//если вдруг в стеке осталось что-то кроме результата, выводим сообщение об ошибке и все, что осталось в стеке
    {
        cout << "something went wrong!";
        while(res.empty() != true)
        {
            cout << res.top() << ' ';
            res.pop();
        }
        return 0.0;
    }
    return res.top();//если же все хорошо, возвращаем результат
}
 
template <class T>
ostream& operator<<(ostream& out, queue<T> cs)
{
    while(cs.empty() != true)
    {
        out << cs.front();
        cs.pop();
    }
    return out;
}
 
int main()
{
    string in;
    queue<char> gen;
    cout << "Enter an expression:\n";
    getline(cin, in);
 
    gen = to_revpol(in);
    cout << "Result of the function to_revpol: " << gen << endl;
    cout << "Final result: " << calc(gen);
    return end();
}
0
1464 / 929 / 808
Регистрация: 30.04.2016
Сообщений: 3,216
25.07.2018, 22:42 12
SANTA000, здравствуйте! Я делал так (учитываются операции '+', '-', '*', '/' и круглые скобки + приоритет операций):

Пример входных данных:

(2+13)*4-28*(329/(23-17))

Ответ: -1475.33

Код программы:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <bits/stdc++.h>
 
    using namespace std;
 
int prec(char ch) {
    if (ch == '*' || ch == '/') return 2;
    else if (ch == '+' || ch == '-') return 1;
    else return -1;
}
 
string infixToPostfix(string &s) {
    stack<char> st;
    string res;
    s += " ";
    int len = s.size();
    for (int i = 0; i < len; i++) {
        if (isdigit(s[i]) || s[i] == '.')
            res += s[i];
        else if (s[i] == '(') st.push('(');                                
        else if (s[i] == ')') {
            res += " ";
            while (!st.empty() && st.top() != '(') {
                char ch = st.top();
                st.pop();
                res += ch;
                if (ch == '*' || ch == '/') res += " ";
            }
            if (st.top() == '(') {
                char ch = st.top();
                st.pop();
            }
        } else {
            res += " ";
            while (!st.empty() && prec(s[i]) <= prec(st.top())) {
                char ch = st.top();
                st.pop();
                res += ch;
                res += " ";
            }
            st.push(s[i]);
        }
    }
    while (!st.empty()) {
        char ch = st.top();
        st.pop();
        res += ch;
    }
    return res;
}
 
int main() {
    double a, b;
    stack<double> st;
    string s, sign;
    getline(cin, s);
    s = infixToPostfix(s);
    stringstream str(s);
    while (str >> sign) {
        if (!(sign == "-" || sign == "+" || sign == "*" || sign == "/")) st.push(atof(sign.c_str()));
        else {
            if (!st.empty()) {
                b = st.top();
                st.pop();
            }
            if (!st.empty()) {
                a = st.top();
                st.pop();
            }
            switch (sign[0]) {
            case '+':
                st.push(a + b);
                break;
            case '-':
                st.push(a - b);
                break;
            case '*':
                st.push(a * b);
                break;
            case '/':
                st.push(a / b);
                break;
            }
        }
    }
    if (!st.empty()) {
        double ch = st.top();
        st.pop();
        if (st.empty()) {
            cout << ch << "\n";
        }
    }
    system("pause");
    return 0;
}
0
2702 / 1872 / 553
Регистрация: 05.06.2014
Сообщений: 5,423
25.07.2018, 23:16 13
Цитата Сообщение от Fixer_84 Посмотреть сообщение
SANTA000, здравствуйте! Я делал так (учитываются операции '+', '-', '*', '/' и круглые скобки + приоритет операций):
Тыц. Те же объемы кода, но при этом никаких std::stack. А значит, будет быстрее, ибо динамическую память не дергает.
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
25.07.2018, 23:16

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

обычный калькулятор
помогите решить задачу на С: Написать программу, работающую как простейший калькулятор,...

Не могу сделать обычный калькулятор в билдере с помощью print f И scan f
не могу сделать обычный калькулятор в билдере с помощью print f И scan f! киньте кто нить готовый...

Калькулятор и стек
Решил опробовать себя в С++. В Visual Studio C++ решил сделать мини калькулятор, который выполняет...

Стек: Калькулятор ОБЗ
Написать программу, получающую строку с некоторым выражением, записанным обратной бесскобочной...

Как можно динамическую структуру стек преобразовать в класс со стеком?
Добрый день, у меня возник вопрос. как можно динамическую структуру стэк преобразовать в классы со...

Класс Калькулятор
Нужно создать класс Калькулятор который принимает значение N ( N - это число операции) и который...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.