Proektsoftbg / Calcpad

Free and open source software for mathematical and engineering calculations.
https://calcpad.eu
MIT License
391 stars 46 forks source link

Operations order? #154

Closed johnnyontheweb closed 1 year ago

johnnyontheweb commented 1 year ago

Hello, see this other issue of an external library : https://github.com/pieterderycke/Jace/issues/79 in which CalcPad is cited for comparison. I believe CalcPad assumes the correct operations order. On the other hand, Excel gives different results for the same formulas (see linked issue), mainly because the minus sign before u is not evaluated in operations order. Please find attached excel file. test.xlsx

I need to clarify this - thanks in advance

Proektsoftbg commented 1 year ago

Hi,

This has been broadly discussed years ago. The mathematically correct order is as specified in Wikipedia: -3^2 = -9 and 2^3^3 = 2^(3^3) = 2^27 and not -3^2 = 9 or (2^3)^3 = 8^3.

I know that Excel works differently. In the early versions of Calcpad, we made it exactly as in Excel for compatibility. However, this was well explained and documented. And still it is: https://calcpad.eu/help/21/operators

Years ago, after a long discussion, we changed it to match the commonly accepted mathematical rules. Wolfram Alpha also calculates like this: -2^2 2^3^3

About the discussion, you are generally right. Also, I definitely disagree with four things:

  1. The "minus" in "-u" is not the "sign of u". This is a unary operator. If we have 0 - u, then it is a binary operator.
  2. The exponentiation operator x^y is not "x" multiplied "y" times: "-2^2 is (-2 * -2)". This is just a special case, where "y" is a natural number. But what about x^1.5 or x^pi or x^z, where z is a complex number.
  3. C# is not a good example here, because it does not have the x^y operator (and for any C-like language that applies). Instead, it uses the Math.Pow(x, y) function, which is quite different. However, in VB.NET, which has this operator, -2^2 = -4.
  4. Speaking about math programming, I think that the "golden standard" should be Wolfram Mathematica, and not C#.

However, for such niche specific languages like Calcpad, Excel or Jace, it is possible to have their specific syntax that may differ from the common math notation, which obviously is the case for Excel. It should not be a problem as long as it is well documented and known.

BTW, you can use Calcpad as a C# library to parse expressions in the same way as Jace. You have to reference the Calcpad.Core project. You can check the source code of the Command line interpreter:

https://github.com/Proektsoftbg/Calcpad/blob/main/Calcpad.Cli/Program.cs

johnnyontheweb commented 1 year ago

Thanks a lot for the explanation!

Proektsoftbg commented 1 year ago

BTW, I used the benchmark project from this blog post to test Calcpad versus Jace and NCalc.

First, I upgraded the project to the latest .NET 7.0. Otherwise, I would not be able to use it with Calcpad. Then, installed Jace and NCalc packages from Nuget and also referenced Calcpad.Core.dll. I added a test method similar to others but for Calcpad:

       private static void BenchmarkCalcpad(IEnumerable<string> formulas)
        {
            DateTime startTime = DateTime.Now;
            var parser = new MathParser(new MathSettings());
            foreach (string formula in formulas)
            {
                parser.Parse(formula);
                for (int i = 0; i < NumberOfTests; i++)
                {
                    parser.SetVariable("var1", NextDouble());
                    parser.SetVariable("var2", NextDouble());
                    parser.SetVariable("var3", NextDouble());
                    double resultCalcpad = parser.CalculateReal();
                }
            }
            DateTime endTime = DateTime.Now;
            Console.WriteLine("Execution time Calcpad: {0}", endTime - startTime);
        }

Finally, I compiled the code to release and run the app from the "\bin\Release\" folder.

On my machine, I got the following results:

image

The upgraded benchmark project can be downloaded from here: CalcBenchmark.zip

Jace looks very professional and also NCalc. Although Calcpad was not designed as a .NET library, it performed 2-3 times faster. :)

johnnyontheweb commented 1 year ago

Wow, it looks very good - I should definitely try CalcPad as interpreter for my scripts. I have to say that this test seems to contradict what's showed in this blog post (it seems Jace became slower than Ncalc, at least on .NET 7). Thanks also for sharing the code. However, to let me use CalcPad for my scripts, I need the support for custom functions (ex. MyFunction(x,y)).

Proektsoftbg commented 1 year ago

Actually, you can use functions and other advanced Calcpad features: units, numerical methods, etc.

parser.Parse("f(x)=x^2");
parser.Calculate();

Then, you can use it further:

parser.Parse("f(1)");
parser.Calculate();
johnnyontheweb commented 1 year ago

Thanks, but I need something more complex, e.g. I want to write the code for the function (also to interact with other data and other existing libraries of mine), this is not as simple as defining f(x)=...

Proektsoftbg commented 1 year ago

If it is a very complex function, you can write it directly in C#. It will still read and write Calcpad variables and interact with whatever else you need.

If you need to keep your code in strings and execute it dynamically, use the Roslin Scripting API: https://github.com/dotnet/roslyn/blob/main/docs/wiki/Scripting-API-Samples.md

It is the most native and powerful way to compile and execute C# code at runtime. I do not think we can do something better about that. First, you need to install the package:

Install-Package Microsoft.CodeAnalysis.CSharp.Scripting

Then, add a using clause and... use it: using Microsoft.CodeAnalysis.CSharp.Scripting; double result = await CSharpScript.EvaluateAsync<double>("1d + 2d");

Explore the samples from the above link to learn more. It is very well explained. :)

johnnyontheweb commented 1 year ago

Thanks for the hint, however the code in functions cannot be scripted (just for clarity: I have compiled functions, not to be scripted). I need something like https://github.com/pieterderycke/Jace/wiki/Custom-Functions

Proektsoftbg commented 1 year ago

OK. I see. We can add such feature if we decide in future to make Calcpad a .NET library.