mirror of
https://github.com/0xJ1M/MathsEngine.git
synced 2026-06-04 23:10:09 +00:00
Feature/implement exponentiation (#6)
* Modified System to make each numeric node a non-generic for now. Implemented decimal exponentation. This is a draft implementation and is not intended for final release * Reverted change to NumericNode and fixed tests
This commit is contained in:
@@ -78,10 +78,8 @@ namespace EngineTests.Parser_Tests.Nodes
|
||||
[TestMethod]
|
||||
public void TestNodeFactoryNumericNodesOnDefinedTypes()
|
||||
{
|
||||
Token test_token1 = new("100", Token.Type.Numeric, Token.NumericType.Integer, 0);
|
||||
Token test_token2 = new("100.5", Token.Type.Numeric, Token.NumericType.Decimal, 0);
|
||||
|
||||
BaseNode testNode1 = NodeFactory.CreateNumericNode(test_token1);
|
||||
BaseNode testNode2 = NodeFactory.CreateNumericNode(test_token2);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Parser\Nodes\NumericIntegerNode.cs" />
|
||||
<Compile Remove="Parser\Nodes\TreeNode.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -105,6 +105,28 @@ namespace MathEngine.Parser.Parser
|
||||
return lhs.Divide(rhs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base method for exponentiating two nodes, returning another BaseNode object
|
||||
/// </summary>
|
||||
/// <param name="otherNode">The node which will be the power to raise the current instance to</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
protected virtual BaseNode Exponentiate(BaseNode otherNode)
|
||||
{
|
||||
throw new InvalidOperationException("Attempted to call BaseNode _exponentiate, which is invalid!");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base operator for exponentiating two Base Nodes
|
||||
/// </summary>
|
||||
/// <param name="lhs">The left BaseNode</param>
|
||||
/// <param name="rhs">The right BaseNode</param>
|
||||
/// <returns>The exponentiating of the two BaseNodes, as defined by the calling type</returns>
|
||||
public static BaseNode operator ^(BaseNode lhs, BaseNode rhs)
|
||||
{
|
||||
return lhs.Exponentiate(rhs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Abstract Base method that evaluates the current Node
|
||||
/// </summary>
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace MathEngine.Parser.Parser
|
||||
case Token.Type.Division:
|
||||
return new BinaryNode(LeftBranch, RightBranch, (a, b) => a / b);
|
||||
case Token.Type.Exponentiation:
|
||||
throw new NotImplementedException("Exponentiation is not implemented at this time");
|
||||
return new BinaryNode(LeftBranch, RightBranch, (a, b) => a ^ b);
|
||||
default:
|
||||
throw new NotImplementedException("Attempted to create a BinaryNode with an invalid operation!");
|
||||
}
|
||||
@@ -43,11 +43,11 @@ namespace MathEngine.Parser.Parser
|
||||
switch (CurrentToken.NumericalType)
|
||||
{
|
||||
case Token.NumericType.Integer:
|
||||
return new NumericNode<Int64>(Int64.Parse(CurrentToken.TokenValue));
|
||||
throw new NotImplementedException("Integer Numbers are not implemented at this time");
|
||||
case Token.NumericType.Decimal:
|
||||
return new NumericNode<Decimal>(Decimal.Parse(CurrentToken.TokenValue));
|
||||
return new NumericNode<decimal>(Decimal.Parse(CurrentToken.TokenValue));
|
||||
case Token.NumericType.Complex:
|
||||
throw new NotImplementedException("Complex Numbers are not implemented at this time");
|
||||
throw new NotImplementedException("Complex Numbers are not implemented at this time");
|
||||
default:
|
||||
throw new InvalidDataException("Attempted to create a NumericNode with non numeric data!");
|
||||
}
|
||||
|
||||
90
MathEngine/MathEngine/Parser/Nodes/NumericIntegerNode.cs
Normal file
90
MathEngine/MathEngine/Parser/Nodes/NumericIntegerNode.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using MathEngine.Parser.Parser;
|
||||
using MathEngine.Parser.Parser.Nodes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MathEngine.Parser.Nodes
|
||||
{
|
||||
internal class NumericIntegerNode: BaseNode
|
||||
{
|
||||
private readonly decimal Value;
|
||||
|
||||
/// <summary>
|
||||
/// Initialises a new instance of a NumericNode with a given Token
|
||||
/// </summary>
|
||||
/// <param name="value">The token for the nodes value</param>
|
||||
public NumericIntegerNode(decimal value)
|
||||
{
|
||||
this.Children = null;
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
protected override BaseNode Add(BaseNode otherNode)
|
||||
{
|
||||
if (otherNode is NumericIntegerNode)
|
||||
{
|
||||
NumericIntegerNode rhs = (NumericIntegerNode)otherNode;
|
||||
return new NumericIntegerNode(Value + rhs.Value);
|
||||
}
|
||||
throw new InvalidOperationException("Attempted Invalid operation");
|
||||
}
|
||||
|
||||
protected override BaseNode Subtract(BaseNode otherNode)
|
||||
{
|
||||
if (otherNode is NumericIntegerNode)
|
||||
{
|
||||
NumericIntegerNode rhs = (NumericIntegerNode)otherNode;
|
||||
return new NumericIntegerNode(Value - rhs.Value);
|
||||
}
|
||||
throw new InvalidOperationException("Attempted Invalid operation");
|
||||
}
|
||||
|
||||
protected override BaseNode Multiply(BaseNode otherNode)
|
||||
{
|
||||
if (otherNode is NumericIntegerNode)
|
||||
{
|
||||
NumericIntegerNode rhs = (NumericIntegerNode)otherNode;
|
||||
return new NumericIntegerNode(Value * rhs.Value);
|
||||
}
|
||||
throw new InvalidOperationException("Attempted Invalid operation");
|
||||
}
|
||||
|
||||
protected override BaseNode Divide(BaseNode otherNode)
|
||||
{
|
||||
if (otherNode is NumericIntegerNode)
|
||||
{
|
||||
NumericIntegerNode rhs = (NumericIntegerNode)otherNode;
|
||||
return new NumericIntegerNode(Value / rhs.Value);
|
||||
}
|
||||
throw new InvalidOperationException("Attempted Invalid operation");
|
||||
}
|
||||
|
||||
protected override BaseNode Exponentiate(BaseNode otherNode)
|
||||
{
|
||||
if (otherNode is NumericIntegerNode)
|
||||
{
|
||||
NumericIntegerNode rhs = (NumericIntegerNode)otherNode;
|
||||
return new NumericIntegerNode((Int64)(Math.Pow((double)(Value), (double)rhs.Value)));
|
||||
}
|
||||
throw new InvalidOperationException("Attempted Invalid operation");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the Numeric Node by simply returning the current instance
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override BaseNode Evaluate()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,15 +5,15 @@ namespace MathEngine.Parser.Parser.Nodes
|
||||
/// <summary>
|
||||
/// Represents a Tree node that can store a numeric value
|
||||
/// </summary>
|
||||
internal class NumericNode<T> : BaseNode where T: INumber<T>
|
||||
internal class NumericNode<T> : BaseNode where T: INumber<T>
|
||||
{
|
||||
private readonly T Value;
|
||||
private readonly decimal Value;
|
||||
|
||||
/// <summary>
|
||||
/// Initialises a new instance of a NumericNode with a given Token
|
||||
/// </summary>
|
||||
/// <param name="value">The token for the nodes value</param>
|
||||
public NumericNode(T value)
|
||||
public NumericNode(decimal value)
|
||||
{
|
||||
this.Children = null;
|
||||
this.Value = value;
|
||||
@@ -21,40 +21,50 @@ namespace MathEngine.Parser.Parser.Nodes
|
||||
|
||||
protected override BaseNode Add(BaseNode otherNode)
|
||||
{
|
||||
if (otherNode is NumericNode<T>)
|
||||
if (otherNode is NumericNode<decimal>)
|
||||
{
|
||||
NumericNode<T> rhs = (NumericNode<T>)otherNode;
|
||||
return new NumericNode<T>(Value + rhs.Value);
|
||||
NumericNode<decimal> rhs = (NumericNode<decimal>)otherNode;
|
||||
return new NumericNode<decimal>(Value + rhs.Value);
|
||||
}
|
||||
throw new InvalidOperationException("Attempted Invalid operation");
|
||||
}
|
||||
|
||||
protected override BaseNode Subtract(BaseNode otherNode)
|
||||
{
|
||||
if (otherNode is NumericNode<T>)
|
||||
if (otherNode is NumericNode<decimal>)
|
||||
{
|
||||
NumericNode<T> rhs = (NumericNode<T>)otherNode;
|
||||
return new NumericNode<T>(Value - rhs.Value);
|
||||
NumericNode<decimal> rhs = (NumericNode<decimal>)otherNode;
|
||||
return new NumericNode<decimal>(Value - rhs.Value);
|
||||
}
|
||||
throw new InvalidOperationException("Attempted Invalid operation");
|
||||
}
|
||||
|
||||
protected override BaseNode Multiply(BaseNode otherNode)
|
||||
{
|
||||
if (otherNode is NumericNode<T>)
|
||||
if (otherNode is NumericNode<decimal>)
|
||||
{
|
||||
NumericNode<T> rhs = (NumericNode<T>)otherNode;
|
||||
return new NumericNode<T>(Value * rhs.Value);
|
||||
NumericNode<decimal> rhs = (NumericNode<decimal>)otherNode;
|
||||
return new NumericNode<decimal>(Value * rhs.Value);
|
||||
}
|
||||
throw new InvalidOperationException("Attempted Invalid operation");
|
||||
}
|
||||
|
||||
protected override BaseNode Divide(BaseNode otherNode)
|
||||
{
|
||||
if (otherNode is NumericNode<T>)
|
||||
if (otherNode is NumericNode<decimal>)
|
||||
{
|
||||
NumericNode<T> rhs = (NumericNode<T>)otherNode;
|
||||
return new NumericNode<T>(Value / rhs.Value);
|
||||
NumericNode<decimal> rhs = (NumericNode<decimal>)otherNode;
|
||||
return new NumericNode<decimal>(Value / rhs.Value);
|
||||
}
|
||||
throw new InvalidOperationException("Attempted Invalid operation");
|
||||
}
|
||||
|
||||
protected override BaseNode Exponentiate(BaseNode otherNode)
|
||||
{
|
||||
if (otherNode is NumericNode<decimal>)
|
||||
{
|
||||
NumericNode<decimal> rhs = (NumericNode<decimal>)otherNode;
|
||||
return new NumericNode<decimal>((decimal)(Math.Pow((double)Value, (double)(rhs.Value))));
|
||||
}
|
||||
throw new InvalidOperationException("Attempted Invalid operation");
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@ namespace MathEngine.Parser.Parser
|
||||
case Token.Type.Subtraction:
|
||||
case Token.Type.Multiplication:
|
||||
case Token.Type.Division:
|
||||
case Token.Type.Exponentiation:
|
||||
while ((OperatorStack.Count != 0 && ((((OperatorStack.Peek().Token_Type == Token.Type.Function) | (OperatorPrecedence(OperatorStack.Peek()) > OperatorPrecedence(CurrentToken)) | ((OperatorPrecedence(OperatorStack.Peek()) == OperatorPrecedence(CurrentToken)) & (IsLeftAssociatve(CurrentToken)))) && !(OperatorStack.Peek().Token_Type == Token.Type.LeftParenthesis)))))
|
||||
{
|
||||
OutputStack.Push(OperatorStack.Pop());
|
||||
|
||||
@@ -25,6 +25,11 @@
|
||||
/// </summary>
|
||||
public static readonly Token Divide = new("/", Type.Division, NumericType.NaN, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Represents the token for ^
|
||||
/// </summary>
|
||||
public static readonly Token Exponentiation = new("^", Type.Exponentiation, NumericType.NaN, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Enum representing the token type
|
||||
/// </summary>
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
'-' => Token.Minus,
|
||||
'*' => Token.Multiply,
|
||||
'/' => Token.Divide,
|
||||
'^' => Token.Exponentiation,
|
||||
_ => throw new Exception(String.Format("Character {0} is not a defined operator", curChar)),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user