Giter VIP home page Giter VIP logo

jace's People

Contributors

erobishaw avatar mibe avatar mrxrsd avatar npehrsson avatar pierrelemmel avatar pieterderycke avatar rawrspace avatar rmaclean avatar semihokur avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jace's Issues

Symbol names with underscores could be handled

For the project I'm working on, a client needs to be able to enter variable names with underscores in them, like "var_1" instead of "var1". They could come at any part of the name.

I made a stab at adjusting TokenReader.cs to allow this. On line 161, I added || character == '_' to the or-chain. It seems to work well, but I'm not yet familiar with the entirety of the tokenization mechanism to be absolutely certain there aren't other things that would need changing.

Can we make Random overrideable?

We built against 0.9.3 and added our own implementation of "random" that is different. We'd like to keep it. If it were overridable that would be ideal.

Current culture question

Dear Pieter,

Thanks for sharing this great library!

I hope you can help me with a small issue I'm facing: I've noticed that the math formula is sensitive to the UI culture, i.e. in my culture (Dutch) I would like to parse 0.5, but this generates a parse error, so instead I have to use 0,5.

How should I proceed when I would always like to use the former version? For example, can I somewhere specify CurrentCulture.InvariantCulture when parsing formulas?

Thanks, Erik

Build Function with constants

Hi,

Is it possible to add constant vars when build a function? something like that:

engine.build("a+b+c").Parameter("a",1").Parameter("b",2").Build();

Or I need to replace constant variable by myself before create a function?
engine.build("1+2+c").Build();

tks

Usage of conditional clause IF

Hi,
I cannot understand ho to use the IF statement:
1 - like this: DT=if(Se==8,D/te,10000000)

2 - or like this: if(Se==8,DT=D/te,DT=10000000)

both of them do not work. Is it a bug or I did something wrong?

Under Mono 3.2.8, Jace.Benchmark crashes with failed system assertion

With a freshly downloaded and cleanly built Jace.NET solution (2c0033a) and using Mono 3.2.8 on Lubuntu 14.04, running the Jace.Benchmark project causes a crash of some sort during the last "Compiled Mode" section just after the threads are started. Reliably reproducible for me.

Here is a transcript of the application output, including assertion failure message and stacktrace:

Loaded assembly: /home/bb/Jace-master/Jace.Benchmark/bin/Debug/Jace.Benchmark.exe
Loaded assembly: /home/bb/Jace-master/Jace.Benchmark/bin/Debug/Jace.dll
Jace.NET Benchmark Application

--------------------
Function: 2+3*7/23
Number Of Tests: 1,000,000

Interpreted Mode:
Loaded assembly: /usr/lib/mono/gac/System.Core/4.0.0.0__b77a5c561934e089/System.Core.dll [External]
Loaded assembly: /usr/lib/mono/gac/System/4.0.0.0__b77a5c561934e089/System.dll [External]
Total duration: 00:00:05.3861940
Compiled Mode:
Loaded assembly: Anonymously Hosted DynamicMethods Assembly [External]
Total duration: 00:00:05.3827540
--------------------
Function: (var1 + var2 * 3)/(2+3) - something
Number Of Tests: 1,000,000

Interpreted Mode:
Total duration: 00:00:04.4561450
Compiled Mode:
Total duration: 00:00:03.5664070
--------------------
Random Generated Functions: 1,000
Number Of Variables Of Each Function: 3
Number Of Executions For Each Function: 10,000
Total Number Of Executions: 10,000,000
Parallel: True

Interpreted Mode:
Thread started:  #2
Thread started:  #3
Thread finished:  #2
Thread finished:  #3
Total duration: 00:00:28.6792790
Compiled Mode:
Thread started:  #4
Thread started:  #5
* Assertion at mini-codegen.c:2307, condition `sp < 8' not met

Stacktrace:

  at <unknown> <0xffffffff>
  at (wrapper managed-to-native) System.Delegate.CreateDelegate_internal (System.Type,object,System.Reflection.MethodInfo,bool) <IL 0x00024, 0xffffffff>
  at System.Delegate.CreateDelegate (System.Type,object,System.Reflection.MethodInfo,bool,bool) <IL 0x00344, 0x00caf>
  at System.Delegate.CreateDelegate (System.Type,System.Reflection.MethodInfo,bool) <IL 0x00005, 0x00043>
  at System.Delegate.CreateDelegate (System.Type,System.Reflection.MethodInfo) <IL 0x00003, 0x0002f>
  at System.Reflection.Emit.DynamicMethod.CreateDelegate (System.Type) <IL 0x00032, 0x000d3>
  at Jace.Execution.DynamicCompiler.BuildFormulaInternal (Jace.Operations.Operation,Jace.Execution.IFunctionRegistry) [0x0003d] in /home/bb/Jace-master/Jace/Execution/DynamicCompiler.cs:47
  at Jace.Execution.DynamicCompiler.BuildFormula (Jace.Operations.Operation,Jace.Execution.IFunctionRegistry) [0x00017] in /home/bb/Jace-master/Jace/Execution/DynamicCompiler.cs:30
  at Jace.CalculationEngine/<BuildFormula>c__AnonStorey0.<>m__0 (string) [0x0001c] in /home/bb/Jace-master/Jace/CalculationEngine.cs:303
  at Jace.Util.MemoryCache`2/<GetOrAdd>c__AnonStorey0.<>m__0 (TKey) [0x00013] in /home/bb/Jace-master/Jace/Util/MemoryCache.cs:137
  at System.Collections.Concurrent.ConcurrentDictionary`2/<GetOrAdd>c__AnonStorey3.<>m__0 () <IL 0x00012, 0x00039>
  at (wrapper delegate-invoke) System.Func`1<System.Collections.Generic.KeyValuePair`2<string, Jace.Util.MemoryCache`2/CacheItem<string, System.Func`2<System.Collections.Generic.Dictionary`2<string, double>, double>>>>.invoke_TResult__this__ () <IL 0x00054, 0xffffffff>
  at System.Collections.Concurrent.SplitOrderedList`2<string, System.Collections.Generic.KeyValuePair`2<string, Jace.Util.MemoryCache`2/CacheItem<string, System.Func`2<System.Collections.Generic.Dictionary`2<string, double>, double>>>>.ListInsert (System.Collections.Concurrent.SplitOrderedList`2/Node<string, System.Collections.Generic.KeyValuePair`2<string, Jace.Util.MemoryCache`2/CacheItem<string, System.Func`2<System.Collections.Generic.Dictionary`2<string, double>, double>>>>,System.Collections.Concurrent.SplitOrderedList`2/Node<string, System.Collections.Generic.KeyValuePair`2<string, Jace.Util.MemoryCache`2/CacheItem<string, System.Func`2<System.Collections.Generic.Dictionary`2<string, double>, double>>>>,System.Collections.Concurrent.SplitOrderedList`2/Node<string, System.Collections.Generic.KeyValuePair`2<string, Jace.Util.MemoryCache`2/CacheItem<string, System.Func`2<System.Collections.Generic.Dictionary`2<string, double>, double>>>>&,System.Func`1<System.Collections.Generic.KeyValuePair`2<string, Jace.Util.MemoryCache`2/CacheItem<string, System.Func`2<System.Collections.Generic.Dictionary`2<string, double>, double>>>>) <IL 0x00068, 0x001cf>
  at System.Collections.Concurrent.SplitOrderedList`2<string, System.Collections.Generic.KeyValuePair`2<string, Jace.Util.MemoryCache`2/CacheItem<string, System.Func`2<System.Collections.Generic.Dictionary`2<string, double>, double>>>>.InsertInternal (uint,string,System.Collections.Generic.KeyValuePair`2<string, Jace.Util.MemoryCache`2/CacheItem<string, System.Func`2<System.Collections.Generic.Dictionary`2<string, double>, double>>>,System.Func`1<System.Collections.Generic.KeyValuePair`2<string, Jace.Util.MemoryCache`2/CacheItem<string, System.Func`2<System.Collections.Generic.Dictionary`2<string, double>, double>>>>,System.Collections.Concurrent.SplitOrderedList`2/Node<string, System.Collections.Generic.KeyValuePair`2<string, Jace.Util.MemoryCache`2/CacheItem<string, System.Func`2<System.Collections.Generic.Dictionary`2<string, double>, double>>>>&) <IL 0x00039, 0x0014f>
  at System.Collections.Concurrent.SplitOrderedList`2<string, System.Collections.Generic.KeyValuePair`2<string, Jace.Util.MemoryCache`2/CacheItem<string, System.Func`2<System.Collections.Generic.Dictionary`2<string, double>, double>>>>.InsertOrGet (uint,string,System.Collections.Generic.KeyValuePair`2<string, Jace.Util.MemoryCache`2/CacheItem<string, System.Func`2<System.Collections.Generic.Dictionary`2<string, double>, double>>>,System.Func`1<System.Collections.Generic.KeyValuePair`2<string, Jace.Util.MemoryCache`2/CacheItem<string, System.Func`2<System.Collections.Generic.Dictionary`2<string, double>, double>>>>) <IL 0x00008, 0x0006f>
  at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd (TKey,System.Func`2<TKey, TValue>) <IL 0x00058, 0x0022e>
  at Jace.Util.MemoryCache`2.GetOrAdd (TKey,System.Func`2<TKey, TValue>) [0x0003e] in /home/bb/Jace-master/Jace/Util/MemoryCache.cs:133
  at Jace.CalculationEngine.BuildFormula (string,Jace.Operations.Operation) [0x00028] in /home/bb/Jace-master/Jace/CalculationEngine.cs:303
  at Jace.CalculationEngine.Build (string) [0x00042] in /home/bb/Jace-master/Jace/CalculationEngine.cs:159
  at Jace.Execution.FormulaBuilder.Build () [0x0002f] in /home/bb/Jace-master/Jace/Execution/FormulaBuilder.cs:80
  at Jace.Benchmark.Program/<BenchMarkCalculationEngineRandomFunctionBuild>c__AnonStorey0.<>m__0 (string) [0x00034] in /home/bb/Jace-master/Jace.Benchmark/Program.cs:128
  at System.Threading.Tasks.Parallel/<ForEach>c__AnonStorey6`1.<>m__0 (TSource,System.Threading.Tasks.ParallelLoopState,object) <IL 0x00007, 0x0002d>
  at System.Threading.Tasks.Parallel/<ForEach>c__AnonStorey5`2.<>m__0 () <IL 0x000e5, 0x00394>
  at System.Threading.Tasks.TaskActionInvoker/ActionInvoke.Invoke (System.Threading.Tasks.Task,object,System.Threading.Tasks.Task) <IL 0x00006, 0x00029>
  at System.Threading.Tasks.Task.InnerInvoke () <IL 0x0003f, 0x000ad>
  at System.Threading.Tasks.Task.ThreadStart () <IL 0x00098, 0x002eb>
  at System.Threading.Tasks.Task.Execute () <IL 0x00001, 0x00027>
  at System.Threading.Tasks.TpScheduler.<QueueTask>m__0 (object) <IL 0x00006, 0x00043>
  at System.Threading.Thread.StartInternal () <IL 0x0003c, 0x000bf>
  at (wrapper runtime-invoke) object.runtime_invoke_void__this__ (object,intptr,intptr,intptr) <IL 0x0004e, 0xffffffff>

Native stacktrace:

    /usr/bin/mono() [0x8105b4a]
    [0xb771740c]
    [0xb7717424]
    /lib/i386-linux-gnu/libc.so.6(gsignal+0x47) [0xb750c827]
    /lib/i386-linux-gnu/libc.so.6(abort+0x143) [0xb750fc53]
    /usr/bin/mono() [0x8288b23]
    /usr/bin/mono() [0x8288bb3]
    /usr/bin/mono() [0x8100a10]
    /usr/bin/mono() [0x80659b9]
    /usr/bin/mono() [0x8066dd1]
    /usr/bin/mono() [0x8068de4]
    /usr/bin/mono() [0x8069aee]
    /usr/bin/mono() [0x8186398]
    [0xb5bf62e4]
    [0xb5bf4b30]
    [0xb5bf3e54]
    [0xb5bf3de0]
    [0xb5bf3584]
    [0xb5846180]
    [0xb5845f44]
    [0xb584388a]
    [0xb58431d9]
    [0xb5842eea]
    [0xb5843078]
    [0xb5bc2bb0]
    [0xb5842c68]
    [0xb5842a80]
    [0xb584282f]
    [0xb58423b8]
    [0xb5842174]
    [0xb5bf858c]
    [0xb5bf8260]
    [0xb561d20c]
    [0xb561ce7e]
    [0xb561af2d]
    [0xb561ab82]
    [0xb561ab36]
    [0xb561a584]
    [0xb561a278]
    [0xb561a21c]
    [0xb561a1a0]
    [0xb5e1b18d]
    /usr/bin/mono() [0x8069bf0]

Debug info from gdb:

Could not attach to process.  If your uid matches the uid of the target
process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try
again as the root user.  For more details, see /etc/sysctl.d/10-ptrace.conf
ptrace: Operation not permitted.
No threads.

=================================================================
Got a SIGABRT while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================

Variable 'e' is no longer parsed properly

A change was recently made to add support for scientific notation. I believe in doing so we lost the ability to use the built-in variable e.

Attempts to use any formula using the variable e as previously done now fail. e.g.

var engine = new CalculationEngine(CultureInfo.InvariantCulture, ExecutionMode.Compiled);
var result = engine.Calculate("e");

When using more complex functions (1 * e) you receive a rather unclear error message:

There is a syntax issue for the operation \"*\" at position 2. The number of arguments does not match with what is expected.

Reverting the following line change seems to avoid the issue, but I am sure will also prevent the scientific notation support from functioning properly:

return character == decimalSeparator || (character >= '0' && character <= '9') || (isFormulaSubPart && isFirstCharacter && character == '-') || character == 'e' || character == 'E';

Possible race condition in Jace.Util.MemoryCache<TKey, TValue>.EnsureCacheStorageAvailable

I'm using commit 2c0033a.

Description

Probably less than 10% of the time that I run Jace.Benchmarks (in a Debug configuration), in the parallel part during either the interpreted or compiled subpart, there is an unhandled NullReferenceException from the orderby lambda within the keysToDelete query composition in the Jace.Util.MemoryCache<TKey, TValue>.EnsureCacheStorageAvailable method.

When this happens, the current p (a KeyValuePair<TKey, CacheItem> structure) has both Key and Value equal to null, like a default zeroed structure had been retrieved rather than any of the previously added KeyValuePair structures (which seem to always be added to the ConcurrentDictionary with non-null members). The call to LastAccessed seems to be the thrower.

To reproduce

To try to reliably see this error, you can make the following source modification: In Jace.Benchmarks.Program, starting around line 50, adjust the number of random generated functions to 10,000 and the number of executions per function to 1,000. After I do this, I can reliably reproduce the above-mentioned error in every run I launch.

Possible solution

On line 157 of MemoryCache.cs, replacing the query source dictionary with dictionary.ToArray() (which uses ConcurrentDictionary.ToArray, not Enumerable.ToArray) seems to totally resolve the problem by thread-safely taking a snapshot of dictionary before the query is composed and executed.

Possible explanation

Based on the relatively little I've reviewed at the .NET 4.5.1 reference source for Enumerable's query operators, the race condition seems like it might be due to (a) the query's source enumerable being dictionary itself rather than a snapshot and (b) one thread's dictionary.TryRemove (MemoryCache.cs:167) occurring between some enumerator object's MoveNext and Current calls on another thread (the enumerator being some one of the several that exist in the operator call-chain upon query execution) when executing ToList on the composed query (MemoryCache.cs:159).

I'm not (or not yet) super-familiar with LINQ or CLR threading, though, so this explanation might be wrong or at least incomplete.

Matrix & display function itself

Hello :) ,

I got two questions.

How do i get the actual parsed function? Not the result.

Do you have a example for working with matrix?

Arbitrary symbol name handling could be allowed with square brackets

It seems like square brackets are ignored during tokenization, so perhaps they could be used to allow a user to enter a variable name that is any string they'd like, e.g. with spaces, numbers at the beginning, etc.

Not sure how I'd make this change myself, but I'm looking into it when I have a chance.

.NET Standard Nuget Package

I have a need to run Jace in a .NET Core app.
I could not use the Nuget version as it targets the .NET Framework.
So I checked out the Portable library. I ran Visual Studio Portability plugin tool over this project at it gave a 100% pass for .NET Standard.
Whilst I can use the portable lib in my .NET Core library now, I'd love to be able to link it to a NuGet package so I can receive any future updates.
Is this a feasible thing to do ? Or are there some things about the Portable project I'm not aware of ?

Effiency around functions

Wouldn't it be more efficient to register the function like this:

FunctionRegistry.RegisterFunction("sin", (Func<double, double>)Math.Sin, false);`

Instead of

FunctionRegistry.RegisterFunction("sin", (Func<double, double>)((a) => Math.Sin(a)), false);

Thinking of that it would be one less function call.
But I may be mistaken.

Problems with ambiguity of e

The Euler number e is also used for scientific notation. This leads to some problems. E.g.
"-e"
fails with a IndexOutOfBounds exception in TokenReader.Read(string formula).

Percent calculations

Great library, but I'm missing to calculate with percent %. An easy example, 100+20% don't give a result.

Invalid tokens

I have formulas like this:
$Load1/(4*$g)
in which "$Load1" and "$g" are variables.

I get "Invalid token "$" detected at position 0" when I try to run Jace with that.
Why "$" is not accepted as part of the variable name?

thanks,
Giovanni

Documentation error about standard function IF

There is an error on the documentation related to the standard function IF.
The description of the function and the example provided uses the comma (,) as operator separator. It seems that the valid separator is ;

Therefore the correct information for the IF function must be as follow:

  • if(A1; A2; A3) -> GOOD
  • if(A1, A2, A3) -> BAD

The example provided must be changed to:
engine.Calculate("if(var1 < var2; 23; 8)", variables);

Unary minus precedence

Unary minus has higher precedence than power operator:
var result = engine.Calculate("-1^2");
The result must become -1 but becomes +1 instead.

Override operators

Hi there, found this project by looking for alternative to NCalc. Seems to work for me, but i am finding a very high memory issue with it and i see that performance on this project seems very good according to the readme and wiki pages.

One thing i need to know if that is it possible to override the operators? I ask this because if i have + for example, i want to check first if one of the values is NULL, and if so return NULL.

Performance Slowness

Currently at the line mentioned below it can be seen that the DynamicCompiler returns a Func that makes a call to EngineUtil.ConvertVariableNamesToLowerCase. When calling Calculate on the CalculationEngine it has already converted all variable names to lowercase. Ideally, this would be a feature one could opt-out of altogether since users interested in maximizing performance might be enforcing lowercase variable names already.

variables = EngineUtil.ConvertVariableNamesToLowerCase(variables);

If my performance metrics from a project using your nuget package are correct, ~33% of the time executing a calculation (through the CalculationEngine.Build method, so we are already avoiding the repeated call to EngineUtil.ConvertVariableNamesToLowerCase in the CalculationEngine.Calculate method) for us is taken up by ensuring that the variables are all lowercased.

string support

support for string variables, comparison and evaluation. Example:

if(var_1=='A', 'Match', 'No Match')

Scientific notation support

Is it possible to have support for scientific notation?
I'd like to be able to write something like

engine.Build("var1+2.11E-3");

At the moment the error message I get is "The syntax of the provided formula is not valid."

Similarly

engine.Build("2.11E-3");

gives "Unexpected floating point constant "2.11" found."

Thanks

Interpreter.BuildFormula does not work with constants

Running the following throws and exception, that the variable "pi" was not found:

CalculationEngine engine = new CalculationEngine(CultureInfo.InvariantCulture, ExecutionMode.Interpreted);
Func<Dictionary<string, double>, double> formula = engine.Build("pi");
Dictionary<string, double> variables = new Dictionary<string, double>();
double result = formula(variables);

However, when running this with ExecutionMode.Compiled it works as expected.

The difference is, that Interpreter that is used in ExecutionMode.Interpreted does not check for constants as DynamicCompiler does that is used in ExecutionMode.Compiled:

private static class PrecompiledMethods
{
    public static double GetVariableValueOrThrow(string variableName, FormulaContext context)
    {
        if (context.Variables.TryGetValue(variableName, out double result))
            return result;
        else if (context.ConstantRegistry.IsConstantName(variableName))
            return context.ConstantRegistry.GetConstantInfo(variableName).Value;
        else
            throw new VariableNotDefinedException($"The variable \"{variableName}\" used is not defined.");
    }
}

I will create a pull request where this check of the ConstantRegistry is added to the Interpreter.

Documentation Does not match Released Master Version

Hello,
(New here on Github. )
I was looking for a calculation engine for my project and yours is very good. However, when trying out the compile-time constant example (image attached) I noticed that the documentation for the same does not match the Master branch released version.
Seems like that feature is still in the dev branch.

Annotation 2019-12-31 102117

Thought to bring it to your notice.

Also, I saw that you are incorporating .Net Core as well and planning a release for 1.0 version. Is there an estimate on when the version 1.0 would be released?

Thank you for everything.
Regards,

Non base-10 numbers

Hello again

Another feature that would be nice is support for non base 10 integers
For example 0x for hex and 0b for binary

Support complex number

Do you have any plan to add support variable as complex number, i? Since .NET 4.0 or .NET 4.5, Microsoft start introduce System.Numerics.Complex, and Imaginary number.

This is very useful especially in composing math expression in electronic engineering computing. Or you can give me some tips maybe I can try to fork your repo and extend myself. Or should I go for NCalc for more easier implementation? (As I know, NCalc also not support yet).

Separator in different culture

I don't know if Jace is designed to be culture-dependent, but I think that the syntax found in this Wiki must be equal for all users, indipendently from the OS culture.

I forced this in TokenReader.cs by using:
//this.decimalSeparator = cultureInfo.NumberFormat.NumberDecimalSeparator[0]; this.decimalSeparator = '.'; //this.argumentSeparator = cultureInfo.TextInfo.ListSeparator[0]; this.argumentSeparator = ',';

Just to share with everyone.

Rev to version 1.0?

I saw from your blog (Pieter) that you plan to rev to 1.0 when you add a few more features. Does it really need to wait for those?
Most people are nervous about using something that has a version number less than 1 (ok.. they're typically nervous for 1 as well, but less so).
This looks like a quality library. I like the test coverage. But I noticed it doesn't have as many downloads as I would expect.
Do you think the number of downloads would increase if it had a version that signals, "This is released"?

Refuses to parse expression with ternary operator

Hi,

I'm trying to parse the following expression a + (d <= d1 ? b * -0.01 : (d <= d2 ? b * 0.02 + c * 0.03 : 0))

However it fails saying it doesn't expect the multiplication

Jace.ParseException
Unexpected floating point constant "-0.01" found.
   at Jace.AstBuilder.VerifyResultStack()
   at Jace.AstBuilder.Build(IList`1 tokens)
   at Jace.CalculationEngine.BuildAbstractSyntaxTree(String formulaText)
   at Jace.CalculationEngine.Build(String formulaText)

Any idea on how I could achieve this ?

Engine ThreadSafety

Is the ThreadEngine meant to be thread safe so I can use it as a singleton accross threads?

Is this project still being updated?

Looking for an alternative to NCALC and come across to this package, but wondered if tis still maintained or updated?

Does this project works with .NET5 and the upcoming .NET6? If it doesnt, can it be updated? How soon?

Bitwise operations

Hello!
Great library, however i am missing native bitwise operations support.
For example bitwise shifting (>> and <<) or bitwise inversion (~)
They can be substituted with functions, but having them as supported operations would be nice

Wrong precendence for unitary minus and exponential

I stumbled across this problem when entering the normal distribution. I could narrow the problem down to the following issue:

-(1)^2 is interpreted as (-1)^2 giving 1 as a result although it should be -1.
The same happens when parsing -1^2 which is equal to -(1)^2.

This is because the precedence of the operations is wrong. I will provide a PR.

sqrt(): return positive and negative values

According to Wikipedia:

In mathematics, a square root of a number a is a number y such that y^2 = a; in other words, a number y whose square (the result of multiplying the number by itself, or y ⋅ y) is a. For example, 4 and −4 are square roots of 16 because 42 = (−4)2 = 16.

To facilitate this, an Operation would be need to handle processing and returning two doubles. Each operation would have to decide if it will operate on the double and possibly filter out double.NaN.

I see this as a major overhaul and a major breaking change, and would require a bump in the major version if following semver.

Once that overhaul is complete, it would be trivial to return new Tuple<double, double>(Math.Sqrt(x), -Math.Sqrt(x)) for the Sqrt function operation. Alternatively, a new internal model could be passed around that includes the double result as well as a flag that indicates the next operation should be performed on both the result and the negation of the result. Edit: This would not work as the next operation may alter the negation result differently and that information would need to be communicated to further operations and eventually the caller.

Thoughts?

Issue with variable case sensitivity

When testing out your example:

CalculationEngine engine = new CalculationEngine();
Func<Dictionary<string, double>, double> formula = engine.Build("var1+2/(3*otherVariable)");

        Dictionary<string, double> variables = new Dictionary<string, double>();
        variables.Add("var1", 2);
        variables.Add("otherVariable", 4.2);

        double result = formula(variables);

I get an exception that says "othervariable is not defined." If I change 'variables.Add("otherVariable",4.2");' to 'variables.Add("othervariable",4.2");' then it works fine. The variables in the formula seem to be getting converted to lower case. Can you confirm this bug? I am using version 0.8.3.

Invalid floating point numbers cause InvalidOperationException

First of all: Thanks for the very good and performant mathematical formula parser.

When only entering "." as a formula or any other invalid floating point number like "..", "..1", "0..1" the TokenReader will skip this, causing the AstBuilder to throw an InvalidOperationException because it expects the token list not to be empty. The token reader should throw an ParseException in this case.

Special characters support

I'd like to define variables with special characters.
Now I'm using the _ (underscore) character to differentiate two type of variables. But I need to differentiate a third type of variable and I'd like to use characters like | or # or : or ? etc.
Can you add the support of one of this characters for the name of a variable?

Thank you

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.