mirror of
https://github.com/0xJ1M/MathsEngine.git
synced 2026-06-05 02:10:08 +00:00
WIP: Implemented a rough system for function evaluation
This commit is contained in:
@@ -4,6 +4,7 @@ using MathEngine.AST.Nodes;
|
|||||||
using MathEngine.Tokenizer;
|
using MathEngine.Tokenizer;
|
||||||
|
|
||||||
using static MathEngine.Tokenizer.Token;
|
using static MathEngine.Tokenizer.Token;
|
||||||
|
using MathEngine.Types;
|
||||||
|
|
||||||
namespace EngineTests.Parser_Tests.Nodes
|
namespace EngineTests.Parser_Tests.Nodes
|
||||||
{
|
{
|
||||||
@@ -18,8 +19,8 @@ namespace EngineTests.Parser_Tests.Nodes
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void TestNodeFactoryBinaryNodesOnDefinedOperations()
|
public void TestNodeFactoryBinaryNodesOnDefinedOperations()
|
||||||
{
|
{
|
||||||
NumericNode<decimal> node1 = new(200);
|
NumericNode node1 = new(new DecimalValue(200));
|
||||||
NumericNode<decimal> node2 = new(100);
|
NumericNode node2 = new(new DecimalValue(100));
|
||||||
|
|
||||||
Token plus = Token.Plus;
|
Token plus = Token.Plus;
|
||||||
Token minus = Token.Minus;
|
Token minus = Token.Minus;
|
||||||
|
|||||||
@@ -1,11 +1,4 @@
|
|||||||
using System;
|
namespace MathEngine.AST.Nodes
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Numerics;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MathEngine.AST.Nodes
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abstract class representing a Node in a Tree structure
|
/// Abstract class representing a Node in a Tree structure
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
using System;
|
using MathEngine.Types.Interfaces;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using static MathEngine.Functions.BuiltIns.BuiltIns;
|
||||||
|
|
||||||
namespace MathEngine.AST.Nodes
|
namespace MathEngine.AST.Nodes
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a Tree node that stores a function
|
/// Represents a Tree node that stores a function
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class FunctionNode<T> : BaseNode where T : INumber<T>
|
internal class FunctionNode : BaseNode
|
||||||
{
|
{
|
||||||
Action func;
|
private FunctionWrapper func;
|
||||||
List<NumericNode<T>> args;
|
private INumericNode[] args;
|
||||||
|
|
||||||
public FunctionNode(Action Function, List<NumericNode<T>> arguments)
|
public FunctionNode(FunctionWrapper Function, INumericNode[] arguments)
|
||||||
{
|
{
|
||||||
func = Function;
|
func = Function;
|
||||||
args = arguments;
|
args = arguments;
|
||||||
@@ -23,7 +25,7 @@ namespace MathEngine.AST.Nodes
|
|||||||
|
|
||||||
public override BaseNode Evaluate()
|
public override BaseNode Evaluate()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return func(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
using MathEngine.Tokenizer;
|
using MathEngine.Functions.BuiltIns;
|
||||||
|
using MathEngine.Tokenizer;
|
||||||
|
using MathEngine.Types;
|
||||||
|
using MathEngine.Types.Interfaces;
|
||||||
|
using System.Runtime.Intrinsics.X86;
|
||||||
|
using Xunit.Sdk;
|
||||||
using static MathEngine.Tokenizer.Token;
|
using static MathEngine.Tokenizer.Token;
|
||||||
|
|
||||||
namespace MathEngine.AST.Nodes
|
namespace MathEngine.AST.Nodes
|
||||||
@@ -32,7 +36,7 @@ namespace MathEngine.AST.Nodes
|
|||||||
return new BinaryNode(LeftBranch, RightBranch, (a, b) => a / b);
|
return new BinaryNode(LeftBranch, RightBranch, (a, b) => a / b);
|
||||||
case TokenType.Exponentiation:
|
case TokenType.Exponentiation:
|
||||||
throw new NotImplementedException("Exponentiation is not supported at this time!");
|
throw new NotImplementedException("Exponentiation is not supported at this time!");
|
||||||
return new BinaryNode(LeftBranch, RightBranch, (a, b) => a ^ b);
|
// return new BinaryNode(LeftBranch, RightBranch, (a, b) => a ^ b);
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException("Attempted to create a BinaryNode with an invalid operation!");
|
throw new NotImplementedException("Attempted to create a BinaryNode with an invalid operation!");
|
||||||
}
|
}
|
||||||
@@ -46,23 +50,25 @@ namespace MathEngine.AST.Nodes
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static BaseNode CreateFunctionNode(Token FunctionToken, Stack<BaseNode> ArgumentStack)
|
public static BaseNode CreateFunctionNode(Token FunctionToken, Stack<BaseNode> ArgumentStack)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException("Not implemented at this time");
|
int argc = (int)FunctionToken.Arity;
|
||||||
/* Check that the function exists, if it does we then check that the number of arguments
|
|
||||||
* for the function is are avaliable on the ArgumentStack. If so we can construct the Node.
|
|
||||||
* Otherwise, either the function does not exist or there is an argument mismatch */
|
|
||||||
/*try
|
|
||||||
{
|
|
||||||
functionAction = GetFunction(FunctionToken, out int functionArity);
|
|
||||||
if (functionArity >= ArgumentStack.Count)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Number of required arguments is greater than avaliable arugments");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
|
|
||||||
throw;
|
INumericNode[] argsv = new INumericNode[argc];
|
||||||
}*/
|
|
||||||
|
for (int i = argc; i > 0; i--)
|
||||||
|
{
|
||||||
|
// TODO: Update so either INumeric or function nodes are allowed
|
||||||
|
// this will enable nested functions
|
||||||
|
if (ArgumentStack.Peek() is INumericNode numericNode)
|
||||||
|
{
|
||||||
|
argsv[i - 1] = numericNode;
|
||||||
|
ArgumentStack.Pop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Function arguments implement INumericNode.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new FunctionNode(BuiltIns.GetFunction(FunctionToken.Value), argsv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -81,7 +87,7 @@ namespace MathEngine.AST.Nodes
|
|||||||
{
|
{
|
||||||
throw new ArgumentException("Failure to parse number");
|
throw new ArgumentException("Failure to parse number");
|
||||||
}
|
}
|
||||||
return new NumericNode<decimal>(res);
|
return new NumericallyOrderableNode<DecimalValue>(new DecimalValue(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,87 +1,115 @@
|
|||||||
using System.Numerics;
|
using MathEngine.Types.Interfaces;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace MathEngine.AST.Nodes
|
namespace MathEngine.AST.Nodes
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a Tree node that can store a numeric value
|
/// Represents a Tree node that can store a numeric value
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class NumericNode<T> : BaseNode where T : INumber<T>
|
internal class NumericNode<T>: BaseNode, INumericNode, ITrigonometricNode where T : struct, INumeric<T>
|
||||||
{
|
{
|
||||||
private readonly decimal Value;
|
protected readonly T _value;
|
||||||
|
|
||||||
|
Type INumericNode.NumericType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return typeof(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialises a new instance of a NumericNode with a given Token
|
/// Initialises a new instance of a NumericNode with a given Token
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The token for the nodes value</param>
|
/// <param name="value">The token for the nodes value</param>
|
||||||
public NumericNode(decimal value)
|
public NumericNode(T value)
|
||||||
{
|
{
|
||||||
Children = null;
|
Children = null;
|
||||||
Value = value;
|
_value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override BaseNode Add(BaseNode otherNode)
|
protected override BaseNode Add(BaseNode otherNode)
|
||||||
{
|
{
|
||||||
if (otherNode is NumericNode<decimal>)
|
if (otherNode is NumericNode<T> rhs)
|
||||||
{
|
{
|
||||||
NumericNode<decimal> rhs = (NumericNode<decimal>)otherNode;
|
return new NumericNode<T>(_value.Add(rhs._value));
|
||||||
return new NumericNode<decimal>(Value + rhs.Value);
|
|
||||||
}
|
}
|
||||||
throw new InvalidOperationException("Attempted Invalid operation");
|
throw new InvalidOperationException("Attempted Invalid operation");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override BaseNode Subtract(BaseNode otherNode)
|
protected override BaseNode Subtract(BaseNode otherNode)
|
||||||
{
|
{
|
||||||
if (otherNode is NumericNode<decimal>)
|
if (otherNode is NumericNode<T>)
|
||||||
{
|
{
|
||||||
NumericNode<decimal> rhs = (NumericNode<decimal>)otherNode;
|
NumericNode<T> rhs = (NumericNode<T>)otherNode;
|
||||||
return new NumericNode<decimal>(Value - rhs.Value);
|
return new NumericNode<T>(_value.Subtract(rhs._value));
|
||||||
}
|
}
|
||||||
throw new InvalidOperationException("Attempted Invalid operation");
|
throw new InvalidOperationException("Attempted Invalid operation");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override BaseNode Multiply(BaseNode otherNode)
|
protected override BaseNode Multiply(BaseNode otherNode)
|
||||||
{
|
{
|
||||||
if (otherNode is NumericNode<decimal>)
|
if (otherNode is NumericNode<T>)
|
||||||
{
|
{
|
||||||
NumericNode<decimal> rhs = (NumericNode<decimal>)otherNode;
|
NumericNode<T> rhs = (NumericNode<T>)otherNode;
|
||||||
return new NumericNode<decimal>(Value * rhs.Value);
|
return new NumericNode<T>(_value.Multiply(rhs._value));
|
||||||
}
|
}
|
||||||
throw new InvalidOperationException("Attempted Invalid operation");
|
throw new InvalidOperationException("Attempted Invalid operation");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override BaseNode Divide(BaseNode otherNode)
|
protected override BaseNode Divide(BaseNode otherNode)
|
||||||
{
|
{
|
||||||
if (otherNode is NumericNode<decimal>)
|
if (otherNode is NumericNode<T>)
|
||||||
{
|
{
|
||||||
NumericNode<decimal> rhs = (NumericNode<decimal>)otherNode;
|
NumericNode<T> rhs = (NumericNode<T>)otherNode;
|
||||||
return new NumericNode<decimal>(Value / rhs.Value);
|
return new NumericNode<T>(_value.Divide(rhs._value));
|
||||||
}
|
}
|
||||||
throw new InvalidOperationException("Attempted Invalid operation");
|
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Evaluates the Numeric Node by simply returning the current instance
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override BaseNode Evaluate()
|
public override BaseNode Evaluate()
|
||||||
{
|
{
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
internal T GetValue()
|
||||||
{
|
{
|
||||||
return Value.ToString();
|
return _value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void INumericNode.CopyTo<TDest>(ref TDest destination)
|
||||||
|
{
|
||||||
|
if (typeof(TDest) == typeof(T))
|
||||||
|
{
|
||||||
|
destination = Unsafe.As<T, TDest>(ref Unsafe.AsRef(in _value));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Cannot copy {typeof(T)} to {typeof(TDest)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public INumericNode Sin()
|
||||||
|
{
|
||||||
|
if (_value is ITrigonometric<T> trig)
|
||||||
|
return new NumericNode<T>(trig.Sin());
|
||||||
|
throw new NotImplementedException();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public INumericNode Cos()
|
||||||
|
{
|
||||||
|
if (_value is ITrigonometric<T> trig)
|
||||||
|
return new NumericNode<T>(trig.Cos());
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public INumericNode Tan()
|
||||||
|
{
|
||||||
|
if (_value is ITrigonometric<T> trig)
|
||||||
|
return new NumericNode<T>(trig.Tan());
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
55
MathEngine/MathEngine/AST/Nodes/NumericallyOrderableNode.cs
Normal file
55
MathEngine/MathEngine/AST/Nodes/NumericallyOrderableNode.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
using MathEngine.Types.Interfaces;
|
||||||
|
|
||||||
|
namespace MathEngine.AST.Nodes
|
||||||
|
{
|
||||||
|
internal class NumericallyOrderableNode<T> : NumericNode<T>, INumericallyOrderable where T : struct, INumericallyOrderable<T>
|
||||||
|
{
|
||||||
|
public NumericallyOrderableNode(T value) : base(value)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int INumericallyOrderable.CompareTo(INumericNode other)
|
||||||
|
{
|
||||||
|
if (other is NumericallyOrderableNode<T> rhs)
|
||||||
|
{
|
||||||
|
return this._value.CompareTo(rhs._value);
|
||||||
|
}
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool INumericallyOrderable.GreaterThan(INumericNode other)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool INumericallyOrderable.GreaterThanOrEqual(INumericNode other)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool INumericallyOrderable.LessThan(INumericNode other)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool INumericallyOrderable.LessThanOrEqual(INumericNode other)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
INumericallyOrderable INumericallyOrderable.Max(INumericNode other)
|
||||||
|
{
|
||||||
|
if (other is NumericallyOrderableNode<T> rhs)
|
||||||
|
return _value.GreaterThanOrEqual(rhs._value) ? this : rhs;
|
||||||
|
|
||||||
|
throw new InvalidOperationException("Cannot compare incompatible numeric node types");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
INumericallyOrderable INumericallyOrderable.Min(INumericNode other)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using MathEngine.AST;
|
using MathEngine.AST;
|
||||||
using MathEngine.AST.Nodes;
|
using MathEngine.AST.Nodes;
|
||||||
|
using MathEngine.Types;
|
||||||
|
|
||||||
namespace MathEngine.Expression
|
namespace MathEngine.Expression
|
||||||
{
|
{
|
||||||
|
|||||||
105
MathEngine/MathEngine/Functions/BuiltIns/BuiltIns.cs
Normal file
105
MathEngine/MathEngine/Functions/BuiltIns/BuiltIns.cs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
using MathEngine.AST.Nodes;
|
||||||
|
using MathEngine.Types;
|
||||||
|
using MathEngine.Types.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||||
|
|
||||||
|
namespace MathEngine.Functions.BuiltIns
|
||||||
|
{
|
||||||
|
internal class BuiltIns
|
||||||
|
{
|
||||||
|
// Uniform wrapper type: takes decimal[] and returns result via callback
|
||||||
|
public delegate BaseNode FunctionWrapper(INumericNode[] args);
|
||||||
|
|
||||||
|
// Dictionary storing the wrapped functions
|
||||||
|
private static readonly Dictionary<string, FunctionWrapper> _builtIns = new()
|
||||||
|
{
|
||||||
|
{ "sin", Wrap(SinImply)},
|
||||||
|
{ "cos", Wrap(CosImply)},
|
||||||
|
{ "tan", Wrap(TanImply)},
|
||||||
|
{ "max", Wrap(MaxImply)},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Wrap a Func<decimal[], decimal> into FunctionWrapper
|
||||||
|
private static FunctionWrapper Wrap(Func<INumericNode[], INumericNode> func)
|
||||||
|
{
|
||||||
|
return args => (BaseNode)func(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static bool IsFunction(string name)
|
||||||
|
{
|
||||||
|
return _builtIns.ContainsKey(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the wrapper for a function
|
||||||
|
public static FunctionWrapper GetFunction(string name)
|
||||||
|
{
|
||||||
|
if (!_builtIns.TryGetValue(name, out var func))
|
||||||
|
throw new Exception($"Unknown function: {name}");
|
||||||
|
return func;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static INumericNode SinImply(INumericNode[] span)
|
||||||
|
{
|
||||||
|
INumericNode arg = span[0];
|
||||||
|
if (arg is ITrigonometricNode trigNode)
|
||||||
|
{
|
||||||
|
return trigNode.Sin();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException("Argument does not support Sin()");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static INumericNode CosImply(INumericNode[] span)
|
||||||
|
{
|
||||||
|
INumericNode arg = span[0];
|
||||||
|
if (arg is ITrigonometricNode trigNode)
|
||||||
|
{
|
||||||
|
return trigNode.Cos();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException("Argument does not support Sin()");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static INumericNode TanImply(INumericNode[] span)
|
||||||
|
{
|
||||||
|
INumericNode arg = span[0];
|
||||||
|
if (arg is ITrigonometricNode trigNode)
|
||||||
|
{
|
||||||
|
return trigNode.Tan();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException("Argument does not support Sin()");
|
||||||
|
}
|
||||||
|
private static INumericNode MaxImply(INumericNode[] span)
|
||||||
|
{
|
||||||
|
var maxNode = span[0] as INumericallyOrderable
|
||||||
|
?? throw new InvalidOperationException("Argument not orderable");
|
||||||
|
|
||||||
|
foreach (var node in span.Skip(1))
|
||||||
|
{
|
||||||
|
if (node is INumericallyOrderable orderable)
|
||||||
|
{
|
||||||
|
maxNode = maxNode.Max(orderable);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("All arguments must be orderable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
////// Allow registering user-defined functions
|
||||||
|
////public static void RegisterFunction(string name, Func<ReadOnlySpan<INumericNode>, INumericNode> func)
|
||||||
|
////{
|
||||||
|
//// _builtIns[name] = Wrap(func);
|
||||||
|
////}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using MathEngine.Tokenizer;
|
using MathEngine.Functions.BuiltIns;
|
||||||
|
using MathEngine.Tokenizer;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
using static MathEngine.Tokenizer.Token;
|
using static MathEngine.Tokenizer.Token;
|
||||||
|
|
||||||
@@ -155,8 +156,10 @@ namespace MathEngine.Parser
|
|||||||
Stack<Token> OperatorStack = new(Expression.Count/2);
|
Stack<Token> OperatorStack = new(Expression.Count/2);
|
||||||
//The final stack to return
|
//The final stack to return
|
||||||
Queue<Token> rpnQueue = new(Expression.Count);
|
Queue<Token> rpnQueue = new(Expression.Count);
|
||||||
//Stack used to hold the number of input params to a function
|
|
||||||
//Stack<uint> ArityStack = new Stack<uint>();
|
// Stack that is used to handle nested function argument counts
|
||||||
|
Stack<UInt32> arityStack = new();
|
||||||
|
|
||||||
Token PreviousToken = Token.None;
|
Token PreviousToken = Token.None;
|
||||||
Token CurrentToken;
|
Token CurrentToken;
|
||||||
|
|
||||||
@@ -179,8 +182,33 @@ namespace MathEngine.Parser
|
|||||||
PopOperatorsToQueue(OperatorStack, rpnQueue, CurrentToken);
|
PopOperatorsToQueue(OperatorStack, rpnQueue, CurrentToken);
|
||||||
OperatorStack.Push(CurrentToken);
|
OperatorStack.Push(CurrentToken);
|
||||||
break;
|
break;
|
||||||
case TokenType.Function:
|
case TokenType.GenericIdentifier:
|
||||||
OperatorStack.Push(CurrentToken);
|
// few things to consider
|
||||||
|
// 1 Check built-ins
|
||||||
|
if (i + 1 < Expression.Count && Expression[i + 1].Type == TokenType.LeftParenthesis && BuiltIns.IsFunction(CurrentToken.Value))
|
||||||
|
{
|
||||||
|
OperatorStack.Push(CurrentToken with { Type = Token.TokenType.Function });
|
||||||
|
arityStack.Push(1); // at least one arg must be present
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 2 check user defined functions
|
||||||
|
// TODO: Implement User definable functions
|
||||||
|
|
||||||
|
// 3 check to see if it is a user defined variable
|
||||||
|
// TODO: Implement user definable variables
|
||||||
|
|
||||||
|
// 4 assume it is an implict multiplication
|
||||||
|
// TODO: Split identifier into letters and insert implicit multiplication
|
||||||
|
break;
|
||||||
|
case TokenType.FunctionArgumentSeparator:
|
||||||
|
if (arityStack.Count == 0)
|
||||||
|
throw new ParserException("Unexpected function arguement separator");
|
||||||
|
// Pop operators until the last LeftParenthesis
|
||||||
|
while (OperatorStack.Count > 0 && OperatorStack.Peek().Type != TokenType.LeftParenthesis)
|
||||||
|
rpnQueue.Enqueue(OperatorStack.Pop());
|
||||||
|
|
||||||
|
// increment the argument counter
|
||||||
|
arityStack.Push(arityStack.Pop() + 1);
|
||||||
break;
|
break;
|
||||||
case TokenType.LeftParenthesis:
|
case TokenType.LeftParenthesis:
|
||||||
OperatorStack.Push(CurrentToken);
|
OperatorStack.Push(CurrentToken);
|
||||||
@@ -198,7 +226,7 @@ namespace MathEngine.Parser
|
|||||||
|
|
||||||
if (OperatorStack.Count > 0 && (OperatorStack.Peek().Type == TokenType.Function))
|
if (OperatorStack.Count > 0 && (OperatorStack.Peek().Type == TokenType.Function))
|
||||||
{
|
{
|
||||||
rpnQueue.Enqueue(OperatorStack.Pop());
|
rpnQueue.Enqueue(OperatorStack.Pop() with { Arity = arityStack.Pop()});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace MathEngine.Tokenizer
|
|||||||
internal enum TokenType
|
internal enum TokenType
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
|
GenericIdentifier,
|
||||||
|
|
||||||
Numeric,
|
Numeric,
|
||||||
DecimalPoint,
|
DecimalPoint,
|
||||||
@@ -50,6 +51,7 @@ namespace MathEngine.Tokenizer
|
|||||||
public static readonly Token Exponentiation = new("^", TokenType.Exponentiation);
|
public static readonly Token Exponentiation = new("^", TokenType.Exponentiation);
|
||||||
public static readonly Token LeftParenthesis = new("(", TokenType.LeftParenthesis);
|
public static readonly Token LeftParenthesis = new("(", TokenType.LeftParenthesis);
|
||||||
public static readonly Token RightParenthesis = new(")", TokenType.RightParenthesis);
|
public static readonly Token RightParenthesis = new(")", TokenType.RightParenthesis);
|
||||||
|
public static readonly Token FunctionArgumentSeparator = new(",", TokenType.FunctionArgumentSeparator);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns true if the token represents any arithmetic operator.
|
/// Returns true if the token represents any arithmetic operator.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
using MathEngine.Tokenizer;
|
using MathEngine.Tokenizer;
|
||||||
|
using System.ComponentModel.Design;
|
||||||
using static MathEngine.Tokenizer.Token;
|
using static MathEngine.Tokenizer.Token;
|
||||||
|
|
||||||
namespace MathEngine.Tokenizer
|
namespace MathEngine.Tokenizer
|
||||||
@@ -24,6 +25,18 @@ namespace MathEngine.Tokenizer
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a character represents an ASCII letter
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="c">The character to check</param>
|
||||||
|
/// <returns>True if <paramref name="c"/> represents an ASCII letter, false otherwise</returns>
|
||||||
|
|
||||||
|
private static bool IsAsciiLetter(char c)
|
||||||
|
{
|
||||||
|
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if a character represents an ASCII whitespace character
|
/// Checks if a character represents an ASCII whitespace character
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -45,12 +58,22 @@ namespace MathEngine.Tokenizer
|
|||||||
return c == '.';
|
return c == '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a character represents the FunctionArgumentSeparator
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="c">The character to check</param>
|
||||||
|
/// <returns>True if <paramref name="c"/> represents the FunctionArgumentSeparator, false otherwise</returns>
|
||||||
|
private static bool IsFunctionArgumentSeparator(char c)
|
||||||
|
{
|
||||||
|
return c == ',' ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses the <paramref name="expression"/> to read a numeric <typeparamref name="Token"/>
|
/// Parses the <paramref name="expression"/> to read a numeric <typeparamref name="Token"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="expression">The expression being parsed</param>
|
/// <param name="expression">The expression being parsed</param>
|
||||||
/// <param name="at_decimal_point">Indicates if the character read before calling this method was a decimal point or not</param>
|
/// <param name="at_decimal_point">Indicates if the character read before calling this method was a decimal point or not</param>
|
||||||
/// <param name="current_index">The current index the parser is at</param>
|
/// <param name="currentIndex">The current index the parser is at</param>
|
||||||
/// <returns>A <typeparamref name="Token"/> representing the numeric value read</returns>
|
/// <returns>A <typeparamref name="Token"/> representing the numeric value read</returns>
|
||||||
private static Token ReadNumericToken(ReadOnlySpan<char> expression, bool at_decimal_point, ref Int32 currentIndex)
|
private static Token ReadNumericToken(ReadOnlySpan<char> expression, bool at_decimal_point, ref Int32 currentIndex)
|
||||||
{
|
{
|
||||||
@@ -75,6 +98,10 @@ namespace MathEngine.Tokenizer
|
|||||||
ReadOnlySpan<char> errSpan = expression.Slice(currentIndex, errIndex - currentIndex);
|
ReadOnlySpan<char> errSpan = expression.Slice(currentIndex, errIndex - currentIndex);
|
||||||
throw new TokenizerException($"Syntax error: The number {errSpan.ToString()} has multiple decimal point when at most one is allowed.");
|
throw new TokenizerException($"Syntax error: The number {errSpan.ToString()} has multiple decimal point when at most one is allowed.");
|
||||||
}
|
}
|
||||||
|
else if (IsFunctionArgumentSeparator(tempChar))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
else if (!IsAsciiDigit(tempChar) && tempChar != '.')
|
else if (!IsAsciiDigit(tempChar) && tempChar != '.')
|
||||||
{
|
{
|
||||||
break; // end of numeric token
|
break; // end of numeric token
|
||||||
@@ -88,32 +115,70 @@ namespace MathEngine.Tokenizer
|
|||||||
return new Token(numberSpan.ToString(), TokenType.Numeric);
|
return new Token(numberSpan.ToString(), TokenType.Numeric);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
static private Token GetOperatorToken(char curChar)
|
/// Parses the expression to read a GenericIdentifier Token
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="expression">The expression being parsed</param>
|
||||||
|
/// <param name="currentIndex">The current index the parser is at</param>
|
||||||
|
/// <returns>A <typeparamref name="Token"/> representing a GenericIdentifier for further processing</returns>
|
||||||
|
private static Token ReadIdentifierToken(ReadOnlySpan<char> expression, ref Int32 currentIndex)
|
||||||
{
|
{
|
||||||
return curChar switch
|
int start = currentIndex;
|
||||||
|
while (currentIndex + 1 < expression.Length && IsAsciiLetter(expression[currentIndex + 1]))
|
||||||
|
{
|
||||||
|
currentIndex++;
|
||||||
|
}
|
||||||
|
ReadOnlySpan<char> identifier = expression.Slice(start, currentIndex - start + 1);
|
||||||
|
return new Token(identifier.ToString(), TokenType.GenericIdentifier, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the correct Operator Token given a ASCII Character
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="c">The character to get the correct Operator Token for</param>
|
||||||
|
/// <returns>A <typeparamref name="Token"/> which is represented by <paramref name="c"/> </returns>
|
||||||
|
/// <exception cref="TokenizerException">Thrown when <paramref name="c"/> is not a recognized character for an Operator Token</exception>
|
||||||
|
static private Token GetOperatorToken(char c)
|
||||||
|
{
|
||||||
|
return c switch
|
||||||
{
|
{
|
||||||
'+' => Token.Plus,
|
'+' => Token.Plus,
|
||||||
'-' => Token.Minus,
|
'-' => Token.Minus,
|
||||||
'*' => Token.Multiply,
|
'*' => Token.Multiply,
|
||||||
'/' => Token.Divide,
|
'/' => Token.Divide,
|
||||||
'^' => Token.Exponentiation,
|
'^' => Token.Exponentiation,
|
||||||
_ => throw new TokenizerException($"Recieved unknown character '{curChar}' when attempting to parse an operator.")
|
_ => throw new TokenizerException($"Recieved unknown character '{c}' when attempting to parse an operator.")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static private Token GetParenthesisToken(char curChar)
|
/// <summary>
|
||||||
|
/// Returns the correct Parenthesis Token given a ASCII Character
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="c">The character to get the correct Parenthesis Token for</param>
|
||||||
|
/// <returns> The correct Parenthesis <typeparamref name="Token"/> which is represented by <paramref name="c"/></returns>
|
||||||
|
/// <exception cref="TokenizerException">Thrown when <paramref name="c"/> is not a recognized character for a Parenthesis</exception>
|
||||||
|
static private Token GetParenthesisToken(char c)
|
||||||
{
|
{
|
||||||
return curChar switch
|
return c switch
|
||||||
{
|
{
|
||||||
'(' => Token.LeftParenthesis,
|
'(' => Token.LeftParenthesis,
|
||||||
')' => Token.RightParenthesis,
|
')' => Token.RightParenthesis,
|
||||||
_ => throw new TokenizerException($"Recieved unknown character '{curChar}' when attempting to parse a parenthesis."),
|
_ => throw new TokenizerException($"Recieved unknown character '{c}' when attempting to parse a parenthesis."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the Function Argument Separator Token
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The Function Argument Separator <typeparamref name="Token"/></returns>
|
||||||
|
static private Token GetFunctionArgumentSeparatorToken()
|
||||||
|
{
|
||||||
|
return Token.FunctionArgumentSeparator;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tokenizes a given Mathematical expression given as a string to a list of tokens
|
/// Tokenizes a given Mathematical expression given as a string to a list of tokens
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -151,6 +216,12 @@ namespace MathEngine.Tokenizer
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsFunctionArgumentSeparator(curChar))
|
||||||
|
{
|
||||||
|
Tokenstack.Add(GetFunctionArgumentSeparatorToken());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
//Number, two cases two consider, case 1) number is something like 142.2; case 2 .5 which is clearly 0.5.
|
//Number, two cases two consider, case 1) number is something like 142.2; case 2 .5 which is clearly 0.5.
|
||||||
//Case 1
|
//Case 1
|
||||||
if (IsAsciiDigit(curChar))
|
if (IsAsciiDigit(curChar))
|
||||||
@@ -163,6 +234,15 @@ namespace MathEngine.Tokenizer
|
|||||||
Tokenstack.Add(ReadNumericToken(expression, true, ref i));
|
Tokenstack.Add(ReadNumericToken(expression, true, ref i));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// read any iddentifiers
|
||||||
|
// TODO: Consider how to handle imaginary unit (i). Seems like a parser issue, non-issue in symbolic
|
||||||
|
if (IsAsciiLetter(curChar))
|
||||||
|
{
|
||||||
|
Tokenstack.Add(ReadIdentifierToken(expression, ref i));
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//return the stack after triming
|
//return the stack after triming
|
||||||
Tokenstack.TrimExcess();
|
Tokenstack.TrimExcess();
|
||||||
|
|||||||
373
MathEngine/MathEngine/Types/DecimalValue.cs
Normal file
373
MathEngine/MathEngine/Types/DecimalValue.cs
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
using MathEngine.Types.Interfaces;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace MathEngine.Types
|
||||||
|
{
|
||||||
|
internal struct DecimalValue : INumericallyOrderable<DecimalValue>, ITrigonometric<DecimalValue>
|
||||||
|
{
|
||||||
|
|
||||||
|
private decimal _value;
|
||||||
|
|
||||||
|
private static readonly DecimalValue _zero = new(0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The mathematical constant Pi
|
||||||
|
/// </summary>
|
||||||
|
private static readonly decimal PI = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068m;
|
||||||
|
private static readonly decimal TWOPI = 6.283185307179586476925286766559005768394338798750211641949889184615632812572417997256069650684234136m;
|
||||||
|
private static readonly decimal HALFPI = 1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534m;
|
||||||
|
|
||||||
|
// TODO: Find a set of coefficients where more values can fit into decimal while
|
||||||
|
// keeping the accuracy just as high
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pre-computed Chebyshev coefficients for a degree 30 Sine approximation
|
||||||
|
/// </summary>
|
||||||
|
private static readonly decimal[] _sin_cfs = {
|
||||||
|
1.107762718434877094787128e-31m,
|
||||||
|
-1.823732266493779103076113e-35m,
|
||||||
|
-9.181673072797976602053211e-29m,
|
||||||
|
3.225262111842922385008455e-34m,
|
||||||
|
6.446939827037235822437697e-26m,
|
||||||
|
-2.576736665059962220360842e-33m,
|
||||||
|
-3.868170134617741732466926e-23m,
|
||||||
|
1.228109964113387911565451e-32m,
|
||||||
|
1.957294106252405728115831e-20m,
|
||||||
|
-3.882226497276181192594589e-32m,
|
||||||
|
-8.220635246622832053855188e-18m,
|
||||||
|
8.555581455036025700953568e-32m,
|
||||||
|
2.811457254345518890772695e-15m,
|
||||||
|
-1.344198394902903252583665e-31m,
|
||||||
|
-7.647163731819816458999534e-13m,
|
||||||
|
1.512690085816523728430496e-31m,
|
||||||
|
1.605904383682161459928373e-10m,
|
||||||
|
-1.207137865111693794326432e-31m,
|
||||||
|
-2.505210838544171877505162e-8m,
|
||||||
|
6.658710916160807720823915e-32m,
|
||||||
|
0.000002755731922398589065255732m,
|
||||||
|
-2.425218754430548182421541e-32m,
|
||||||
|
-0.0001984126984126984126984127m,
|
||||||
|
5.399220187127378949775714e-33m,
|
||||||
|
0.008333333333333333333333333m,
|
||||||
|
-6.429050541691068943420765e-34m,
|
||||||
|
-0.1666666666666666666666667m,
|
||||||
|
3.144305445341164228755108e-35m,
|
||||||
|
1.0m,
|
||||||
|
-2.646821446601517372109605e-37m};
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pre-computed Chebyshev coefficients for a degree 30 Cosine approximation
|
||||||
|
/// </summary>
|
||||||
|
private static readonly decimal[] _cos_cfs = {
|
||||||
|
-1.819373578408273903259426e-35m,
|
||||||
|
3.210857395660629127502647e-30m,
|
||||||
|
3.558623874711111508186483e-34m,
|
||||||
|
-2.479023574256452751736573e-27m,
|
||||||
|
-3.120601939944795774454124e-33m,
|
||||||
|
1.611734742261012615961468e-24m,
|
||||||
|
1.61966781283449908063686e-32m,
|
||||||
|
-8.896791299969882965587422e-22m,
|
||||||
|
-5.531921460818070226357292e-32m,
|
||||||
|
4.11031762310156955385159e-19m,
|
||||||
|
1.307520378404943821183129e-31m,
|
||||||
|
-1.561920696858280193101514e-16m,
|
||||||
|
-2.189425802841482649852114e-31m,
|
||||||
|
4.779477332387381286306434e-14m,
|
||||||
|
2.61434386212678154378457e-31m,
|
||||||
|
-1.147074559772972468014089e-11m,
|
||||||
|
-2.210663449693968868683802e-31m,
|
||||||
|
2.087675698786809897901e-9m,
|
||||||
|
1.296861671422669049472492e-31m,
|
||||||
|
-0.0000002755731922398589065255651m,
|
||||||
|
-5.084534256113915594062863e-32m,
|
||||||
|
0.00002480158730158730158730159m,
|
||||||
|
1.251597093832519719838309e-32m,
|
||||||
|
-0.001388888888888888888888889m,
|
||||||
|
-1.738090061385202180342415e-33m,
|
||||||
|
0.04166666666666666666666667m,
|
||||||
|
1.113240260965897824377927e-34m,
|
||||||
|
-0.5m,
|
||||||
|
-2.097353881291299259797553e-36m,
|
||||||
|
1.0m
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public Type UnderlyingType => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public DecimalValue Value => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public DecimalValue(decimal value)
|
||||||
|
{
|
||||||
|
_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecimalValue(string value)
|
||||||
|
{
|
||||||
|
_value = decimal.Parse(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs radian angle range reduction into the range -Pi/2 <= x <= Pi/2
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The radian angle to reduce</param>
|
||||||
|
/// <returns>The radian angle <paramref name="x"/> within the range -Pi/2 <= x <= Pi/2</returns>
|
||||||
|
private static decimal RangeReduction(decimal x)
|
||||||
|
{
|
||||||
|
decimal r = x % TWOPI;
|
||||||
|
|
||||||
|
if (r > PI) r -= TWOPI;
|
||||||
|
else if (r < -PI) r += TWOPI;
|
||||||
|
|
||||||
|
if (r > HALFPI) r = PI - r;
|
||||||
|
else if (r < -HALFPI) r = -PI - r;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Evaluates a Polynommial with <typeparamref name="decimal"/> coefficients at a <typeparamref name="decimal"/> point using Horners method
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cfs">The coefficients of the polynomial with the leading coefficient first</param>
|
||||||
|
/// <param name="x">The point to evaluate the polynomial at</param>
|
||||||
|
/// <returns>The evaluation of the polynomial given by <paramref name="cfs"/> at the point <paramref name="x"/></returns>
|
||||||
|
private static decimal HornerPolyEval(ReadOnlySpan<decimal> cfs, decimal x)
|
||||||
|
{
|
||||||
|
decimal result = cfs[0]; // Start with the leading coefficient
|
||||||
|
for (int i = 1; i < cfs.Length; i++)
|
||||||
|
{
|
||||||
|
result = result * x + cfs[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds two <typeparamref name="DecimalValues"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first <typeparamref name="DecimalValue"/></param>
|
||||||
|
/// <param name="b">The second <typeparamref name="DecimalValue"/</param>
|
||||||
|
/// <returns>The sum of <paramref name="a"/> and <paramref name="b"/></returns>
|
||||||
|
public static DecimalValue operator +(DecimalValue a, DecimalValue b)
|
||||||
|
{
|
||||||
|
return new DecimalValue(a._value + b._value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subtracts two <typeparamref name="DecimalValues"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first <typeparamref name="DecimalValue"/></param>
|
||||||
|
/// <param name="b">The second <typeparamref name="DecimalValue"/</param>
|
||||||
|
/// <returns>The difference of <paramref name="a"/> and <paramref name="b"/></returns>
|
||||||
|
public static DecimalValue operator -(DecimalValue a, DecimalValue b)
|
||||||
|
{
|
||||||
|
return new DecimalValue(a._value - b._value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplies two <typeparamref name="DecimalValues"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first <typeparamref name="DecimalValue"/></param>
|
||||||
|
/// <param name="b">The second <typeparamref name="DecimalValue"/</param>
|
||||||
|
/// <returns>The product of <paramref name="a"/> and <paramref name="b"/></returns>
|
||||||
|
public static DecimalValue operator *(DecimalValue a, DecimalValue b)
|
||||||
|
{
|
||||||
|
return new DecimalValue(a._value * b._value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Divides two <typeparamref name="DecimalValues"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first <typeparamref name="DecimalValue"/></param>
|
||||||
|
/// <param name="b">The second <typeparamref name="DecimalValue"/</param>
|
||||||
|
/// <returns>The quotient of <paramref name="a"/> and <paramref name="b"/></returns>
|
||||||
|
/// <exception cref="DivideByZeroException">Thrown when <paramref name="b"/> is equal to zero</exception>
|
||||||
|
public static DecimalValue operator /(DecimalValue a, DecimalValue b)
|
||||||
|
{
|
||||||
|
if (b._value == 0)
|
||||||
|
{
|
||||||
|
throw new DivideByZeroException("DIVISION BY ZERO!");
|
||||||
|
}
|
||||||
|
return new DecimalValue(a._value / b._value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares two <typeparamref name="DecimalValues"/> for equality
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first <typeparamref name="DecimalValue"/></param>
|
||||||
|
/// <param name="b">The second <typeparamref name="DecimalValue"/</param>
|
||||||
|
/// <returns>True if <paramref name="a"/> and <paramref name="b"/> are equal, False otherwise</returns>
|
||||||
|
public static bool operator ==(DecimalValue a, DecimalValue b)
|
||||||
|
{
|
||||||
|
return a._value == b._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares two <typeparamref name="DecimalValue"/> for inequality
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first <typeparamref name="DecimalValue"/></param>
|
||||||
|
/// <param name="b">The second <typeparamref name="DecimalValue"/</param>
|
||||||
|
/// <returns>True if <paramref name="a"/> and <paramref name="b"/> are not equal, False otherwise</returns>
|
||||||
|
public static bool operator !=(DecimalValue a, DecimalValue b)
|
||||||
|
{
|
||||||
|
return a._value != b._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares the current <typeparamref name="DecimalValue"/> instance to another <typeparamref name="DecimalValue"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The <typeparamref name="DecimalValue"/> instance to compare to the current <typeparamref name="DecimalValue"/> instance</param>
|
||||||
|
/// <returns>A signed number indicating the relative values of this instance and value.
|
||||||
|
/// <list type="table">
|
||||||
|
/// <listheader>
|
||||||
|
/// <term>Return value</term>
|
||||||
|
/// <description>Meaning</description>
|
||||||
|
/// </listheader>
|
||||||
|
/// <item>
|
||||||
|
/// <term>Less than zero</term>
|
||||||
|
/// <description>This instance is less than <paramref name="other"/>.</description>
|
||||||
|
/// </item>
|
||||||
|
/// <item>
|
||||||
|
/// <term>Zero</term>
|
||||||
|
/// <description>This instance is equal to <paramref name="other"/>.</description>
|
||||||
|
/// </item>
|
||||||
|
/// <item>
|
||||||
|
/// <term>Greater than zero</term>
|
||||||
|
/// <description>This instance is greater than <paramref name="other"/>.</description>
|
||||||
|
/// </item>
|
||||||
|
/// </list>
|
||||||
|
/// </returns>
|
||||||
|
public int CompareTo(DecimalValue other)
|
||||||
|
{
|
||||||
|
return _value.CompareTo(other._value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares if the current <typeparamref name="DecimalValue"/> instance is less than another <typeparamref name="DecimalValues"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other"><typeparamref name="DecimalValue"/> instance to compare the current <typeparamref name="DecimalValue"/> instanct to.</param>
|
||||||
|
/// <returns>True if the current <typeparamref name="DecimalValue"/> instance is less thatn <paramref name="other"/>, False otherwise</returns>
|
||||||
|
public bool LessThan(DecimalValue other)
|
||||||
|
{
|
||||||
|
return _value < other._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares if the current <typeparamref name="DecimalValue"/> instance is less than or equal to another <typeparamref name="DecimalValues"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other"><typeparamref name="DecimalValue"/> instance to compare the current <typeparamref name="DecimalValue"/> instanct to.</param>
|
||||||
|
/// <returns>True if the current <typeparamref name="DecimalValue"/> instance is less thatn <paramref name="other"/>, False otherwise</returns>
|
||||||
|
public bool LessThanOrEqual(DecimalValue other)
|
||||||
|
{
|
||||||
|
return _value <= other._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares if the current <typeparamref name="DecimalValue"/> instance is greater than another <typeparamref name="DecimalValues"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other"><typeparamref name="DecimalValue"/> instance to compare the current <typeparamref name="DecimalValue"/> instanct to.</param>
|
||||||
|
/// <returns>True if the current <typeparamref name="DecimalValue"/> instance is greater thatn <paramref name="other"/>, False otherwise</returns>
|
||||||
|
public bool GreaterThan(DecimalValue other)
|
||||||
|
{
|
||||||
|
return _value > other._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares if the current <typeparamref name="DecimalValue"/> instance is greater than or equal to another <typeparamref name="DecimalValues"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other"><typeparamref name="DecimalValue"/> instance to compare the current <typeparamref name="DecimalValue"/> instanct to.</param>
|
||||||
|
/// <returns>True if the current <typeparamref name="DecimalValue"/> instance is greater thatn <paramref name="other"/>, False otherwise</returns>
|
||||||
|
public bool GreaterThanOrEqual(DecimalValue other)
|
||||||
|
{
|
||||||
|
return _value >= other._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the current <typeparamref name="DecimalValue"/> instance to
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public DecimalValue Add(DecimalValue other)
|
||||||
|
{
|
||||||
|
return this + other;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecimalValue Subtract(DecimalValue other)
|
||||||
|
{
|
||||||
|
return this - other;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecimalValue Multiply(DecimalValue other)
|
||||||
|
{
|
||||||
|
return this * other;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecimalValue Divide(DecimalValue other)
|
||||||
|
{
|
||||||
|
return this / other;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecimalValue Negate()
|
||||||
|
{
|
||||||
|
return new DecimalValue(decimal.Negate(_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equal(DecimalValue other)
|
||||||
|
{
|
||||||
|
return _value == other._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool NotEqual(DecimalValue other)
|
||||||
|
{
|
||||||
|
return !Equal(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return _value.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (!(obj is DecimalValue))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DecimalValue mys = (DecimalValue)obj;
|
||||||
|
return mys._value == _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "DecimalValue: " + _value.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecimalValue Sin()
|
||||||
|
{
|
||||||
|
decimal reduced_x = DecimalValue.RangeReduction(_value);
|
||||||
|
return new DecimalValue(HornerPolyEval(DecimalValue._sin_cfs, reduced_x));
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecimalValue Cos()
|
||||||
|
{
|
||||||
|
decimal reduced_x = DecimalValue.RangeReduction(_value);
|
||||||
|
return new DecimalValue(HornerPolyEval(DecimalValue._cos_cfs, reduced_x));
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecimalValue Tan()
|
||||||
|
{
|
||||||
|
DecimalValue reduced_x = new DecimalValue(DecimalValue.RangeReduction(_value));
|
||||||
|
return reduced_x.Sin() / reduced_x.Cos();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecimalValue Max(DecimalValue other)
|
||||||
|
{
|
||||||
|
return this.GreaterThanOrEqual(other) ? this : other;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecimalValue Min(DecimalValue other)
|
||||||
|
{
|
||||||
|
return this.LessThanOrEqual(other) ? this : other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
79
MathEngine/MathEngine/Types/Interfaces/INumeric.cs
Normal file
79
MathEngine/MathEngine/Types/Interfaces/INumeric.cs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace MathEngine.Types.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base Interface that defines numerical values
|
||||||
|
/// </summary>
|
||||||
|
internal interface INumeric<T> where T : struct, INumeric<T>
|
||||||
|
{
|
||||||
|
T Value { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds this numeric value to another
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The numeric value to add</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A new <see cref="INumeric"/> instance representing the sum of this and <paramref name="other"/>
|
||||||
|
/// </returns>
|
||||||
|
T Add(T other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subtracts another numeric value from this one
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The numeric value to subtract</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A new <see cref="INumeric"/> instance representing the result of the subtraction
|
||||||
|
/// </returns>
|
||||||
|
T Subtract(T other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplies this numeric value by another
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The numeric value to multiply by</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A new <see cref="INumeric"/> instance representing the product of this and <paramref name="other"/>
|
||||||
|
/// </returns>
|
||||||
|
T Multiply(T other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Divides this numeric value by another
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The numeric value to divide by</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A new <see cref="INumeric"/> instance representing the quotient of this and <paramref name="other"/>
|
||||||
|
/// </returns>
|
||||||
|
T Divide(T other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the negation of this numeric value
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A new <see cref="INumeric"/> instance representing the negated value
|
||||||
|
/// </returns>
|
||||||
|
T Negate();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this numeric value is equal to the specified other value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric value to compare.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this value is equal to <paramref name="other"/>; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
bool Equal(T other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this numeric value is not equal to the specified other value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric value to compare.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this value is not equal to <paramref name="other"/>; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
bool NotEqual(T other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the <see cref="Type"/> of the <see cref="INumeric"/> instance
|
||||||
|
/// </summary>
|
||||||
|
Type UnderlyingType { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
9
MathEngine/MathEngine/Types/Interfaces/INumericNode.cs
Normal file
9
MathEngine/MathEngine/Types/Interfaces/INumericNode.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace MathEngine.Types.Interfaces
|
||||||
|
{
|
||||||
|
internal interface INumericNode
|
||||||
|
{
|
||||||
|
Type NumericType { get; }
|
||||||
|
|
||||||
|
void CopyTo<T>(ref T destination) where T : struct;
|
||||||
|
}
|
||||||
|
}
|
||||||
125
MathEngine/MathEngine/Types/Interfaces/INumericallyOrderable.cs
Normal file
125
MathEngine/MathEngine/Types/Interfaces/INumericallyOrderable.cs
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MathEngine.Types.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension interface that represents a numeric value that supports ordering operations.
|
||||||
|
/// </summary>
|
||||||
|
internal interface INumericallyOrderable<T> : INumeric<T> where T : struct, INumericallyOrderable<T>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares this numeric value with another.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other comparable numeric value.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// Less than zero if this < other, 0 if equal, greater than zero if this > other.
|
||||||
|
/// </returns>
|
||||||
|
int CompareTo(T other);
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if this numeric value is less than the specified other value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric value to compare.</param>
|
||||||
|
/// <returns>True if this < other, False otherwise</returns>
|
||||||
|
bool LessThan(T other);
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this value is less than or equal to the specified other value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric value to compare.</param>
|
||||||
|
/// <returns>True if this <= other, False otherwise</returns>
|
||||||
|
bool LessThanOrEqual(T other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this value is greater than the specified other value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric value to compare.</param>
|
||||||
|
/// <returns>True if this > other, False otherwise</returns>
|
||||||
|
bool GreaterThan(T other);
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this value is less than or equal to the specified other value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric value to compare.</param>
|
||||||
|
/// <returns>True if this >= other, False otherwise</returns>
|
||||||
|
bool GreaterThanOrEqual(T other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the maximum of this node and another node.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric node.</param>
|
||||||
|
/// <returns>A new node representing the maximum value.</returns>
|
||||||
|
T Max(T other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the minimum of this node and another node.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric node.</param>
|
||||||
|
/// <returns>A new node representing the minimum value.</returns>
|
||||||
|
T Min(T other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// AST-level interface representing a numeric node that supports ordering operations.
|
||||||
|
/// </summary>
|
||||||
|
internal interface INumericallyOrderable : INumericNode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Compares this node's value with another node.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric node to compare.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// Less than zero if this < other, 0 if equal, greater than zero if this > other.
|
||||||
|
/// </returns>
|
||||||
|
int CompareTo(INumericNode other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if this node's value is less than the other node's value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric node to compare.</param>
|
||||||
|
/// <returns>True if this < other, False otherwise</returns>
|
||||||
|
bool LessThan(INumericNode other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if this node's value is less than or equal to the other node's value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric node to compare.</param>
|
||||||
|
/// <returns>True if this <= other, False otherwise</returns>
|
||||||
|
bool LessThanOrEqual(INumericNode other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if this node's value is greater than the other node's value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric node to compare.</param>
|
||||||
|
/// <returns>True if this > other, False otherwise</returns>
|
||||||
|
bool GreaterThan(INumericNode other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if this node's value is greater than or equal to the other node's value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric node to compare.</param>
|
||||||
|
/// <returns>True if this >= other, False otherwise</returns>
|
||||||
|
bool GreaterThanOrEqual(INumericNode other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the maximum of this node and another node.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric node.</param>
|
||||||
|
/// <returns>A new node representing the maximum value.</returns>
|
||||||
|
INumericallyOrderable Max(INumericNode other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the minimum of this node and another node.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The other numeric node.</param>
|
||||||
|
/// <returns>A new node representing the minimum value.</returns>
|
||||||
|
INumericallyOrderable Min(INumericNode other);
|
||||||
|
}
|
||||||
|
}
|
||||||
49
MathEngine/MathEngine/Types/Interfaces/ITrigonometric.cs
Normal file
49
MathEngine/MathEngine/Types/Interfaces/ITrigonometric.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MathEngine.Types.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Generic Interface that defines support for Trigonometric evaluation
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
internal interface ITrigonometric<T> where T : struct, INumeric<T>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the sine of this value
|
||||||
|
/// </summary>
|
||||||
|
T Sin();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cosine of this value
|
||||||
|
/// </summary>
|
||||||
|
T Cos();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the tangent of this value
|
||||||
|
/// </summary>
|
||||||
|
T Tan();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal interface ITrigonometricNode: INumericNode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the sine of this value
|
||||||
|
/// </summary>
|
||||||
|
INumericNode Sin();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cosine of this value
|
||||||
|
/// </summary>
|
||||||
|
INumericNode Cos();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the tangent of this value
|
||||||
|
/// </summary>
|
||||||
|
INumericNode Tan();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,11 +4,136 @@ namespace MathRunner
|
|||||||
{
|
{
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
|
|
||||||
|
static readonly decimal[] SIN_COEFF = {-2.495353579956845068391614e-22m,
|
||||||
|
5.577877028144835944149859e-21m,
|
||||||
|
-5.907037282921367151874229e-20m,
|
||||||
|
3.942306394997070814280735e-19m,
|
||||||
|
-1.860603293633641604845514e-18m,
|
||||||
|
6.605428876334905572700573e-18m,
|
||||||
|
-1.83190469182408107133773e-17m,
|
||||||
|
4.06860589192645688022598e-17m,
|
||||||
|
-7.358359464590914836426366e-17m,
|
||||||
|
1.097329189752797643166105e-16m,
|
||||||
|
-1.441182766313743229879074e-16m,
|
||||||
|
1.40511452613827650863302e-16m,
|
||||||
|
2.689837823485177032543228e-15m,
|
||||||
|
8.817888613969593259744191e-17m,
|
||||||
|
-7.647698614509161378062996e-13m,
|
||||||
|
2.706140963906206196147425e-17m,
|
||||||
|
1.605904270053538957745356e-10m,
|
||||||
|
3.932205925254663059528159e-18m,
|
||||||
|
-2.505210838655286048763183e-8m,
|
||||||
|
2.533366734800068550746431e-19m,
|
||||||
|
0.000002755731922398543165479237m,
|
||||||
|
6.481293982930866844259318e-21m,
|
||||||
|
-0.0001984126984126984133938607m,
|
||||||
|
5.479548578024028585883317e-23m,
|
||||||
|
0.008333333333333333333330317m,
|
||||||
|
1.071395263377213212738481e-25m,
|
||||||
|
-0.1666666666666666666666667m,
|
||||||
|
1.61588801274554481697818e-29m,
|
||||||
|
1.0m,
|
||||||
|
-3.751019264464499084009736e-34m};
|
||||||
|
|
||||||
|
static readonly decimal[] s2 = {1.107762718434877094787128e-31m,
|
||||||
|
-1.823732266493779103076113e-35m,
|
||||||
|
-9.181673072797976602053211e-29m,
|
||||||
|
3.225262111842922385008455e-34m,
|
||||||
|
6.446939827037235822437697e-26m,
|
||||||
|
-2.576736665059962220360842e-33m,
|
||||||
|
-3.868170134617741732466926e-23m,
|
||||||
|
1.228109964113387911565451e-32m,
|
||||||
|
1.957294106252405728115831e-20m,
|
||||||
|
-3.882226497276181192594589e-32m,
|
||||||
|
-8.220635246622832053855188e-18m,
|
||||||
|
8.555581455036025700953568e-32m,
|
||||||
|
2.811457254345518890772695e-15m,
|
||||||
|
-1.344198394902903252583665e-31m,
|
||||||
|
-7.647163731819816458999534e-13m,
|
||||||
|
1.512690085816523728430496e-31m,
|
||||||
|
1.605904383682161459928373e-10m,
|
||||||
|
-1.207137865111693794326432e-31m,
|
||||||
|
-2.505210838544171877505162e-8m,
|
||||||
|
6.658710916160807720823915e-32m,
|
||||||
|
0.000002755731922398589065255732m,
|
||||||
|
-2.425218754430548182421541e-32m,
|
||||||
|
-0.0001984126984126984126984127m,
|
||||||
|
5.399220187127378949775714e-33m,
|
||||||
|
0.008333333333333333333333333m,
|
||||||
|
-6.429050541691068943420765e-34m,
|
||||||
|
-0.1666666666666666666666667m,
|
||||||
|
3.144305445341164228755108e-35m,
|
||||||
|
1.0m,
|
||||||
|
-2.646821446601517372109605e-37m};
|
||||||
|
|
||||||
|
|
||||||
|
static readonly decimal[] s3 = { 9.916326246264954201615594e-30m,
|
||||||
|
1.54319928865030320494218e-29m,
|
||||||
|
-2.674184926393101367468514e-28m,
|
||||||
|
-2.692817072692041357738017e-28m,
|
||||||
|
6.587612243251582675930865e-26m,
|
||||||
|
2.093202438542293840804485e-27m,
|
||||||
|
-3.868835054593715102015364e-23m,
|
||||||
|
-9.553041629841611461032692e-27m,
|
||||||
|
1.95729616572122280801307e-20m,
|
||||||
|
2.839955456858767175704141e-26m,
|
||||||
|
-8.220635290513026145246676e-18m,
|
||||||
|
-5.767530270581598294967383e-26m,
|
||||||
|
2.811457254411262970766708e-15m,
|
||||||
|
8.161593358681450120770325e-26m,
|
||||||
|
-7.647163731820510961992906e-13m,
|
||||||
|
-8.059975709448137639642111e-26m,
|
||||||
|
1.605904383682161971192382e-10m,
|
||||||
|
5.477723421466464288236971e-26m,
|
||||||
|
-2.50521083854417188005417e-8m,
|
||||||
|
-2.485058233812166433395256e-26m,
|
||||||
|
0.00000275573192239858906526391m,
|
||||||
|
7.148546378130704537447194e-27m,
|
||||||
|
-0.0001984126984126984126984142m,
|
||||||
|
-1.202593758014493393872389e-27m,
|
||||||
|
0.008333333333333333333333333m,
|
||||||
|
1.046429449740262240020432e-28m,
|
||||||
|
-0.1666666666666666666666667m,
|
||||||
|
-3.934554842474513984886404e-30m,
|
||||||
|
1.0m,
|
||||||
|
3.934032899734993769175678e-32m,};
|
||||||
|
public static decimal Sin(decimal x)
|
||||||
|
{
|
||||||
|
decimal result = SIN_COEFF[0]; // Start with the leading coefficient
|
||||||
|
for (int i = 1; i < SIN_COEFF.Length; i++)
|
||||||
|
{
|
||||||
|
result = result * x + SIN_COEFF[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static decimal Sin2(decimal x)
|
||||||
|
{
|
||||||
|
decimal result = s2[0]; // Start with the leading coefficient
|
||||||
|
for (int i = 1; i < s2.Length; i++)
|
||||||
|
{
|
||||||
|
result = result * x + s2[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static decimal Sin3(decimal x)
|
||||||
|
{
|
||||||
|
decimal result = s3[0]; // Start with the leading coefficient
|
||||||
|
for (int i = 1; i < s3.Length; i++)
|
||||||
|
{
|
||||||
|
result = result * x + s3[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Evaluting expression...");
|
Console.WriteLine("Evaluting expression...");
|
||||||
Expression exp = new("54+2+1");
|
// Expression exp = new("sin(3.14159265)+1+max(1,2,3,4,5,6)");
|
||||||
Console.WriteLine(exp.Evaluate());
|
Expression exp = new("sin(3.14159265)*sin(3.14159265)+cos(3.14159265)*cos(3.14159265) + tan(1.4)");
|
||||||
|
Console.WriteLine(exp.Evaluate().ToString());
|
||||||
Console.WriteLine("Hello, World!");
|
Console.WriteLine("Hello, World!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user