web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Small and medium business | Business Central, N...
Suggested Answer

Procedure to calculate and validate an expression in business central

(0) ShareShare
ReportReport
Posted on by 241

Hi, how are you all doing? Hope you all are doing great. I'm looking for a procedure to calucate and validate an expression in business central (v:15)

I don't want to call any dotnet function to calculate and validate an expression in business central.

For example, there is an input expression:

Input Expression = '((2+3)*2)-1'

Result = 9

Can anyone please tell me if there is any built in procedure to calculate and validate an expression or any alternative way other than dotnet in business central? Answers will be highly appreciated.

Thanks for reading.

I have the same question (0)
  • Suggested answer
    Tabrez Ajaz Profile Picture
    785 on at

    Hello @javed,

    It's a little bit hard without using any dotnet function. But there's also a workaround that you can try by creating a control add-in and using javascript code on-page. It's just a suggestion, I will try this to give you a better idea.

    For calculating this kind of mathematical expression you need to think about all the symbols that you will gonna use while entering the expression after that you need to find which expression is going to execute first, based on the opening and closing brackets.

    I can provide you a MathLib codeunit as given follows, given codeunit can do different mathematical calculation but can't able to solve an expression you need to look into, I will also confirm when I will come up with any solution:

    codeunit 80005 MathLib

    {

       // Mathlib by René Thöne/Landefeld Druckluft GmbH Kassel rthsw@web.de.

       // Uses free avaible Algorithmen from the last 300 Years.

       // Please feel free to use and Modify, but for Fairness let my name in the Unit.

       trigger OnRun()

       begin

           MESSAGE('Ln(20) = %1', Ln(20));

           MESSAGE('Lg(7) = %1', Log(7));

           MESSAGE('6! = %1', "!"(6));

           MESSAGE('Sin(30) = %1', Sin("Grad>Rad"(30)));

           MESSAGE('Cos(30) = %1', Cos("Grad>Rad"(30)));

           MESSAGE('Tan(30) = %1', Tan("Grad>Rad"(30)));

           MESSAGE('ArcSin(0.2) = %1', "Grad>Rad"(0.2));

           MESSAGE('ArcCos(0.3) = %1', ArcCos("Grad>Rad"(0.3)));

           MESSAGE('ArcTan(-5.8) = %1', ArcTan(-5.8));

           MESSAGE('30° adjusted by PI = %1', Adjust(30));

           MESSAGE('Squareroot of 30 = %1', Sqrt(30));

           MESSAGE('the greatest common Divisor of 35 and 25 = %1', gcd(35, 25));

           MESSAGE('the least common multipler of 35 and 25 = %1', lcm(35, 25));

           MESSAGE('29 is %1 prime, 30 is %2 prime', Prime(29), Prime(30));

           MESSAGE('the CrossFoot of 123 is %1', CrossFoot(123));

           MESSAGE('PI = %1, Exp = %2, e (euler) = %3', Pi, E, Euler);

           MESSAGE('the sign of -23 is %1, the sign of 45 is %2', Sign(-23), Sign(45));

           MESSAGE('the max of 23 and 45 is %1', Max(23, 45));

           MESSAGE('the min of 23 and 45 is %1', Min(23, 45));

           MESSAGE('the Integer of 34,567 is %1', Int(34.567));

           //the following Units are also working, but no examples given

           //EuklDistance

           //ManhDistance

           //StreetDistance

           //ConvLongtitute2Km

           //ConvLatitude2Km

       end;

       var

           VarName: array[99] of Code[20];

           VarValue: array[99] of Decimal;

       [Scope('Internal')]

       procedure "!"(x: Decimal) "Fakultät": Decimal

       begin

           Fakultät := x;

           WHILE x > 1 DO BEGIN

               x -= 1;

               Fakultät := Fakultät * x

           END;

       end;

       [Scope('Internal')]

       procedure Sin(x: Decimal): Decimal

       begin

           //Taylor works well, but differs in the near of 90°

           //EXIT(

           //  x - (POWER(x,3)/"!"(3)) + (POWER(x,5)/"!"(5))

           //  - (POWER(x,7)/"!"(7)) + (POWER(x,9)/"!"(9))

           //  - (POWER(x,12)/"!"(11)));

           //so better use Horner

           EXIT(x * (1 - (x * x) * (1 - (x * x) * (1 - (x * x) * (1 - (x * x) * (1 - (x * x) * (1 - (x * x) * (1 - (x * x) * (1 - (x * x)

           / (16 * 17)) / (14 * 15)) / (12 * 13)) / (10 * 11)) / (8 * 9)) / (6 * 7)) / (4 * 5)) / (2 * 3)));

       end;

       [Scope('Internal')]

       procedure Cos(x: Decimal) Cos: Decimal

       begin

           /*EXIT(

             1 - (POWER(x,2)/"!"(2)) + (POWER(x,4)/"!"(4))

             - (POWER(x,6)/"!"(6)) + (POWER(x,8)/"!"(8))

             - (POWER(x,10)/"!"(10)));*/

           //Taylor gives better result in normal areas, but Honer results better on extreme (0° 90°)

           EXIT(Sin(x + Pi / 2));

       end;

       [Scope('Internal')]

       procedure Tan(x: Decimal): Decimal

       begin

           EXIT(Sin(x) / Cos(x));

       end;

       [Scope('Internal')]

       procedure ArcSin(x: Decimal) a: Decimal

       begin

           IF x < 0 THEN

               EXIT(-ArcSin(-x))

           ELSE

               IF x = 1 THEN

                   EXIT(Pi / 2)

               ELSE

                   EXIT(ArcTan(x / Sqrt(1 - x * x)));

       end;

       [Scope('Internal')]

       procedure ArcCos(x: Decimal) a: Decimal

       begin

           IF x < 0 THEN

               EXIT(Pi - ArcCos(-x))

           ELSE

               IF x = 0 THEN

                   EXIT(Pi / 2)

               ELSE

                   EXIT(ArcTan(Sqrt(1 - x * x) / x));

       end;

       [Scope('Internal')]

       procedure ArcTan(x: Decimal) ATan: Decimal

       var

           "Sum": Decimal;

           i: Integer;

           Inverting: Boolean;

       begin

           //Again, Taylor is our friend, but only from -1..1, the rest will be calculated by this.

           Inverting := (x < -1) OR (x > 1);

           IF Inverting THEN

               x := 1 / x;

           CLEAR(ATan);

           FOR i := 1 TO 100 DO BEGIN

               ATan += (POWER(x, i) / i) - (POWER(x, i + 2) / (i + 2));

               i += 3;

           END;

           IF Inverting THEN

               IF x > 0 THEN

                   EXIT(Pi / 2 - ATan)

               ELSE

                   EXIT(-Pi / 2 - ATan)

       end;

       [Scope('Internal')]

       procedure Log(x: Decimal): Decimal

       begin

           EXIT(CalcLog(10, x));

       end;

       [Scope('Internal')]

       procedure Ln(x: Decimal): Decimal

       begin

           EXIT(CalcLog(E, x));

           //You could also calculate Ln with Taylorrows. It's (depending on the Acuracy) faster than the Root.

           //I preffer the Root-Algorythmus, because it is "smarter" and becomes allways maximal accurate.

           //Taylor becommes on very low (< 0,5) and high (> 100) Values more unaccurate.

           //IF (x <= 0) THEN

           //  ERROR('Ln out of Range (>0)');

           //CLEAR(Sum);

           //FOR i := 1 TO 40 DO BEGIN

           //  Sum := Sum + POWER(x-1,i) / (i * POWER(x+1,i));

           //  i += 1; //Step2

           //END;

           //For Ln (Base euler)->

           //EXIT(2*Sum);

           //For Log (Base 10)

           //exit(x/2.30258509299);

       end;

       local procedure CalcLog(Base: Decimal; x: Decimal): Decimal

       var

           Down: Decimal;

           Up: Decimal;

           Step: Decimal;

           Steps: Integer;

           LeadingZeros: Integer;

           LeadingZeroString: Text[30];

       begin

           CLEAR(Steps);

           IF x = 1 THEN //Log(1) = 1;

               EXIT(1);

           //first find upper and lower Range

           IF x > 1 THEN BEGIN

               Up := 1;

               Down := 0;

               WHILE POWER(Base, Up) < x DO

                   Up *= 2;

               Down := Up;

               WHILE POWER(Base, Down) > x DO

                   Down /= 10;

           END ELSE BEGIN

               //On Values 0..1 (except 0) the leading zeros are the offset in -Integer

               //i.e. 0,0027 leads to -2, because the LOG will be something between -2 and zero.

               Down := -STRLEN(COPYSTR(FORMAT(x, 0, '<decimals,0>'), 2)) -

                 STRLEN(DELCHR(COPYSTR(FORMAT(x, 0, '<decimals,0>'), 2), '<', '0'));

               Up := 0;

           END;

           //moving the Ranges step by step to the Result. Steps become smaler every loop.

           REPEAT

               Steps += 1;

               Step := (Up - Down) / 2;

               IF POWER(Base, Step + Down) > x THEN

                   Up -= Step

               ELSE

                   Down += Step;

           UNTIL Steps = 53; //after this Navision doesnt get exacter. The first 12-14 decimals are allways acurate.

           EXIT(ROUND(Up, 0.000000000000001));

       end;

       [Scope('Internal')]

       procedure Adjust(x: Decimal): Decimal

       begin

           REPEAT

               IF x <= -Pi THEN

                   x := x + 2 * Pi;

               IF x > Pi THEN

                   x := x - 2 * Pi

           UNTIL (x > -Pi) AND (x <= Pi);

       end;

       [Scope('Internal')]

       procedure "Grad>Rad"(Grad: Decimal) Rad: Decimal

       begin

           EXIT(Grad / 180 * Pi);

       end;

       [Scope('Internal')]

       procedure "Deg>Rad"(x: Decimal): Decimal

       begin

           EXIT(x * (Pi / 180));

       end;

       [Scope('Internal')]

       procedure "Rad>Deg"(x: Decimal): Decimal

       begin

           EXIT(x * (180 / Pi));

       end;

       [Scope('Internal')]

       procedure Sqrt(x: Decimal): Decimal

       begin

           EXIT(POWER(x, 0.5));

       end;

       [Scope('Internal')]

       procedure gcd(x: Decimal; y: Decimal): Decimal

       var

           Puffer: Decimal;

       begin

           //größter gemeinsamer Teiler

           x := ABS(Int(x));

           y := ABS(Int(y));

           IF (x = 0) AND (y = 0) THEN

               EXIT(0);

           IF (x = 0) OR (x = y) THEN

               EXIT(y);

           IF y = 0 THEN

               EXIT(x);

           REPEAT

               IF x < y THEN BEGIN

                   Puffer := x;

                   x := y;

                   y := Puffer;

               END;

               Puffer := x MOD y;

               x := y;

               y := Puffer;

           UNTIL Puffer = 0;

           EXIT(x);

       end;

       [Scope('Internal')]

       procedure lcm(x: Decimal; y: Decimal): Decimal

       begin

           //kleinstes gemeinsames Vielfaches

           x := ABS(Int(x));

           y := ABS(Int(y));

           EXIT(x * y DIV gcd(x, y));

       end;

       [Scope('Internal')]

       procedure Prime(x: Decimal): Boolean

       var

           i: Integer;

       begin

           //Primzahl?

           x := ABS(x);

           IF x IN [0, 1] THEN

               EXIT(FALSE);

           IF x IN [2, 3] THEN

               EXIT(TRUE);

           i := 2;

           WHILE i <= Int(Sqrt(x)) DO BEGIN

               IF (x MOD i = 0) THEN

                   EXIT(FALSE);

               i += 1;

           END;

           EXIT(TRUE);

       end;

       [Scope('Internal')]

       procedure CrossFoot(x: Decimal): Decimal

       begin

           //Quersumme

           x := ABS(Int(x));

           EXIT((x - 10) MOD 9 + 1);

       end;

       [Scope('Internal')]

       procedure "(a+b)²"(a: Decimal; b: Decimal): Decimal

       begin

           //Binomic1

           EXIT(POWER(a, 2) + 2 * a * b + POWER(b, 2));

       end;

       [Scope('Internal')]

       procedure "(a-b)²"(a: Decimal; b: Decimal): Decimal

       begin

           //Binomic2

           EXIT(POWER(a, 2) - 2 * a * b + POWER(b, 2));

       end;

       [Scope('Internal')]

       procedure "(a+b)*(a-b)"(a: Decimal; b: Decimal): Decimal

       begin

           //Binomic3

           EXIT(POWER(a, 2) - POWER(b, 2));

       end;

       [Scope('Internal')]

       procedure Pi(): Decimal

       begin

           EXIT(3.1415926535897932384626);

       end;

       [Scope('Internal')]

       procedure E(): Decimal

       begin

           EXIT(2.7182818284590452353603);

       end;

       [Scope('Internal')]

       procedure Euler(): Decimal

       begin

           EXIT(0.5772156649015328606065);

       end;

       [Scope('Internal')]

       procedure Sign(x: Decimal): Integer

       begin

           IF x < 0 THEN

               EXIT(-1);

           IF x = 0 THEN

               EXIT(0);

           EXIT(1);

       end;

       [Scope('Internal')]

       procedure "Max"(Dec1: Decimal; Dec2: Decimal): Decimal

       begin

           IF Dec1 > Dec2 THEN

               EXIT(Dec1)

           ELSE

               EXIT(Dec2);

       end;

       [Scope('Internal')]

       procedure "Min"(Dec1: Decimal; Dec2: Decimal): Decimal

       begin

           IF Dec1 > Dec2 THEN

               EXIT(Dec2)

           ELSE

               EXIT(Dec1);

       end;

       [Scope('Internal')]

       procedure Int(x: Decimal): Decimal

       begin

           EXIT(ROUND(x, 1, '<'));

       end;

       [Scope('Internal')]

       procedure EuklDistance(x1: Decimal; y1: Decimal; x2: Decimal; y2: Decimal): Decimal

       begin

           EXIT(Sqrt(POWER((x2 - x1), 2) + POWER((y2 - y1), 2)));

       end;

       [Scope('Internal')]

       procedure ManhDistance(x1: Decimal; y1: Decimal; x2: Decimal; y2: Decimal): Decimal

       begin

           EXIT(ABS(x2 - x1) + ABS(y2 - y1));

       end;

       [Scope('Internal')]

       procedure StreetDistance(x1: Decimal; y1: Decimal; x2: Decimal; y2: Decimal): Decimal

       begin

           EXIT((ABS(x2 - x1) + ABS(y2 - y1)) * 1.111);

       end;

       [Scope('Internal')]

       procedure ConvLongtitute2Km(Latitude: Decimal; x: Decimal): Decimal

       var

           Multiplier: Decimal;

       begin

           //Längengrad zu Km

           EXIT(Cos("Grad>Rad"(Latitude)) * 111.32386667);

       end;

       [Scope('Internal')]

       procedure ConvLatitude2Km(x: Decimal): Decimal

       begin

           //Breitengrad zu km

           EXIT(x * 111.32386667);

       end;

       local procedure "---Parser---"()

       begin

       end;

       [Scope('Internal')]

       procedure Parse(String: Integer) result: Decimal

       begin

           InitParser;

       end;

       local procedure SetV(Name: Code[20]; Value: Decimal)

       var

           i: Integer;

           TXTEmptyName: Label 'Empty Varname for Value %1';

           FirstFreeVar: Integer;

           TXT2MaxVars: Label 'Not enough room to store %1. Only 99 Vardefinitions are allowed.';

       begin

           IF Name = '' THEN

               ERROR(TXTEmptyName);

           CLEAR(FirstFreeVar);

           FOR i := 1 TO 99 DO BEGIN

               IF VarName[i] = Name THEN BEGIN

                   VarValue[i] := Value;

                   EXIT;

               END;

               IF VarName[i] = '' THEN BEGIN

                   FirstFreeVar := i;

                   i := 100;

               END;

           END;

           IF FirstFreeVar = 0 THEN

               ERROR(TXT2MaxVars, Name);

           VarName[FirstFreeVar] := Name;

           VarValue[FirstFreeVar] := Value;

       end;

       local procedure GetV(Name: Code[20]) Value: Decimal

       var

           i: Integer;

           TXTunknownVar: Label 'Unknown Var: %1';

       begin

           FOR i := 1 TO 99 DO

               IF VarName[i] = Name THEN

                   EXIT(VarValue[i]);

           ERROR(TXTunknownVar, Name);

       end;

       local procedure InitParser()

       begin

           CLEAR(VarName);

           CLEAR(VarValue);

       end;

    }

    This MathLib codeunit doesn't contain a solution for your question but it's good to know what other MATH things we can do in Business Central

  • M Hussnain Javed Profile Picture
    241 on at

    Hi Tabrez Ajaz, thanks for replying.

    I created a javascript function and invoked it on the page and it's working fine on the page. We can invoke a JS fuction on the page using currpage.controladdinName.JSFunctionName();

    But I need to invoke that JS function in the codeunit but all in vain beacuse we can't use currpage in the codeunit and without keyword currpage js function doesn't work. That's why I'm looking for a way to write a function in codeunit to calculate and validate an expression.

    I found a procedure that validates and calculates an expression here: 

    math function - Developers Forum - Dynamics 365 Business Central/NAV User Group - Dynamics User Group

    but there are two errors in this procedure 

    0028.png

  • Suggested answer
    Tabrez Ajaz Profile Picture
    785 on at

    Hi @Javed,

    Refer to the below API, make a request to the API with your math expression and read the returned response:

    https://api.mathjs.org/

    I hope this will help don't forget to verify to help others in the community.

    Good Luck :)

  • Tolo Profile Picture
    on at

    Hi,

    The question posted is a bit old but I found it because I was searching precisely a function or procedure to calculate expressions as a complement of another software.

    I couldn't find it. So, I decided to make that procedure which I will share in case it may be of interest.

    I'll check it (debug) and publish soon!

    Thanks.

    Tolo

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Neeraj Kumar – Community Spotlight

We are honored to recognize Neeraj Kumar as our Community Spotlight honoree for…

Leaderboard > Small and medium business | Business Central, NAV, RMS

#1
OussamaSabbouh Profile Picture

OussamaSabbouh 2,606

#2
YUN ZHU Profile Picture

YUN ZHU 931 Super User 2025 Season 2

#3
Jainam M. Kothari Profile Picture

Jainam M. Kothari 773 Super User 2025 Season 2

Last 30 days Overall leaderboard

Featured topics

Product updates

Dynamics 365 release plans