**USING ***paceval.* – A SIMPLE CODE EXAMPLE

*paceval.*– A SIMPLE CODE EXAMPLE

If you want to work with a math function like the one below

then the function then looks like this in standard mathematical form

** f(x,y) = -sin(x*cos(x))^(1/y)**

using two variables **x** and **y**.

You only need to create a * paceval.*-Computation object once with this code:

#### Programming with **pace**val. – C/C++

**pace**val.

**PACEVAL_HANDLE** handle_pacevalComputation = **paceval_CreateComputation**(“-sin(x*cos(x))^(1/y)”, 2, “x y”, false);

###### (see also the **paceval. Application programming interface (API)**)

**paceval_CreateComputation**(…) creates an object that identifies the sub-functions and sub-calculations in the specified function and returns the handle of the * paceval.*-Computation object. This one-time precompilation, including function parsing, takes time: less than 1 millisecond on a standard processor used for the Internet of Things (IoT), and even less on a standard computer.

This may already seem very fast, but think about the total time you would have to keep interpreting the function for whatever values you want to compute results for. This could be thousands of values if you wanted to graph the function, for example, and it might take minutes to calculate all the results this way. Therefore, with * paceval*., you can declare the variables by calling

**paceval_CreateComputation**(…) once, which caches all sub-functions and sub-computations and creates a binary image of the function optimized for small size and speed. Ideally, you run

**paceval_CreateComputation**(…) at the very beginning of your program on all your static math models to speed up future computations. You get the result for concrete values of the variables with

**paceval_GetComputationResult**(…).

For the example above, if you want to get the result for **x = 0.5** and **y = 2**, just use this code:

#### Programming with **pace**val. – C/C++

**pace**val.

long double valuesVariablesArray[2];

long double ldResult;

valuesVariablesArray[0] = 0.5; //the x-value

valuesVariablesArray[1] = 2; //the y-value

ldResult = **paceval_ldGetComputationResult**(handle_pacevalComputation, valuesVariablesArray, NULL, NULL);

//ldResult is approximately -0.65180178245228

###### (see also the **paceval. Application programming interface (API)**)

The return value is the result of the calculation. **paceval_GetComputationResult**(…) uses the cached sub-functions and sub-computations previously created by **paceval_CreateComputation**(…). The time required for this calculation result is as short as the time required with compiled standard C++ source code (or even less, depending on the function).

Below is the corresponding standard C++ source code for the example above:

#### Standard programming – C/C++

long double valuesVariablesArray[2];

long double ldResult;

valuesVariablesArray[0] = 0.5; //the x-value

valuesVariablesArray[1] = 2; //the y-value

ldResult = -1*powl(sinl(valuesVariablesArray[0]*cosl(valuesVariablesArray[0])), 1/valuesVariablesArray[1]);

//ldResult is approximately -0.65180178245228

An obvious advantage of * paceval.* over standard C++ code is the readability of the source code and the functionality for error handling. In this example, if

**y**were set to

**0**or close to

**0**, the C++ code would fail because the term would be divided by 0. Otherwise the user would not know why the calculation fails.

* paceval.* automatically detects and localizes this error. For detailed information, just get more information about

**paceval_GetIsError**(…) and

**paceval_GetErrorInformation**(…) in the

**pace**val.**Application programming interface (API)**. In addition, the maintenance of the mathematical model is easier. You could collect all the string representations of the math functions and variables in a central area of code or a database. In addition, the implementation of long functions is easy to handle, since

*imposes no limit on the length and number of variables of the function. The limit is set only by the memory of the underlying system. Imagine a mathematical model consisting of 50 very complex individual functions, each with a minimum length of 50,000 characters and 100 variables. Such a model would be almost impossible to maintain in a way that all users could understand. You can easily find these scenarios in cars with 100+ sensors to monitor, watchdog applications for sensitive products, or stock monitoring and trading applications.*

**pace**val.But there is much more you can do with * paceval.* to better interpret your results. Especially if you are using a very complex mathematical model made up of long functions. This leads to many rounding errors that cannot be accounted for by standard programming. Here

*is the perfect solution. You can easily enable Trusted Interval Computation, TINC™. TINC is the*

**pace**val.*specific*

**pace**val.**Interval arithmetic**optimized for speed.

In the example above, just make the changes highlighted in **green **to use TINC and get the interval that covers the actual result:

#### Programming with **pace**val. – C/C++

**pace**val.

**PACEVAL_HANDLE** handle_pacevalComputation = **paceval_CreateComputation**(“-sin(x*cos(x))^(1/y)”, 2, “x y”, **true**);

###### (see also the **paceval. Application programming interface (API)**)

#### Programming with **pace**val. – C/C++

**pace**val.

long double valuesVariablesArray[2];

long double ldResult;**long double minResultInterval; ****long double maxResultInterval;**

valuesVariablesArray[0] = 0.5; //the x-value

valuesVariablesArray[1] = 2; //the y-value

ldResult = **paceval_ldGetComputationResult**(handle_pacevalComputation, valuesVariablesArray, **&minResultInterval**, **&maxResultInterval**);

// ldResult is approximately -0.65180178245228

// minResultInterval as lower confidence bound is -0.6518017824522809982

// maxResultInterval as upper confidence bound is -0.6518017824522740538

###### (see also the **paceval. Application programming interface (API)**)

# With *pace**val**.*, approximations can be displayed quickly and accurately

*pace*

*.*

With a simple script, a possibly **very long mathematical function is generally generated in a matter of seconds as an approximation across measurement series.** This approximation should then represent a precise mathematical model and can be used and evaluated in separate programs. In this way, inaccurate, error-prone models are eliminated and critical time of the development process is saved and used for immediate further development.

In engineering mathematics, it often happens that complex products require extensive series of measurements. You then have to derive a mathematical model using approximations in order to be able to describe it in the software. This step requires a lot of effort and becomes very time consuming without a product like *pace**val**.* Due to the size of the relevant points within a series of measurements, it can be impossible to find a simple mathematical function that describes them.

A vivid example is a turbine, which has different parameters depending on its duration and size. Small variations, due to the manufacturing process and material properties, result in individual differences and specific adjustments for each turbine. Therefore, the approximation must also be customized and extremely precise and readily available.

A simple example: You want to approximate the measurements (1.5, 6), (2.5, 3), and (3.5, 25), where the values are directly related. This function can be passed to *pace**val**.* immediately:

f(x)= **((x>=1.5) AND (x<=2.5))***(((3-6)/(2.5-1.5))*(x-1.5)+6)

+ **((x>2.5) AND (x<=3.5))***(((25-3)/(3.5-2.5))*(x-2.5)+3)

This can easily be processed by *pace**val**.* in parallel, i.e. very quickly. The same also works if, for example, other approximations (trigonometric, polynomial or other) are more suitable for your work.

# Further calculation examples with *pace**val**.*

*pace*

*.*

As you can see, *pace**val**.***offers many advantages ** thanks to its readability, high parallelizability, unlimited length of functions or number of variables. Other examples are decision trees with cost per decision and matrix multiplication with variables.

As an example, consider a decision tree with two branches and variables a and b, as shown on the left. You can create a single function for all paths that can be computed by *pace**val**.* depending on the variables a and b. The function can be processed immediately by *pace**val**.*:

f(a, b)=**((a<0) AND (b<30)) *** (2+6) +** ((a<0) AND (b>=30)) *** (2+9)

+ **((a>=0) AND (b<10)) *** (6+1) + **((a>=0) AND (b>=10))** * (6+3)

This is also automatically parallelized internally by paceval. The example can be extended with several branches and variables. Depending on the number of variables, the function becomes longer and longer. If there are values from 20 sensors in a system and each sensor requires two decisions, then there are 2^20= 1,048,576 possible decision paths. If you had to write a program for all of these decision paths, it would be very large and difficult to maintain. It would also be extremely complex and prone to failure when costs change, sensors are added, or decisions need to be made dynamically. *pace**val**.* eliminates all of these problems. In other words: instead of hundreds of thousands or millions of lines of code, *pace**val**.* makes it possible with less than 50 lines.

If you were multiplying two matrices by *pace**val**.*, you would create one calculation object per entry. In the given example there are 9 such objects, which are then calculated with values of the variables x,y,z,u,v and w. You can also extend this example, since the number of objects in *pace**val**.* is unlimited.

These are just two examples. Other examples would be weighted directed graphs, dot products, vector multiplication, hidden Markov model for fast gesture recognition, transformations (DCT, FFT), polynomials, intrinsic values, zero-knowledge-proofs and much more.