Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.77/47: Рейтинг темы: голосов - 47, средняя оценка - 4.77
0 / 0 / 0
Регистрация: 25.10.2009
Сообщений: 45

Пишем необычный калькулятор

06.02.2013, 12:51. Показов 9455. Ответов 17
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет! Решил написать калькулятор, который выполняет простые арифмет операции (слож,умн,деление,вычит).

хочу сделать необычный калькулятор..т.е. он будет состоять из двух полей - первое поле (сюда будем записывать числа с которыми нужно выполнить матем операции), второе поле(сюда будет показываться результ мат операций).

Хотелось бы для поля ввода чисел - сделать условие - приоритеты вычислений мы будем указывать с помощью скобок и количество вложенности скобок и количество выполняемых математ операций в одной строке не будет ограничено.
например (5-3)+2=4

проблема как в поле edit1 сделать так, чтобы учитывались приоритеты ?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
06.02.2013, 12:51
Ответы с готовыми решениями:

Необычный LINQ запрос
Помогите пожалуйста, даже сообразить не могу, string names = { "Alonso", "Zheng", "Smith", "Jones", "Smythe",...

Пишем простой бот для браузера
Привет! Подскажите, каким образом лучше подойти к решению задачи. Мне нужно написать бота, который будет заходить на адрес в браузере...

В чем разница, если мы пишем имя класса перед инициализацией экземпляра?
А в чем разница в записи FbTransaction fbt = fg.BeginTransaction(); и такой записи fbt = fg.BeginTransaction(); ?

17
1057 / 864 / 195
Регистрация: 31.03.2010
Сообщений: 2,521
06.02.2013, 12:58
dron4ik, погугли обратная польская запись.
она позволят записывать выжение, которое однозначно вычисляется слева направо.

далее создаешь конвертер из обычной записи в польскую и калькулятор польской записи.
0
Темная сторона .Net
 Аватар для Noob.net
592 / 489 / 39
Регистрация: 21.07.2012
Сообщений: 1,668
06.02.2013, 12:59
dron4ik, Обратная польская запись
и еще тык
0
0 / 0 / 0
Регистрация: 25.10.2009
Сообщений: 45
07.02.2013, 07:58  [ТС]
равзе у меня не прямая польская запись?

Добавлено через 2 минуты
а может можно как нить циклом пройтись по выражению.найти самое вложенное выражение т.е. 5+(2+(3-1)) сначала вычисляем 3-1, далее на уровень вверх 2+2, далее опять на уровень вверх, 5+4..может как нить так реализовать?не силен на си шарпе..как можно это реализовать?

Добавлено через 1 минуту
прочитал, но ОПЗ, для меня вернее для реализации сложновато будет..поэтому я предложил альтернативу..(есть внизу вернее в др посте)
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
07.02.2013, 07:59
Цитата Сообщение от dron4ik Посмотреть сообщение
а может можно как нить циклом пройтись по выражению. найти самое вложенное выражение
нет
Цитата Сообщение от dron4ik Посмотреть сообщение
прочитал, но ОПЗ, для меня вернее для реализации сложновато будет
Это самое простое, понятное и распространенное решение для вашей задачи, так что изучайте.
0
2 / 2 / 3
Регистрация: 19.01.2013
Сообщений: 32
07.02.2013, 08:05
Цитата Сообщение от dron4ik Посмотреть сообщение
равзе у меня не прямая польская запись?

Добавлено через 2 минуты
а может можно как нить циклом пройтись по выражению.найти самое вложенное выражение т.е. 5+(2+(3-1)) сначала вычисляем 3-1, далее на уровень вверх 2+2, далее опять на уровень вверх, 5+4..может как нить так реализовать?не силен на си шарпе..как можно это реализовать?

Добавлено через 1 минуту
прочитал, но ОПЗ, для меня вернее для реализации сложновато будет..поэтому я предложил альтернативу..(есть внизу вернее в др посте)
Ага, я так сделал, прям по выражению. Надо проходить строку-выражение рекурсивно. Встречаешь первое число и запоминаешь следующий за ним знак операции. Если это '*', то уножаешь это число на следующее и так столько раз, пока не встретишь '+' или '-'. Аналогично с делением. Потом делаешь это для следующего числа. Это для того, чтобы получить n1 + n2 или n1 - n2 и не работать с произведениями. Результат вычислений передаешь по ссылке. В конце, когда строка кончится, вернешь указатель на ее конец. Так же заканчиваешь вычисление и возвращаешь указатель тогда, когда встречаешь закрывающую скобку. Это означает, что ты вычислил скобочное выражение. Соответсвенно, если вместо числа ты встречаешь открывающую скобку, то применяешь эту функцию к ее содержимому, и потом смотришь след. число. Пока строка не кончится.
0
0 / 0 / 0
Регистрация: 25.10.2009
Сообщений: 45
07.02.2013, 08:19  [ТС]
Спасибо!) а можно на примере?(легенький примерчик простенький) как правильно это написать в коде си шарпе?
0
2 / 2 / 3
Регистрация: 19.01.2013
Сообщений: 32
07.02.2013, 08:31
Цитата Сообщение от dron4ik Посмотреть сообщение
Спасибо!) а можно на примере?(легенький примерчик простенький) как правильно это написать в коде си шарпе?
Я написал на C++) Не знаю, как на C#.
Работает где-то так:

1 + 5 * (9 - 4)

1:
num = 1;
op = +;

2:
op = +;
==> result = num;
3:
num = 5;
op = *;
while (op == '*' || op == '/') {
nextNum = '('
==> nextNum = result(9 - 4) //это формально
nextOp = 0 //нулевой байт, знак после скобки
==> ничего дальше не делать
<применить op к result и nextNum>
op = nextOp
1
0 / 0 / 0
Регистрация: 25.10.2009
Сообщений: 45
07.02.2013, 08:38  [ТС]
вообще пока не ясно( можешь код закамментить си++ не знаю
0
2 / 2 / 3
Регистрация: 19.01.2013
Сообщений: 32
07.02.2013, 08:45
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
char * Eval(char * firstElem, double & result) {
    result = 0;
    double num;
    //Считываем первое число и первый знак операции:
    char * binOp = BinOp(firstElem, num);
    if (*binOp == '%') {
        cout << "Error: Incorrected enter of numbers." << endl << endl;
        return binOp;
    }
    result = num;
    //Запинаем число в результате, и если считанный
    //знак - умножение, то будем считывать следующие
    //числа и умножать на их на результат, пока знак
    //умножения не сменится на плюс или минус:
    while (*binOp == '*' || *binOp == '/') {
        char * nextBinOp = BinOp(binOp + 1, num);
        if (*nextBinOp == '%') {
            cout << "Error: Incorrected enter of numbers." << endl << endl;
            result = 0;
            return nextBinOp;
        }
        if (*binOp == '/' && !num) {
            cout << "Error: Division by zero." << endl << endl;
            result = 0;
            return binOp;
        }
        MultOrDivision(*binOp, result, num);
        binOp = nextBinOp;
    }
    //Если после умножений нет никаких операций - выход:
    if (!*binOp || *binOp == ')')
        return binOp;
    //Теперь наверняка операция либо + либо -:
    while (*binOp && *binOp != ')') {
        //Имеем первое слагаемое/член разности. Нужен
        //второй член: получим его, исключив умножение:
        char * nextBinOp = BinOp(binOp + 1, num);
        if (*nextBinOp == '%') {
            cout << "Error: Incorrected enter of numbers." << endl << endl;
            result = 0;
            return nextBinOp;
        }
        while (*nextBinOp == '*' || *nextBinOp == '/') {
            double bufferNum;
            char * next_nextBinOp = BinOp(nextBinOp + 1, bufferNum);
            if (*next_nextBinOp == '%') {
                cout << "Error: Incorrected enter of numbers." << endl << endl;
                result = 0;
                return next_nextBinOp;
            }
            if (*nextBinOp == '/' && !bufferNum) {
                cout << "Error: Division by zero." << endl << endl;
                result = 0;
                return nextBinOp;
            }
            MultOrDivision(*nextBinOp, num, bufferNum);
            nextBinOp = next_nextBinOp;
        }
        //Возвращаемся к знаку, полученному после первого
        //слагаемого/члена разности - применяем его:
        switch (*binOp) {
            case '+':
                result += num;
                break;
            case '-':
                result -= num;
                break;
        }
        //BinOp - знак '+', '-' или 0:
        binOp = nextBinOp;
    }
    return binOp;
}
0
0 / 0 / 0
Регистрация: 25.10.2009
Сообщений: 45
07.02.2013, 09:06  [ТС]
спасибо чувак) не можешь подсказать какой лучше цикл использовать для "пробежки" по выражению?
0
2 / 2 / 3
Регистрация: 19.01.2013
Сообщений: 32
07.02.2013, 09:44
В смысле пробежки? Перед вычислением я лишь пробегаю по выражению, чтобы убрать пробелы и проверить правильность скобочного выражения, а остальные ошибки проверяются уже во время рекурсии конкретно в функции BinOp. Если ты об этом) Стоило сделать так, чтобы все проверялось в рекурсии. Чтобы считать числа, цикл идет по символам до стречи со знаком операции или точки (вещественное число) или открывающей скобки. Ты об этом?)
0
0 / 0 / 0
Регистрация: 25.10.2009
Сообщений: 45
07.02.2013, 12:07  [ТС]
на формачке сделал один тексбокс и кнопку"расчитать". теперь думаю символы введенные в тексбокс нужно пихнуть в какой нить list или массив, а далее создать цикл который будет считывать из массива символы...
0
1057 / 864 / 195
Регистрация: 31.03.2010
Сообщений: 2,521
07.02.2013, 12:41
рекурсивный код очень сложный и подвержен ошибкам. посмотрите в википедии есть даже готовые программы по переводу в ОПЗ
0
2 / 2 / 3
Регистрация: 19.01.2013
Сообщений: 32
07.02.2013, 13:47
Цитата Сообщение от dron4ik Посмотреть сообщение
на формачке сделал один тексбокс и кнопку"расчитать". теперь думаю символы введенные в тексбокс нужно пихнуть в какой нить list или массив, а далее создать цикл который будет считывать из массива символы...
Затолкать символы в массив большого труда не составит, если действительно нужно использовать массив. Я не знаком с этим, но лучше бы посмотреть документацию на строки вC#

Цитата Сообщение от Learx Посмотреть сообщение
рекурсивный код очень сложный и подвержен ошибкам. посмотрите в википедии есть даже готовые программы по переводу в ОПЗ
Захотелось избежать использования ОПЗ и деревье и сделать программу, которая глотает выражение и выплевывает значение. Насчет того, какой подход эффективнее, я пока не знаю, и спорить не буду)
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6101 / 4957 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
07.02.2013, 14:08
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
using System;
using System.Collections.Generic;
using System.Text;
 
namespace MyMath
{
    public static class CalculateExpression
    {
        private static readonly Dictionary<string, byte> _opdict = new Dictionary<string, byte>
            {{"(", 0}, {"+", 1}, {"-", 2},{"/", 3}, {"*", 4}};
 
        private static readonly HashSet<string> _operators = new HashSet<string> { "+", "-", "/", "*" };
 
        private static string _input;
 
        private static double CalculateSimple(double a, double b, char op)
            //Выполняем нужное вычисление в зависимости от операции
        {
            switch (op)
            {
                case '+':
                    return a + b;
                case '-':
                    return a - b;
                case '*':
                    return a*b;
                case '/':
                    return a/b;
            }
            return 0;
        }
 
        private static double StackCalc(double a, double b, char op)
            //Так как из стека достаем в обратном порядке, требуется инвертировать левый и правый операнды
        {
            return CalculateSimple(b, a, op);
        }
 
        private static bool BadBreckets(string s) //Проверяем баланс скобок в строке
        {
            int i = 0;
            foreach (char c in s)
            {
                if (c == '(')
                    i++;
                else if (c == ')')
                    i--;
            }
            return i != 0;
        }
 
        private static string Reverse(string s) //Обращаем строку в обратный порядок
        {
            int length = s.Length;
            var sb = new StringBuilder(length, length);
            for (int i = length - 1; i >= 0; i--)
                sb.Append(s[i]);
            return sb.ToString();
        }
 
        public static string ToRPN() //Для более удобного анализа переводим в ОПН
        {
            var result = new StringBuilder(_input.Length);
            bool negative = false;
            var stack = new Stack<char>();
            foreach (char c in _input)
            {
                if (c == ' ') continue;
                if (c == '(')
                    stack.Push(c);
                else if (c == ')')
                    //Если встречаем закрывающую скобку, то вытряхиваем в строку все, до появления открывабщей скобки
                {
                    while (stack.Count > 0)
                    {
                        char a = stack.Pop();
                        if (a == '(') break;
                        result.Append(" " + a);
                    }
                }
                else if (_operators.Contains(c.ToString()))
                    //Иначе если это оператор, вытряхиваем все операторы с большим приоритетом в строку, после этого засовываемся сами в стек
                {
                    string op = c.ToString();
                    if (c == '-')
                    {
                        negative = true;
                        result.Append("0 "); //Используем математический подход a - b = a + (0 - b)
                        op = "+";
                    }
                    else
                        negative = false;
                    result.Append(" ");
                    while (stack.Count > 0 && _opdict[op] < _opdict[stack.Peek().ToString()])
                    {
                        result.Append(stack.Pop() + " ");
                    }
                    stack.Push(op[0]);
                }
                else
                {
                    if (negative)
                    {
                        result.Append('-');
                        negative = false;
                    }
                    result.Append(c);
                } //Если это не скобки и не операторы, то это цифра, добавляем к выходной строке, с учетом знака
            }
            while (stack.Count > 0) //Вытряхиваем в строку оставшиеся символы
                result.Append(" " + stack.Pop());
            return result.ToString();
        }
 
        public static string ToPN()
        {
            return Reverse(ToRPN());
        }
 
        public static double Calculate(string input)
            //Вычисляем выражение. Если формат ввода неправильный, возвращаем null
        {
            if (BadBreckets(input) || String.IsNullOrEmpty(input))
                return double.NaN;
            _input = input;
            string[] strings = ToRPN().Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
            var stack = new Stack<double>(input.Length/2);
            foreach (string s in strings)
            {
                if (_opdict.ContainsKey(s)) //Если оператор, то выполняем его над последними двумя элементами стека.
                {
                    if (stack.Count < 2)
                        if (s == "+" || s == "-")
                        {
                            stack.Push(StackCalc(stack.Pop(), 0, s[0]));
                            continue;
                        }
                        else return double.NaN;
                    stack.Push(StackCalc(stack.Pop(), stack.Pop(), s[0]));
                }
                else //Иначе это должно быть число, если вдруг что-то другое, то возвращаем null
                {
                    double a;
                    if (!double.TryParse(s, out a)) return double.NaN;
                    stack.Push(a);
                }
            }
            return Math.Round(stack.Peek(), 15);
            //В стеке остается единственный элемент, значение выражения, который возвращаем
        }
    }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
 
namespace MyMath
{
    class Program
    {
        static void Main()
        {
            while (true)
            {
                Console.WriteLine("Введите выражение для вычисления. Для выхода напишите exit");
                string s = Console.ReadLine();
                if (s == "exit")
                    return;
                double result = CalculateExpression.Calculate(s);
                Console.WriteLine(double.IsNaN(result) ? "Неправильный формат ввода" : result.ToString());
            }
        }
    }
}
Код туповат, но для 2*(2+2) работает
2
0 / 0 / 0
Регистрация: 25.10.2009
Сообщений: 45
08.02.2013, 09:05  [ТС]
как из тексбокса передать инфу (т.е. наше какое нить введеное выражаение типа (20-9)+1)) в массив?
0
1057 / 864 / 195
Регистрация: 31.03.2010
Сообщений: 2,521
11.02.2013, 18:51
у textBox есть поле Text, которое хранит строку. по сути дела строка - это массив символов.
если хотите хранить список выражений, то создайте List<string> - поле класса в него добавляйте строку методом Add
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
11.02.2013, 18:51
Помогаю со студенческими работами здесь

Необычный калькулятор
Здравствуйте! Необходима помощь в создании необычного калькулятора. Он должен выполнять простейшие функции сложения, вычитания,умножения и...

Необычный код - необычный результат.
Бросте на форму PaintBox и сделайте Align alClient. В OnPaint напишите так: procedure TForm1.PaintBox1Paint(Sender: TObject); var ...

Необычный баннер
У меня на рабочем столе windows 7 застрял вот такой необычный баннер поверх всех окон. диспетчер задач открывается лишь на доли секунд, как...

Необычный поиск
Здравствуйте. У меня есть задумка, в реализации которой, возникли затруднения... На картинке 111 изображён фрагмент из делфи, где уже...

Необычный foreach
копаясь к завалах чужого кода нащёл подобную каракозябру foreach ($_POST as $package_name =&gt; $is_enabled) { $app_type = $_POST; ...


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

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru