Форум программистов, компьютерный форум CyberForum.ru

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

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 27, средняя оценка - 4.96
ЛазаретЪ
1 / 1 / 0
Регистрация: 04.02.2011
Сообщений: 30
23.05.2011, 20:42     Как работает калькулятор? #1
Помогите подробней код разобрать и прокомментировать назначение переменных, функций...

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];
}
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
yekka
384 / 148 / 8
Регистрация: 12.05.2011
Сообщений: 450
23.05.2011, 20:46     Как работает калькулятор? #2
а что конкретно непонятно?
ЛазаретЪ
1 / 1 / 0
Регистрация: 04.02.2011
Сообщений: 30
23.05.2011, 21:01  [ТС]     Как работает калькулятор? #3
Больше всего интересует, как здесь происходит работа со скобками.
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
24.05.2011, 00:45     Как работает калькулятор? #4
Логика работы подчиняется такой формальной грамматике
Код
// <цифра> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
// <число> ::= <цифра> { <цифра> } [ '.' <цифра> { <цифра> } ]
// 
// <выражение> ::= <слагаемое> [ ( '+' | '-' ) <слагаемое> ]
// <слагаемое> ::= <множитель> [ ( '*' | '/' ) <множитель> ]
// <множитель> ::= ( <число> | '(' <выражение> ')' ) [ '^' <множитель> ]
Правда в этом коде немножко набыдлокодил со степенью, можно было (если посмотреть на грамматику) реализовать куда проще и естественнее, но переделывать лень...
Chipnddail
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;
    }
}
Dejust
 Аватар для Dejust
49 / 49 / 1
Регистрация: 31.01.2011
Сообщений: 156
24.05.2011, 08:30     Как работает калькулятор? #6
Цитата Сообщение от ЛазаретЪ Посмотреть сообщение
подробней код разобрать
По всей видимости, в листинге для решения задачи реализован нисходящий разбор.

Интересная штука кстати
Chipnddail
14 / 14 / 1
Регистрация: 03.09.2009
Сообщений: 109
24.05.2011, 09:39     Как работает калькулятор? #7
Алгоритм аналогичен алгоритму для перевода в Обратную польскую запись
Просто не выводит в строку, а сразу реализует вычисления без вывода в строку.
ЛазаретЪ
1 / 1 / 0
Регистрация: 04.02.2011
Сообщений: 30
24.05.2011, 14:27  [ТС]     Как работает калькулятор? #8
А как "расшифровать" например строку
C++
1
std::cin.get();
?
Это что-то из области ООП?
diagon
Higher
 Аватар для diagon
1920 / 1186 / 49
Регистрация: 02.05.2010
Сообщений: 2,925
Записей в блоге: 2
24.05.2011, 14:29     Как работает калькулятор? #9
Ожидание ввода символа
get-метод объекта std::cin (да, это ООП)
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
24.05.2011, 14:46     Как работает калькулятор? #10
Цитата Сообщение от Chipnddail Посмотреть сообщение
Алгоритм аналогичен алгоритму для перевода в Обратную польскую запись
Если вы про мой код, то никакой аналогии ОПЗ там нет.
ЛазаретЪ
1 / 1 / 0
Регистрация: 04.02.2011
Сообщений: 30
24.05.2011, 14:47  [ТС]     Как работает калькулятор? #11
Цитата Сообщение от diagon Посмотреть сообщение
Ожидание ввода символа
get-метод объекта std::cin (да, это ООП)
ООП без классов?
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
24.05.2011, 14:49     Как работает калькулятор? #12
ЛазаретЪ, кто сказал, что без классов? Да, программа написана в процедурном стиле, однако в ней используются стандартные объекты стандартных библиотечных классов (тот же std::cin - объект класса istrem).
ЛазаретЪ
1 / 1 / 0
Регистрация: 04.02.2011
Сообщений: 30
24.05.2011, 14:51  [ТС]     Как работает калькулятор? #13
Т.е. классы уже прописаны в стандартной библиотеке?
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
24.05.2011, 14:54     Как работает калькулятор? #14
ЛазаретЪ, разумеется, иначе какое удовольствие в использовании голого языка? Думаю, в любом более-менее приличном языке есть стандартная библиотека с реализациями часто используемого инструментария. Не будь её, вы бы даже на экран ничего вывести не смогли без использования низкоуровневых системных API.
ЛазаретЪ
1 / 1 / 0
Регистрация: 04.02.2011
Сообщений: 30
24.05.2011, 15:09  [ТС]     Как работает калькулятор? #15
Спасибо, буду дальше разбираться и задавать вопросы, если что.
ЛазаретЪ
1 / 1 / 0
Регистрация: 04.02.2011
Сообщений: 30
25.05.2011, 19:31  [ТС]     Как работает калькулятор? #16
А в каком случае программа выдаст сообщение "Неверная расстановка скобок!" ? По разному перепробовал скобки ставить, а ошибка не вылазит..
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
25.05.2011, 19:42     Как работает калькулятор? #17
На обработку этой ошибки особый упор не делался, в данном случае обрабатывается вариант, когда открывающей скобке не соответствует закрывающая.
ЛазаретЪ
1 / 1 / 0
Регистрация: 04.02.2011
Сообщений: 30
26.05.2011, 20:29  [ТС]     Как работает калькулятор? #18
C++
1
2
3
#include <iostream> \\заголовочный файл с классами, функциями и переменными для организации ввода-вывода
#include <vector>   \\для работы с динамическими массивами(в него можно засовывать числа, объекты и прочее)
#include <cmath>    \\для выполнения простых математических операций
А #include <iomanip> - для чего нужен?
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
26.05.2011, 20:35     Как работает калькулятор? #19
Например, для std::setprecision.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.05.2011, 20:39     Как работает калькулятор?
Еще ссылки по теме:

Неправильно работает небольшая программа-калькулятор C++
Как это работает? Я хочу спросить как работает C++ и где можно про него почитать C++
Простой калькулятор и калькулятор с парсингом C++

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

Или воспользуйтесь поиском по форуму:
jonson
 Аватар для jonson
231 / 204 / 61
Регистрация: 18.03.2010
Сообщений: 749
26.05.2011, 20:39     Как работает калькулятор? #20
Цитата Сообщение от ЛазаретЪ Посмотреть сообщение
А #include <iomanip> - для чего нужен?
В этом файле определены некоторые манипуляторы потокового ввода/вывода.
например:
std::setprecision
std::setw
std::setbase и т. д.
Yandex
Объявления
26.05.2011, 20:39     Как работает калькулятор?
Ответ Создать тему
Опции темы

Текущее время: 14:25. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru