С Новым годом! Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.55/65: Рейтинг темы: голосов - 65, средняя оценка - 4.55
244 / 164 / 133
Регистрация: 30.09.2012
Сообщений: 690
1

Калькулятор: обратная польская запись

30.06.2015, 22:07. Показов 12426. Ответов 4
Метки нет (Все метки)

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
#include <iostream>
#include <stack>
#include <vector>
#include <iterator>
#include <algorithm>
#include <math.h>
bool is_symbol(char sym)
{
    switch(sym)
    {
        case '+': return true;
        case '-': return true;
        case '(': return true;
        case '^': return true;
        // ---------- //
        case '/': return true;
        case '*': return true;
    }
    return false;
}
 
bool is_mid_priority(char sym)
{
    switch(sym)
    {
        case '/': return true;
        case '*': return true;
    }
    return false;
}
 
bool is_low_priority(char sym)
{
    switch(sym)
    {
        case '-': return true;
        case '+': return true;
    }
    return false;
}
 
bool is_high_priority(char sym)
{
    return sym == '^' ? true : false;
}
 
int main()
{
    //std::string expression("(3 + 4 - 5) * 2"); // ??????
    //std::string expression("1 + (5 - 3) * (3 - 1) + 2");
    //std::string expression("2 ^ 3 * 2 + 1");
    //std::string expression("2 + 3 + 5 * 2 + 3 * 6 / 2");
    std::string expression("2 + 3 + 5 * (2 + 3 * 6) / 2"); // ???
    std::stack<char> symbols;
    std::vector<char> exit_string;
    std::stack<double> result;
    double buffer = 0;
 
    for(std::string::iterator it = expression.begin(); it != expression.end(); ++it)
    {
        if(::isdigit(*it)) exit_string.push_back(*it); // Если это цифра
        else if(is_symbol(*it)) // Если это символ
        {
            if(is_low_priority(*it))
            {
                if(symbols.size() && !is_low_priority(symbols.top()))
                {
                    exit_string.push_back(symbols.top());
                    symbols.pop();
                }
                symbols.push(*it);
            }
            else if(is_mid_priority(*it))
            {
                if(symbols.size() && is_high_priority(symbols.top()))
                {
                    exit_string.push_back(symbols.top());
                    symbols.pop();
                }
                symbols.push(*it);
            }
            else if(is_high_priority(*it))
            {
                symbols.push(*it);
            }
            else symbols.push(*it);
        }
        else if(*it == ')')
        {
            while(symbols.top() != '(')
            {
                std::cout << "\n1";
                exit_string.push_back(symbols.top());
                symbols.pop();
            }
            if(symbols.size()) { symbols.pop(); }
        }
    }
    while(symbols.size()) { exit_string.push_back(symbols.top()); symbols.pop(); }
    std::copy(exit_string.begin(), exit_string.end(), std::ostream_iterator<char>(std::cout, " "));
 
    for(std::vector<char>::iterator it = exit_string.begin(); it != exit_string.end(); ++it)
    {
        if(::isdigit(*it)) result.push(*it - '0');
        else
            switch(*it)
            {
            case '+': { buffer = result.top(); result.pop(); result.top() += buffer; break; }
            case '-': { buffer = result.top(); result.pop(); result.top() -= buffer; break; }
            case '*': { buffer = result.top(); result.pop(); result.top() *= buffer; break; }
            case '/': { buffer = result.top(); result.pop(); result.top() /= buffer; break; }
            case '^': { buffer = result.top(); result.pop(); result.top() = pow(result.top(), buffer); break; }
            }
    }
    std::cout << "\nANSWER: " << result.top();
    return 0;
}
Собственно, те выражения, которые помечены вопросами, и вызывают крах программы. По моим наблюдениям, крах происходит в цикле, который обрабатывает вхождение закрывающей скобки.
Также, если кто-то что-то подскажет по поводу улучшения реализации, да и вообще любые другие замечания по коду в целом, то также буду очень благодарен! =)
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
30.06.2015, 22:07
Ответы с готовыми решениями:

Калькулятор (обратная польская запись)
Есть калькулятор к нему нужно добавить &quot;(&quot;, &quot;)&quot;.Погуглив понял, что нужно внедрять обратную...

Обратная польская запись
Нужно создать класс с++ для вычисления обратной польской записи с помощь стека.

Обратная польская запись
Нужна помощь. Есть программа с общей польской записью. Программа принимает только буквенное...

Обратная польская запись
Подскажите, как по обратной польской записи выражения построить дерево выражения Например:...

4
3176 / 1935 / 312
Регистрация: 27.08.2010
Сообщений: 5,131
Записей в блоге: 1
30.06.2015, 22:24 2
Цитата Сообщение от Gr1f0nn Посмотреть сообщение
#include <iostream> #include <stack> #include <vector> #include <iterator> #include <algorithm>

Не по теме:

Осподи!


http://stjarnhimlen.se/snippets/eval.c

Суперкалькулятор
1
244 / 164 / 133
Регистрация: 30.09.2012
Сообщений: 690
30.06.2015, 22:37  [ТС] 3

Не по теме:

Цитата Сообщение от gazlan Посмотреть сообщение
Осподи!
Есть такое ^_^
Много лишнего наворочено, но пока решил сделать первую рабочую версию, а потом уже приводить все в порядок (касаемо применения стандартных алгоритмов, итераторов, векторов и т.д и т.п.).



За ссылки спасибо, попробую разобраться в решениях, но, как мне кажется, это будет несколько неправильный подход (???), так как, в итоге, обработка строки скорее всего будет скопирована, а ошибку я так и не найду ^_^

Добавлено через 5 минут
Есть идея сделать что-то вроде счетчика, который бы подсчитывал количество операций внутри каждой скобки, но это слабо похоже на адекватное решение. Просто, не смотря на проверки не пустоты стека, как я понял, программа все равно либо выходит за его границы, либо это как раз "непредсказуемый" вывод результата команд .pop() и .top(), если стек пуст.
0
3176 / 1935 / 312
Регистрация: 27.08.2010
Сообщений: 5,131
Записей в блоге: 1
30.06.2015, 22:51 4
Классика: Four Function Calculator: An AnaGram Example

+

Страуструп. Грамматики. Парсер - C++
Упражнение для программы калькулятор из книги Язык программирования С++

+ поиск по форуму.
1
244 / 164 / 133
Регистрация: 30.09.2012
Сообщений: 690
30.06.2015, 23:07  [ТС] 5
Проблему нашел. Почему-то в некоторых случаях открывающая скобка не записывается в стек.

Добавлено через 13 минут
Все. Проблема решена.
Ошибка была в этой строке:
C++
1
if(symbols.size() && !is_low_priority(symbols.top()))
Открывающая скобка в данном случае также проходила по условию, поэтому она выходила из стека раньше времени.
Решил так:
C++
1
if(symbols.size() && (is_mid_priority(symbols.top()) || is_high_priority(symbols.top())))
Здесь скобка точно не пройдет ^_^
0
30.06.2015, 23:07
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.06.2015, 23:07
Помогаю со студенческими работами здесь

Обратная польская запись
Здравствуйте, изучаю обратную польскую запись, столкнулся с такой проблемой: Перерыл множество...

Обратная Польская Запись
Сам вопрос: Я написал программу, она работает, но препод по Структурам данных сломал ее в два...

Обратная польская запись
Добрый день, подскажите, как будет выглядеть обратная польская запись для for (i=0;i&lt;n;i++){...

Обратная польская запись
Написать программу формирования ОПЗ и расчета полученного вы-ражения. Разработать удобный интерфейс...


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

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