-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
Стековый калькулятор
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
using System.Runtime.CompilerServices; | ||
using Microsoft.VisualBasic; | ||
using Microsoft.VisualBasic.FileIO; | ||
using Stack; | ||
|
||
namespace CalculatorNamespace; | ||
|
||
/// <summary> | ||
/// Класс, содержищий в себе метод для вычисления выражений, записанных в постфиксной записи | ||
/// </summary> | ||
public class Calculator | ||
{ | ||
/// <summary> | ||
/// Метод для вычисления выражений, записанных в постфиксной записи | ||
/// </summary> | ||
/// <param name="expression">Выражение в постфиксной записи</param> | ||
/// <param name="stack">Стек, реализующий интерфейс IStack. С помощью него калькулятор будет вычислять значение выражения </param> | ||
/// <returns></returns> | ||
public static Tuple<double, ErrorCode> Evaluate(string expression, IStack stack) | ||
{ | ||
if (expression == null || expression == string.Empty) | ||
{ | ||
return Tuple.Create(-1.0, ErrorCode.ExpressionIsNull); | ||
} | ||
|
||
Array elements = expression.Split(" "); | ||
foreach (string item in elements) | ||
{ | ||
if (int.TryParse(item, out int number)) | ||
{ | ||
stack.Add((double)number); | ||
} | ||
else | ||
{ | ||
if (item.Length != 1) | ||
{ | ||
return Tuple.Create(-1.0, ErrorCode.WrongOperator); | ||
} | ||
(double number2, bool notEmpty2) = stack.Pop(); | ||
if (notEmpty2) | ||
{ | ||
(double number1, bool notEmpty1) = stack.Pop(); | ||
if (notEmpty1) | ||
{ | ||
(double result, ErrorCode ec) = Operation(number1, number2, item[0]); | ||
if (ec != ErrorCode.Ok) | ||
{ | ||
return Tuple.Create(-1.0, ec); | ||
} | ||
stack.Add(result); | ||
} | ||
|
||
} | ||
} | ||
} | ||
(double answer, bool notEmpty) = stack.Pop(); | ||
return Tuple.Create(answer, ErrorCode.Ok); | ||
} | ||
|
||
private static Tuple<double, ErrorCode> Operation(double number1, double number2, char op) | ||
{ | ||
switch (op) | ||
{ | ||
case '+': | ||
{ | ||
return Tuple.Create(number1 + number2, ErrorCode.Ok); | ||
} | ||
case '-': | ||
{ | ||
return Tuple.Create(number1 - number2, ErrorCode.Ok); | ||
} | ||
case '/': | ||
{ | ||
if (Math.Abs(number2) < double.Epsilon) | ||
{ | ||
return Tuple.Create(0.0, ErrorCode.DivisionByZero); | ||
} | ||
return Tuple.Create(number1 / number2, ErrorCode.Ok); | ||
} | ||
case '*': | ||
{ | ||
return Tuple.Create(number1 * number2, ErrorCode.Ok); | ||
} | ||
default: | ||
return Tuple.Create(-1.0, ErrorCode.WrongOperator); | ||
} | ||
} | ||
|
||
private static void ClearStack(IStack stack) | ||
{ | ||
while (stack.Size() > 0) | ||
{ | ||
stack.Pop(); | ||
} | ||
} | ||
|
||
public enum ErrorCode | ||
{ | ||
Ok, | ||
DivisionByZero, | ||
WrongOperator, | ||
ExpressionIsNull | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using Microsoft.VisualBasic; | ||
|
||
namespace Stack; | ||
|
||
/// <summary> | ||
/// Интерфейс для создания стека, хранящего значения типа double | ||
/// </summary> | ||
public interface IStack | ||
{ | ||
/// <summary> | ||
/// Метод для добавления элемента типа double в стек | ||
/// </summary> | ||
/// <param name="element">Элемент, который необходимо добавить</param> | ||
void Add(double element); | ||
|
||
/// <summary> | ||
/// Метод для извлечения верхнего элемента из стека | ||
/// </summary> | ||
/// <returns>double - значение верхнего элемента (-1, если его не было) и bool - true, если элемент был в стеке, false, если не было</returns> | ||
Tuple<double, bool> Pop(); | ||
|
||
/// <summary> | ||
/// Количество элементов в стеке | ||
/// </summary> | ||
int Size(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
namespace Stack; | ||
|
||
|
||
/// <summary> | ||
/// Реализация IStack с помощью списков | ||
/// </summary> | ||
public class ListStack : IStack | ||
{ | ||
public ListStack() | ||
{ | ||
this.list = new List<double>(); | ||
} | ||
|
||
public void Add(double element) | ||
{ | ||
this.list.Add(element); | ||
} | ||
|
||
public Tuple<double, bool> Pop() | ||
{ | ||
double value = -1; | ||
bool notEmpty = false; | ||
if (this.list.Count > 0) | ||
{ | ||
notEmpty = true; | ||
value = this.list[this.list.Count - 1]; | ||
this.list.RemoveAt(this.list.Count - 1); | ||
} | ||
return Tuple.Create(value, notEmpty); | ||
} | ||
|
||
public int Size() | ||
{ | ||
return list.Count; | ||
} | ||
|
||
private List<double> list; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using System.ComponentModel.DataAnnotations; | ||
using CalculatorNamespace; | ||
using Stack; | ||
|
||
class Program | ||
{ | ||
|
||
public static void Main() | ||
{ | ||
Console.Write("Введите выражение: "); | ||
string? expression = Console.ReadLine(); | ||
var listStack = new ListStack(); | ||
var stackWithNodes = new StackWithNodes(); | ||
(double answer1, Calculator.ErrorCode ec1) = Calculator.Evaluate(expression, listStack); | ||
Check warning on line 14 in Calculator/Calculator.Src/Program.cs GitHub Actions / build-Windows
Check warning on line 14 in Calculator/Calculator.Src/Program.cs GitHub Actions / build-Windows
Check warning on line 14 in Calculator/Calculator.Src/Program.cs GitHub Actions / build-Ubuntu_and_MacOs (ubuntu-latest)
Check warning on line 14 in Calculator/Calculator.Src/Program.cs GitHub Actions / build-Ubuntu_and_MacOs (macos-latest)
|
||
(double answer2, Calculator.ErrorCode ec2) = Calculator.Evaluate(expression, stackWithNodes); | ||
if (ec1 == Calculator.ErrorCode.Ok && ec2 == Calculator.ErrorCode.Ok) | ||
{ | ||
Console.WriteLine($"Результат работы при использовании стека на списках: {answer1}\nБез списков: {answer2}"); | ||
} | ||
else if (ec1 == Calculator.ErrorCode.DivisionByZero || ec2 == Calculator.ErrorCode.DivisionByZero) | ||
{ | ||
Console.WriteLine("Вы не можете делить на ноль"); | ||
} | ||
else if (ec1 == Calculator.ErrorCode.WrongOperator || ec2 == Calculator.ErrorCode.WrongOperator) | ||
{ | ||
Console.WriteLine("Проверьте правильность ввода"); | ||
} | ||
else if (ec1 == Calculator.ErrorCode.ExpressionIsNull || ec2 == Calculator.ErrorCode.ExpressionIsNull) | ||
{ | ||
Console.WriteLine("Выражение не может быть пустой строкой"); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
using System.Diagnostics; | ||
|
||
namespace Stack; | ||
|
||
/// <summary> | ||
/// Реализация IStack с помощью встроенного класса Node | ||
/// </summary> | ||
public class StackWithNodes : IStack | ||
{ | ||
private class Node | ||
{ | ||
public Node() | ||
{ | ||
this.value = 0; | ||
} | ||
|
||
public double value; | ||
public Node? next; | ||
} | ||
|
||
public StackWithNodes() | ||
{ | ||
top = new Node(); | ||
} | ||
|
||
|
||
public void Add(double element) | ||
{ | ||
Node newNode = new Node(); | ||
newNode.next = this.top; | ||
newNode.value = element; | ||
this.top = newNode; | ||
++this.count; | ||
} | ||
|
||
public Tuple<double, bool> Pop() | ||
{ | ||
double answer = -1.0; | ||
bool notEmpty = false; | ||
if (this.count > 0) | ||
{ | ||
Node next = this.top.next; | ||
Check warning on line 42 in Calculator/Calculator.Src/StackWithNodes.cs GitHub Actions / build-Windows
Check warning on line 42 in Calculator/Calculator.Src/StackWithNodes.cs GitHub Actions / build-Windows
Check warning on line 42 in Calculator/Calculator.Src/StackWithNodes.cs GitHub Actions / build-Ubuntu_and_MacOs (ubuntu-latest)
|
||
answer = this.top.value; | ||
this.top = next; | ||
Check warning on line 44 in Calculator/Calculator.Src/StackWithNodes.cs GitHub Actions / build-Windows
Check warning on line 44 in Calculator/Calculator.Src/StackWithNodes.cs GitHub Actions / build-Windows
Check warning on line 44 in Calculator/Calculator.Src/StackWithNodes.cs GitHub Actions / build-Ubuntu_and_MacOs (ubuntu-latest)
|
||
notEmpty = true; | ||
--this.count; | ||
} | ||
return Tuple.Create(answer, notEmpty); | ||
} | ||
|
||
public int Size() | ||
{ | ||
return this.count; | ||
} | ||
|
||
public int count { get; private set; } | ||
private Node top; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
|
||
<IsPackable>false</IsPackable> | ||
<IsTestProject>true</IsTestProject> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="coverlet.collector" Version="6.0.0" /> | ||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" /> | ||
<PackageReference Include="NUnit" Version="3.14.0" /> | ||
<PackageReference Include="NUnit.Analyzers" Version="3.9.0" /> | ||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Using Include="NUnit.Framework" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Calculator.Src\Calculator.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
namespace Calculator.Tests; | ||
|
||
using System.Collections.Specialized; | ||
using System.Runtime.CompilerServices; | ||
using System.Security.Cryptography; | ||
using CalculatorNamespace; | ||
using Stack; | ||
|
||
public class Tests | ||
{ | ||
public static readonly string[] expressions = ["5 7 +", "5 -7 +", "5 0 +", | ||
"5 25 *", "7 -15 *", "-10 -14 *", "-10 0 *", "6 0 /", "10 2 /", "-5 2 /", | ||
"dfsgfvx", ""]; | ||
private static readonly double[] expectedAnswers = [12.0, -2.0, 5.0, 125.0, -105.0, | ||
140.0, 0.0, -1, 5.0, -2.5, -1, -1]; | ||
private static readonly Calculator.ErrorCode[] expectedErrorCodes = | ||
[Calculator.ErrorCode.Ok, | ||
Calculator.ErrorCode.Ok, | ||
Calculator.ErrorCode.Ok, | ||
Calculator.ErrorCode.Ok, | ||
Calculator.ErrorCode.Ok, | ||
Calculator.ErrorCode.Ok, | ||
Calculator.ErrorCode.Ok, | ||
Calculator.ErrorCode.DivisionByZero, | ||
Calculator.ErrorCode.Ok, | ||
Calculator.ErrorCode.Ok, | ||
Calculator.ErrorCode.WrongOperator, | ||
Calculator.ErrorCode.ExpressionIsNull]; | ||
|
||
private static IEnumerable<(string, double, Calculator.ErrorCode, IStack)> InputData | ||
{ | ||
get | ||
{ | ||
for (int i = 0; i < expressions.Length; ++i) | ||
{ | ||
yield return new(expressions[i], expectedAnswers[i], expectedErrorCodes[i], new ListStack()); | ||
yield return new(expressions[i], expectedAnswers[i], expectedErrorCodes[i], new StackWithNodes()); | ||
} | ||
} | ||
} | ||
|
||
[TestCaseSource(nameof(InputData))] | ||
public void CalculationTest((string, double, Calculator.ErrorCode, IStack) inputData) | ||
{ | ||
(var expression, var expectedAnswer, var errorCode, var stack) = inputData; | ||
(double answer, Calculator.ErrorCode ec) = Calculator.Evaluate(expression, stack); | ||
Assert.Multiple(() => | ||
{ | ||
Assert.That(ec, Is.EqualTo(errorCode)); | ||
if (errorCode == Calculator.ErrorCode.Ok) | ||
{ | ||
Assert.That(answer, Is.EqualTo(expectedAnswer).Within(double.Epsilon)); | ||
} | ||
}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.0.31903.59 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Calculator", "Calculator.Src\Calculator.csproj", "{72690AF6-3603-47BC-8BCC-81F8AA9E2513}" | ||
EndProject | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Calculator.Tests", "Calculator.Tests\Calculator.Tests.csproj", "{32426C3E-47BA-4FD3-89F3-F3ECDD3B7773}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{72690AF6-3603-47BC-8BCC-81F8AA9E2513}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{72690AF6-3603-47BC-8BCC-81F8AA9E2513}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{72690AF6-3603-47BC-8BCC-81F8AA9E2513}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{72690AF6-3603-47BC-8BCC-81F8AA9E2513}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{32426C3E-47BA-4FD3-89F3-F3ECDD3B7773}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{32426C3E-47BA-4FD3-89F3-F3ECDD3B7773}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{32426C3E-47BA-4FD3-89F3-F3ECDD3B7773}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{32426C3E-47BA-4FD3-89F3-F3ECDD3B7773}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
EndGlobal |