Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.77/22: Рейтинг темы: голосов - 22, средняя оценка - 4.77
1 / 1 / 1
Регистрация: 04.02.2011
Сообщений: 30
1

Как работает калькулятор?

23.05.2011, 20:42. Показов 4418. Ответов 21
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Помогите подробней код разобрать и прокомментировать назначение переменных, функций...

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
228
229
230
231
232
#include <iostream>
#include <vector>
#include <cmath>
#include <iomanip>
 
double number();
double factor();
double expr();
double brackets();
double power();
 
int main()
{
    double n;
 
    setlocale(LC_ALL, "Rus");
 
    std::cout << "Введите выражение: ";
 
    n = expr();
 
    std::cout << "Результат вычисления: " << std::setprecision(10) << n << std::endl;
 
    std::cin.get();
    return 0;
}
 
double number()
{
    double result = 0.0;
    double k = 10.0;
    int sign = 1;
    char c;
 
    c = std::cin.get();
 
    while (c == ' ')
        c = std::cin.get();
 
    if (c == '-')
        sign = -1;
    else
    {
        if (c != '+')
            std::cin.putback(c);
    }
 
    while (true)
    {
        c = std::cin.get();
 
        while (c == ' ')
            c = std::cin.get();
 
        if (c >= '0' && c <= '9')
            result = result * 10.0 + (c - '0');
        else
        {
            std::cin.putback(c);
            break;
        }
    }
 
    c = std::cin.get();
 
    if (c == '.')
    {
        while (true)
        {
            c = std::cin.get();
 
            if (c >= '0' && c <= '9')
            {
                result += (c - '0') / k;
                k *= 10.0;
            }
            else
            {
                std::cin.putback(c);
                break;
            }
        }
    }
    else
        std::cin.putback(c);
 
    return sign * result;
}
 
double factor()
{
    double result;
    double temp;
    char op;
 
    result = power();
 
    while (true)
    {
        op = std::cin.get();
 
        while (op == ' ')
            op = std::cin.get();
 
        switch (op)
        {
        case '*':
            result *= power();
            break;
        case '/':
            temp = power();
 
            if (temp == 0.0)
            {
                std::cout << "Деление на нуль!" << std::endl;
                exit(-1);
            }
 
            result /= temp;
            break;
        default:
            std::cin.putback(op);
            return result;
        }
    }
}
 
double expr()
{
    double result;
    char op;
 
    result = factor();
 
    while (true)
    {
        op = std::cin.get();
 
        while (op == ' ')
            op = std::cin.get();
 
        switch (op)
        {
        case '+':
            result += factor();
            break;
        case '-':
            result -= factor();
            break;
        default:
            std::cin.putback(op);
            return result;
        }
    }
}
 
double brackets()
{
    double result;
    int sign = 1;
    char op;
 
    op = std::cin.get();
 
    while (op == ' ')
        op = std::cin.get();
 
    if (op == '-')
    {
        sign = -1;
        op = std::cin.get();
    }
    else
    {
        if (op == '+')
            op = std::cin.get();
    }
 
    while (op == ' ')
        op = std::cin.get();
 
    if (op == '(')
    {
        result = sign * expr();
 
        op = std::cin.get();
 
        if (op != ')')
        {
            std::cout << "Неверная расстановка скобок!" << std::endl;
            exit(-1);
        }
 
        return result;
    }
    else
    {
        std::cin.putback(op);
 
        return sign * number();
    }
}
 
double power()
{
    double result;
    char op;
    std::vector < double > args;
 
    args.push_back(brackets());
 
    while (true)
    {
        op = std::cin.get();
        
        while (op == ' ')
            op = std::cin.get();
 
        if (op == '^')
            args.push_back(brackets());
        else
        {
            std::cin.putback(op);
            break;
        }
    }
 
    for (int i = args.size() - 1; i > 0; i--)
        args[i - 1] = pow(args[i - 1], args[i]);
 
    return args[0];
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
23.05.2011, 20:42
Ответы с готовыми решениями:

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

Простой калькулятор: Не работает код, как это исправить?
Здравствуйте! Вот имеется такой код, взят отсюда, ...

Как преобразовать обычный калькулятор в калькулятор использующий класс стек?
#include &lt;iostream&gt; int main(){ int a = 0; int b = 0; char operation; ...

Не работает калькулятор
Делаю калькулятор, но он делает только сложение и закрывается после того как написал ответ. ...

21
387 / 151 / 16
Регистрация: 12.05.2011
Сообщений: 450
23.05.2011, 20:46 2
а что конкретно непонятно?
0
1 / 1 / 1
Регистрация: 04.02.2011
Сообщений: 30
23.05.2011, 21:01  [ТС] 3
Больше всего интересует, как здесь происходит работа со скобками.
0
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
24.05.2011, 00:45 4
Логика работы подчиняется такой формальной грамматике
Код
// <цифра> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
// <число> ::= <цифра> { <цифра> } [ '.' <цифра> { <цифра> } ]
// 
// <выражение> ::= <слагаемое> [ ( '+' | '-' ) <слагаемое> ]
// <слагаемое> ::= <множитель> [ ( '*' | '/' ) <множитель> ]
// <множитель> ::= ( <число> | '(' <выражение> ')' ) [ '^' <множитель> ]
Правда в этом коде немножко набыдлокодил со степенью, можно было (если посмотреть на грамматику) реализовать куда проще и естественнее, но переделывать лень...
1
14 / 14 / 1
Регистрация: 03.09.2009
Сообщений: 109
24.05.2011, 06:46 5
Советую поискать про Обратную Польскую Запись.
С ее помощью можно наиболее эффективно разбирать даже сложные скобочные выражения.
Не так давно сам попробовал реализовать что-то вроде калькулятора на c99.

Возможно, пригодится мой код. Он довольно подробно прокомментирован.
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
/*Методы для преобразования входной текстовой строки в тесктовоую строку
 * в обратной польской записи для дальнейшего вычисления
 Бесскобочная символика Лукашевича*/
 
 
#include <stdio.h>
#include <stdlib.h>
#include "Stack.h"
 
static struct stack *opers_head = NULL; //указатель вершины стека операторов
struct stack *operands = NULL; //указатель вершины стека операндов
extern void operate(char c);
 
int isDigit(char c){ //определяет цифру
    return (c>='0' && c<='9');
}
 
int get_prior(char c){ //возвращает приоритет операции
    switch(c){
        case '(':
            return 0;
        case ')':
            return 1;
        case '+':
        case '-':
            return 2;
        case '*':
        case '/':
            return 3;
        default:
            return -1;
    }
}
int CalcOPN(char *input){
    char c;//Входной символ для анализа
    char buff[11]; //буфер для символов числа для преобразования в число
    char* buff_ptr = buff; //указатель на буфер символов
    int prior; //Приоритет оператора
    int left_oper_count = 0; //число появления открывающей скобки
    //Вынимаем по одному символу из входной строки
    while ((c=*input++)!='\0'){
        //если входной символ операнд(цифра), пишем в буфер
        if (isDigit(c))
        {
            *(buff_ptr++) = c;
        }
        else
        {
            //если оператор, выясняем приоритет
            prior=get_prior(c);
            //символ не является цифрой или оператором
            if (prior==-1){
                //завершаем программу с ошибкой
                fputs("Введен неверный символ", stdout);
                return(EXIT_FAILURE);
            }
            else{
                //есть символы в буфере (был считан операнд)
                //преобразуем его в int и положим в стек операндов
                if (buff_ptr > buff){
                    *buff_ptr = '\0';//нулевой символ в конце строки
                //Преобразованный символ помещаем в стек операндов 
                    push(atoi(buff), &operands);
                //Возвращаем указатель на начало массива
                    buff_ptr = buff;
                }
                    switch(c) {
                        case '(':
                            //увеличить счетчик открытых скобок
                            ++left_oper_count;
                            //затолкать скобку в стек
                            push(c, &opers_head);
                            break;
                        case '+': case '-': case '/': case '*':
               //если стек непустой проверяем приоритеты
                            if (!isEmptyStack(opers_head)) {                              
               //выталкиваем из стека операторы с равным и большим приоритетом
                                while (get_prior(c) < get_prior(peek(opers_head)))
                //вычисляем результат операции и пишем в стек операндов
                                            operate(pop(&opers_head));
                            }
               //заталкиваем орератор в стек
                            push(c, &opers_head);
                            break;
                        case ')':
                            //если нет открывающей скобки
                            if (left_oper_count<=0){
                                fputs("Непарные скобки", stdout);
                                return(EXIT_FAILURE);
                            }
                            //если есть открывающие
                            else {
                             //выталкиваем из стека все, что между скобками
                                while ((c=pop(&opers_head)) != '(')
                             //вычисляем результат и пишем в стек операндов
                                    operate(c);
                                //уменьшаем счетчик открытых скобок
                                --left_oper_count;
                            }
                            break;
                    }
            }
        }
    }
    //если буфер символов не пуст (был считан операнд)
    //преобразуем его в int и положим в стек операндов
    if (buff_ptr>buff){
        *buff_ptr = '\0';//нулевой символ в конце строки
        //Преобразованный символ помещаем в стек операндов 
        push(atoi(buff), &operands);
        //Возвращаем указатель на начало массива
        buff_ptr = buff;
    }
     //выталкием все, что осталось в стеке опрераторов
    while(!isEmptyStack(opers_head))
        //вычисляем результат и пишем в стек операндов
        operate(pop(&opers_head));
    return(EXIT_SUCCESS);
}
 
//вычисление над операндами на основе поступившего оператора
//реализованы только бинарные операции
void operate(char c) {
    //Извлекаем из стека два операнда
    int b = pop(&operands);
    int a = pop(&operands);
    switch(c){
        case '+':
            push(a + b, &operands);
            break;
        case '-':
            push(a - b, &operands);
            break;
        case '/':
            push(a / b, &operands);
            break;
        case '*':
            push(a * b, &operands);
            break;
    }
}
1
49 / 49 / 4
Регистрация: 31.01.2011
Сообщений: 156
24.05.2011, 08:30 6
Цитата Сообщение от ЛазаретЪ Посмотреть сообщение
подробней код разобрать
По всей видимости, в листинге для решения задачи реализован нисходящий разбор.

Интересная штука кстати
0
14 / 14 / 1
Регистрация: 03.09.2009
Сообщений: 109
24.05.2011, 09:39 7
Алгоритм аналогичен алгоритму для перевода в Обратную польскую запись
Просто не выводит в строку, а сразу реализует вычисления без вывода в строку.
0
1 / 1 / 1
Регистрация: 04.02.2011
Сообщений: 30
24.05.2011, 14:27  [ТС] 8
А как "расшифровать" например строку
C++
1
std::cin.get();
?
Это что-то из области ООП?
0
Higher
1953 / 1219 / 120
Регистрация: 02.05.2010
Сообщений: 2,925
Записей в блоге: 2
24.05.2011, 14:29 9
Ожидание ввода символа
get-метод объекта std::cin (да, это ООП)
0
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
24.05.2011, 14:46 10
Цитата Сообщение от Chipnddail Посмотреть сообщение
Алгоритм аналогичен алгоритму для перевода в Обратную польскую запись
Если вы про мой код, то никакой аналогии ОПЗ там нет.
0
1 / 1 / 1
Регистрация: 04.02.2011
Сообщений: 30
24.05.2011, 14:47  [ТС] 11
Цитата Сообщение от diagon Посмотреть сообщение
Ожидание ввода символа
get-метод объекта std::cin (да, это ООП)
ООП без классов?
0
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
24.05.2011, 14:49 12
ЛазаретЪ, кто сказал, что без классов? Да, программа написана в процедурном стиле, однако в ней используются стандартные объекты стандартных библиотечных классов (тот же std::cin - объект класса istrem).
1
1 / 1 / 1
Регистрация: 04.02.2011
Сообщений: 30
24.05.2011, 14:51  [ТС] 13
Т.е. классы уже прописаны в стандартной библиотеке?
0
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
24.05.2011, 14:54 14
ЛазаретЪ, разумеется, иначе какое удовольствие в использовании голого языка? Думаю, в любом более-менее приличном языке есть стандартная библиотека с реализациями часто используемого инструментария. Не будь её, вы бы даже на экран ничего вывести не смогли без использования низкоуровневых системных API.
1
1 / 1 / 1
Регистрация: 04.02.2011
Сообщений: 30
24.05.2011, 15:09  [ТС] 15
Спасибо, буду дальше разбираться и задавать вопросы, если что.
0
1 / 1 / 1
Регистрация: 04.02.2011
Сообщений: 30
25.05.2011, 19:31  [ТС] 16
А в каком случае программа выдаст сообщение "Неверная расстановка скобок!" ? По разному перепробовал скобки ставить, а ошибка не вылазит..
0
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
25.05.2011, 19:42 17
На обработку этой ошибки особый упор не делался, в данном случае обрабатывается вариант, когда открывающей скобке не соответствует закрывающая.
1
1 / 1 / 1
Регистрация: 04.02.2011
Сообщений: 30
26.05.2011, 20:29  [ТС] 18
C++
1
2
3
#include <iostream> \\заголовочный файл с классами, функциями и переменными для организации ввода-вывода
#include <vector>   \\для работы с динамическими массивами(в него можно засовывать числа, объекты и прочее)
#include <cmath>    \\для выполнения простых математических операций
А #include <iomanip> - для чего нужен?
0
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
26.05.2011, 20:35 19
Например, для std::setprecision.
0
240 / 213 / 84
Регистрация: 18.03.2010
Сообщений: 750
26.05.2011, 20:39 20
Цитата Сообщение от ЛазаретЪ Посмотреть сообщение
А #include <iomanip> - для чего нужен?
В этом файле определены некоторые манипуляторы потокового ввода/вывода.
например:
std::setprecision
std::setw
std::setbase и т. д.
0
26.05.2011, 20:39
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.05.2011, 20:39
Помогаю со студенческими работами здесь

Не работает калькулятор
Постигаю азы программирования, решил написать калькулятор и столкнулся с проблемой - он просто не...

Почему так странно работает калькулятор
Здраствуйте, я сегодня решил взяться за C++, решил написать самое простое, калькулятор: #include...

Неправильно работает небольшая программа-калькулятор
это калькулятор фунтов, шиллингов и пенсов по старой системе. он должен уметь складывать, вычитать...

Как это работает? Я хочу спросить как работает C++ и где можно про него почитать
Привет, котоны. Заранее благодарю. Это будет моих общих вопросов нить, т.к. создавать целую ветку...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru