Пятница, 19 Апреля 2024, 01:03

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
Форум игроделов » Программирование » Программирование .NET » Задание по C# (Логическое задание для решения уравнений)
Задание по C#
gorlumfanДата: Четверг, 09 Октября 2014, 01:20 | Сообщение # 1
участник
Сейчас нет на сайте
Перейду сразу к сути вопроса. Есть задание:
тебе вводят арифметическое выражение в целых числах со скобками. Ты должен вывести результат.

Например, вводят: 3*(8-(9-3)+2*2)+1
Ты выводишь: 19

тебе вводят произвольное выражение, а ты его разбираешь и выводишь ответ.
Вводят с клавиатуры, во время работы программы, через Console.ReadLine.
Заранее ты выражение не знаешь, и в код программы подставить не можешь.

Честно говоря мыслей по поводу этой задачи не много. Лично я себе это представляю как. Вводим уравнение, записываем его в массив, в нем разбиваем на элементы. И уже после этого начинаем расчет.
Если есть у кого какие либо идеи по этому поводу, буду рад услышать.
HPlusDieseДата: Четверг, 09 Октября 2014, 02:14 | Сообщение # 2
участник
Сейчас нет на сайте
Цитата gorlumfan ()
Лично я себе это представляю как. Вводим уравнение, записываем его в массив, в нем разбиваем на элементы. И уже после этого начинаем расчет.

Почти верно.
Тебе нужна либа для парсинга или самому всё сделать нужно?
LertmindДата: Четверг, 09 Октября 2014, 09:17 | Сообщение # 3
заслуженный участник
Сейчас нет на сайте
Самый простой способ преобразовать в обратную польскую нотацию и посчитать. Она может быть неявно в алгоритме. Почти готовый код на C++ здесь. Ещё можно написать простой калькулятор без скобок, потом внутренние выражения в скобках заменять посчитанными значения, например 3*(8-(9-3)+2*2)+1 => 3*(8-6+2*2)+1 => 3*6 + 1 => 19, но это хреновый способ в плане производительности.
ZnOFFДата: Четверг, 09 Октября 2014, 09:28 | Сообщение # 4
частый гость
Сейчас нет на сайте
Есть ещё способ - "компиляция на лету". Компилятор сам всё это может посчитать. Зачем за него мозг напрягать?
gorlumfanДата: Четверг, 09 Октября 2014, 11:02 | Сообщение # 5
участник
Сейчас нет на сайте
Короче говоря, это точно не парсер. Как объяснил мой учитель, это "Задание чисто на манипулирование строками и данными, которые ты сам создаешь." Ребят не как не пойму как это реализовать, хоть направление дайте в котором капать )

Добавлено (09.10.2014, 11:02)
---------------------------------------------

Цитата ZnOFF ()
Есть ещё способ - "компиляция на лету". Компилятор сам всё это может посчитать. Зачем за него мозг напрягать?

Можно поподробнее про это ?)
VinchensooДата: Четверг, 09 Октября 2014, 11:17 | Сообщение # 6
Злобный социопат с комплексом Бога
Сейчас нет на сайте
Цитата gorlumfan ()
Короче говоря, это точно не парсер. Как объяснил мой учитель, это "Задание чисто на манипулирование строками и данными, которые ты сам создаешь." Ребят не как не пойму как это реализовать, хоть направление дайте в котором капать )

Это и есть парсер. Лол.
http://habrahabr.ru/post/199266/


HPlusDieseДата: Четверг, 09 Октября 2014, 11:26 | Сообщение # 7
участник
Сейчас нет на сайте
Цитата gorlumfan ()
хоть направление дайте в котором капать )

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


Сообщение отредактировал HPlusDiese - Четверг, 09 Октября 2014, 11:27
KamiRoninДата: Четверг, 09 Октября 2014, 11:48 | Сообщение # 8
почти ветеран
Сейчас нет на сайте
пример на разных языках для ОПН

Мыслю - значит программирую...
Конструктивная критика - умных ведет к совершенству...
Великие умы обсуждают идеи, средние - обсуждают поступки, а малые - людей.
gorlumfanДата: Пятница, 10 Октября 2014, 08:15 | Сообщение # 9
участник
Сейчас нет на сайте
Всем спасибо за помощь, но как сказал человек давший мне задание. Делаться это должно проще, чем эти 2 метода. Пока копаю дальше, может что пропустил.
LertmindДата: Пятница, 10 Октября 2014, 12:01 | Сообщение # 10
заслуженный участник
Сейчас нет на сайте
Цитата gorlumfan ()
но как сказал человек давший мне задание. Делаться это должно проще, чем эти 2 метода.
Плохой учитель у тебя, БЕГN. А вообще, раз он знает лучше, пусть тебе лучше и объяснит чего хочет.
gorlumfanДата: Вторник, 04 Ноября 2014, 01:53 | Сообщение # 11
участник
Сейчас нет на сайте
Ребят после продолжительной читалки книжек и сети + советы учителя написал следующий код. Код рабочий все правильно делает. И спасибо кстати за подсказку относительно польской нотации, сразу не разобрал что к чему. Так вот собственно вопрос, программа считывает пример -> преобразует его в ОПН -> затем считает. Но проблема в том, что лишь по 1 символу. Как можно с этим побороться ? Если это поможет то вот мой код
Код
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
      class Program
      {
          static void Main(string[] args)
          {
              string m = Console.ReadLine();
              Console.WriteLine("Эта же запись но в посфиксном виде " + Postfix(m));
              Console.WriteLine("Ответ " + Equal(Postfix(m)));
              Console.ReadLine();//Задержка экрана
          }
          //
          //Функция превращения строки в постфиксную запись
          static string Postfix(string Input)
          {
              var MyStack = new Stack<char>();//Объявлен стек для операций
              string x = null;
              int y;
              //Цикл превращение строки в постфиксную
              for (int i = 0; i < Input.Length; i++)
              {

                  if (Char.IsDigit(Input[i]))//Проверяем входной символ, если число
                  {
                      x += Convert.ToString(Input[i]);
                  }
                  else //Если символ, производим его разбор
                  {
                      y = Prior(Input[i]);// Назначаем приоритет для входящего символа
                      if (MyStack.Count == 0) //Если стек пустой
                      {
                          MyStack.Push(Input[i]);//Закидываем знак в стек
                      }
                      else //Если стек имеет какие либо значения
                      {
                          if (y != Prior(MyStack.Peek()))//Если символы по приоритету не ровны
                          {
                    if (y > Prior(MyStack.Peek()))//Если приоритет входящего символа больше имеющегося
                    {
                     MyStack.Push(Input[i]);
                    }
                    else
                     if (y < Prior(MyStack.Peek()))
                     {

                     if (y == 2) //Если символ является закрывающей скобкой
                     {
                     if (MyStack.Peek() == '(') //Если на вершине стека находится открывающая скобка
                     {
                     MyStack.Pop();
                     }
                     else
                     if (MyStack.Peek() != '(') //Если не равен открывающей скобке
                     {
                     while (MyStack.Peek() != '(')//Пока на вершине стека не будет открывающей скобки,
                     {
                     x += MyStack.Pop(); //Выталкиваем в строку символы
                     }
                     MyStack.Pop();
                     }
                     }
                     else
                     {
                     if (y == 1) //Если равен открывающей скобке
                     {
                     MyStack.Push(Input[i]);
                     }
                     else
                     {
                     x += MyStack.Pop();
                     MyStack.Push(Input[i]);
                     }

                     }
                     }
                          }
                          else
                    if (y == Prior(MyStack.Peek()))//Если символы ровны
                    {
                     x += MyStack.Pop();//Из вершины стека выкидываем символ в строку
                     MyStack.Push(Input[i]);//Кладем в стек новый символ
                    }

                      }
                  }

              }
              while (MyStack.Count > 0)//Выкидываем остаток символов из стека
              {
                  x += MyStack.Pop();
              }
              return x;//Возвращаем строку в постфиксной записи
          }

          //
          //Функция подсчета   
          static int Equal(string Input)
          {
              var MyStack = new Stack<int>();
              int a = 0, b = 0;
              for (int i = 0; i < Input.Length; i++)
              {
                  if (Char.IsDigit(Input[i]))//Если число то,   
                  {
                      MyStack.Push(CharsToInt(Input[i]));
                  }
                  else //иначе
                  {
                      Console.WriteLine("В стаке кол-во элементов " + MyStack.Count);
                      a = MyStack.Pop();//Выкидываем первое число
                      Console.WriteLine("Первое число " + a);
                      b = MyStack.Pop();//Выкидываем второе число
                      Console.WriteLine("Второе число " + b);

                      switch (Input[i])//Переключатель для определения действий над числами
                      {
                          //Модуль возведения в степень не работает правильно (работает только с положительными числами)
                          case '^': Console.WriteLine("Знак операции ^");
                    a = Convert.ToInt32(Math.Pow(a, b));
                    Console.WriteLine("Значение x " + a);
                    MyStack.Push(a); break;
                          case '*': Console.WriteLine("Знак операции *");
                    a = b * a;
                    Console.WriteLine("Значение x " + a);
                    MyStack.Push(a); break;
                          case '/': Console.WriteLine("Знак операции /");
                    if (a == 0)
                    {
                     a = 0;
                    }
                    else
                    {
                     a = b / a;
                    }
                    Console.WriteLine("Значение x " + a);
                    MyStack.Push(a); break;
                          case '+': Console.WriteLine("Знак операции +");
                    a = b + a;
                    Console.WriteLine("Значение x " + a);
                    MyStack.Push(a); break;
                          case '-': Console.WriteLine("Знак операции -");
                    a = b - a;
                    Console.WriteLine("Значение x " + a);
                    MyStack.Push(a); break;
                      }
                  }
              }
              return a;
          }

          //Функция обработки числа из char в int
          static int CharsToInt(char Input)
          {
              int x = 0, y = 0;
              //кол-во итераций в данном случае равно a.Length

              x = Input - '0'; //Переводит из char в int число справа на левово
              y = y * 10 + x;

              return y;
          }

          //
          //Функция обработки числа из char[] в int
          static int CharsArrToInt(char[] Input)
          {
              int x = 0, y = 0;
              //кол-во итераций в данном случае равно a.Length
              for (int power = 0; power < Input.Length; power++) //Цикл обработки числа из Char в Int
              {
                  x = (Input[power] - '0'); //Переводит из char в int число справа на левово
                  y = y * 10 + x;
              }
              return y;
          }
          //
          //Функция приоритета знаков
          static int Prior(char Input)
          {
              switch (Input) //Получаем на входе символ, и возвращаем его приоритет.
              {
                  case '^': return 6;
                  case '*': return 5;
                  case '/': return 5;
                  case '+': return 4;
                  case '-': return 4;
                  case '=': return 3;
                  case ')': return 2;
                  case '(': return 1;
                  default: return 0;
              }

          }
      }
}


Сообщение отредактировал gorlumfan - Вторник, 04 Ноября 2014, 01:59
LertmindДата: Вторник, 04 Ноября 2014, 06:20 | Сообщение # 12
заслуженный участник
Сейчас нет на сайте
В string Postfix(string Input) внутри if (Char.IsDigit(Input[i])) {} записать:
Код
if (i > 0 && !Char.IsDigit(Input[i - 1]))
     x += " ";
x += Convert.ToString(Input[i]);

Тогда в постфиксной записи будут пробелы между числами, например для "(10+1)*23" будет " 10 1+ 23*".

В int Equal(string Input) объявляем переменную string number = ""; и вместо if (Char.IsDigit(Input[i])) {} else { записать:
Код
if (Char.IsDigit(Input[i]))//Если число то,    
{
     number += Input[i];
     if (i + 1 == Input.Length || !Char.IsDigit(Input[i + 1]))
     {
         MyStack.Push(int.Parse(number));
         number = "";
     }
}
else if (Prior(Input[i]) > 0)//иначе
{

В number будет собираться число. Если следующий символ не цифра или конец строки, то добавляем в стек число (можешь написать свою функцию преобразования из строки в число вместо int.Parse(), хотя ты зачем-то уже написал CharsArrToInt() ). Проверка if (Prior(Input[i]) > 0) нужна, чтобы проходили только символы операций, а всякие пробелы и прочий мусор игнорировались.

Полный код (протестил только для (10+1)*23, должно работать для всего):
Код
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
     class Program
     {
         static void Main(string[] args)
         {
             string m = Console.ReadLine();
             Console.WriteLine("Эта же запись но в посфиксном виде " + Postfix(m));
             Console.WriteLine("Ответ " + Equal(Postfix(m)));
             Console.ReadLine();//Задержка экрана
         }
         //
         //Функция превращения строки в постфиксную запись
         static string Postfix(string Input)
         {
             var MyStack = new Stack<char>();//Объявлен стек для операций
             string x = null;
             int y;
             //Цикл превращение строки в постфиксную
             for (int i = 0; i < Input.Length; i++)
             {

                 if (Char.IsDigit(Input[i]))//Проверяем входной символ, если число
                 {
                     if (i > 0 && !Char.IsDigit(Input[i - 1]))
                         x += " ";
                     x += Convert.ToString(Input[i]);
                 }
                 else //Если символ, производим его разбор
                 {
                     y = Prior(Input[i]);// Назначаем приоритет для входящего символа
                     if (MyStack.Count == 0) //Если стек пустой
                     {
                         MyStack.Push(Input[i]);//Закидываем знак в стек
                     }
                     else //Если стек имеет какие либо значения
                     {
                         if (y != Prior(MyStack.Peek()))//Если символы по приоритету не ровны
                         {
                             if (y > Prior(MyStack.Peek()))//Если приоритет входящего символа больше имеющегося
                             {
                    MyStack.Push(Input[i]);
                             }
                             else
                    if (y < Prior(MyStack.Peek()))
                    {

                    if (y == 2) //Если символ является закрывающей скобкой
                    {
                    if (MyStack.Peek() == '(') //Если на вершине стека находится открывающая скобка
                    {
                    MyStack.Pop();
                    }
                    else
                    if (MyStack.Peek() != '(') //Если не равен открывающей скобке
                    {
                    while (MyStack.Peek() != '(')//Пока на вершине стека не будет открывающей скобки,
                    {
                    x += MyStack.Pop(); //Выталкиваем в строку символы
                    }
                    MyStack.Pop();
                    }
                    }
                    else
                    {
                    if (y == 1) //Если равен открывающей скобке
                    {
                    MyStack.Push(Input[i]);
                    }
                    else
                    {
                    x += MyStack.Pop();
                    MyStack.Push(Input[i]);
                    }

                    }
                    }
                         }
                         else
                             if (y == Prior(MyStack.Peek()))//Если символы ровны
                             {
                    x += MyStack.Pop();//Из вершины стека выкидываем символ в строку
                    MyStack.Push(Input[i]);//Кладем в стек новый символ
                             }

                     }
                 }

             }
             while (MyStack.Count > 0)//Выкидываем остаток символов из стека
             {
                 x += MyStack.Pop();
             }
             return x;//Возвращаем строку в постфиксной записи
         }

         //
         //Функция подсчета    
         static int Equal(string Input)
         {
             var MyStack = new Stack<int>();
             int a = 0, b = 0;
             string number = "";
             for (int i = 0; i < Input.Length; i++)
             {
                 if (Char.IsDigit(Input[i]))//Если число то,    
                 {
                     number += Input[i];
                     if (i + 1 == Input.Length || !Char.IsDigit(Input[i + 1]))
                     {
                         MyStack.Push(int.Parse(number));
                         number = "";
                     }
                 }
                 else if (Prior(Input[i]) > 0)//иначе
                 {
                     Console.WriteLine("В стаке кол-во элементов " + MyStack.Count);
                     a = MyStack.Pop();//Выкидываем первое число
                     Console.WriteLine("Первое число " + a);
                     b = MyStack.Pop();//Выкидываем второе число
                     Console.WriteLine("Второе число " + b);

                     switch (Input[i])//Переключатель для определения действий над числами
                     {
                         //Модуль возведения в степень не работает правильно (работает только с положительными числами)
                         case '^': Console.WriteLine("Знак операции ^");
                             a = Convert.ToInt32(Math.Pow(a, b));
                             Console.WriteLine("Значение x " + a);
                             MyStack.Push(a); break;
                         case '*': Console.WriteLine("Знак операции *");
                             a = b * a;
                             Console.WriteLine("Значение x " + a);
                             MyStack.Push(a); break;
                         case '/': Console.WriteLine("Знак операции /");
                             if (a == 0)
                             {
                    a = 0;
                             }
                             else
                             {
                    a = b / a;
                             }
                             Console.WriteLine("Значение x " + a);
                             MyStack.Push(a); break;
                         case '+': Console.WriteLine("Знак операции +");
                             a = b + a;
                             Console.WriteLine("Значение x " + a);
                             MyStack.Push(a); break;
                         case '-': Console.WriteLine("Знак операции -");
                             a = b - a;
                             Console.WriteLine("Значение x " + a);
                             MyStack.Push(a); break;
                     }
                 }
             }
             return a;
         }

         //Функция обработки числа из char в int
         static int CharsToInt(char Input)
         {
             int x = 0, y = 0;
             //кол-во итераций в данном случае равно a.Length

             x = Input - '0'; //Переводит из char в int число справа на левово
             y = y * 10 + x;

             return y;
         }

         //
         //Функция обработки числа из char[] в int
         static int CharsArrToInt(char[] Input)
         {
             int x = 0, y = 0;
             //кол-во итераций в данном случае равно a.Length
             for (int power = 0; power < Input.Length; power++) //Цикл обработки числа из Char в Int
             {
                 x = (Input[power] - '0'); //Переводит из char в int число справа на левово
                 y = y * 10 + x;
             }
             return y;
         }
         //
         //Функция приоритета знаков
         static int Prior(char Input)
         {
             switch (Input) //Получаем на входе символ, и возвращаем его приоритет.
             {
                 case '^': return 6;
                 case '*': return 5;
                 case '/': return 5;
                 case '+': return 4;
                 case '-': return 4;
                 case '=': return 3;
                 case ')': return 2;
                 case '(': return 1;
                 default: return 0;
             }

         }
     }
}

Добавлено (04.11.2014, 06:20)
---------------------------------------------
На самом деле, твой код не работает с унарным минусом ("-1" фейл). Ещё ты неправильно возводишь в степень, во-первых, надо записать a = Convert.ToInt32(Math.Pow(b, a));, во-вторых, возведение в степень правоассоциативная операция и для, например 2^2^3, должно быть 2^(2^3), а не (2^2)^3 как в твоей программе, опять же прочитай внизу здесь. Замечу, что для "0-2^2^3" должен быть результат -256, а для "(0-2)^2^3" уже 256 (если сделаешь унарный минус, то 0 приписывать не надо).

gorlumfanДата: Вторник, 04 Ноября 2014, 13:20 | Сообщение # 13
участник
Сейчас нет на сайте
Lertmind, Спасибо за разъяснение, как будет возможность обязательно попробую переделать )
Форум игроделов » Программирование » Программирование .NET » Задание по C# (Логическое задание для решения уравнений)
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг