Calculate value
Value resolver – Abstract
Purpose: Performs mathematical operations with numeric values (with and without unit), and usually returns the calculation result as a 'Unit number' as the return value.
The Calculate value value resolver allows mathematical operations with numeric values (with and without unit), and usually returns the calculation result as a 'Unit Number' as the return value.
Exceptions:
The calculation expression is empty or contains syntax errors (e.g. regarding bracket replacement). Then the return value is 'No value' ($null), but no error occurs.
The calculation expression's syntax is correct, but it is not possible to calculate. Then an error occurs at runtime (e.g. ArithmeticException: Division by zero).
In principle, a calculation expression can serve the sole purpose of defining a 'Unit Number' statically (via text entry in the configuration), for example: 7.5t for the definition of a maximum weight of '7.5 tonnes'.
In most cases, however, the calculation links variable input variables that are at least partially provided via variables.
The calculation expression can be constructed from different components:
Type of component |
Syntax/Example |
Description |
Example of expressions |
Result (example) |
Constant numerical values |
<Value>[<Alias of the unit>] or <Alias of the unit>(then 1 is assumed as the value) |
►IMPORTANT◄ Regardless of the settings for the Current locale, the entry of the point as a decimal separator is required. The unit of a constant must appear after it and be identified via the alias from the relevant dynamic enumeration. Spaces between value and unit are optional. |
-1.024 USD (= 1 USD)ft (= 1 ft)m3 (= 1 m3) |
Constant 'Unit number' (UnitNumber), whose 'value' (value) field specifies a signed decimal number and in the optional 'unit' (unit) field refers to one of the configured Units. |
Preset constants |
pi |
Pi π (3.1415926535897932384...) |
radius^2*pi |
Circular area for a circle with the radius defined by the radius variable. |
e |
Euler's number e (2.7182818284590452353...) |
ln(e) |
1 |
|
Automatically preset variables |
input Input value |
By default, the input variable is preassigned with the input value, provided this can be converted into a numerical value. |
input*1.19 |
Calculates a gross amount (with a tax rate of 19%) if the input value (input) is a net amount. |
► NOTE ◄ Data field paths for accessing numerically interpretable field values (e.g. input.numericProperty) are resolved exclusively for the input value (input) so that, for example, several input value fields can be calculated without having to be mapped to individual variables. |
input.end-input.start (input.end-input.start)ms convert((input.end-input.start)ms,H) |
Calculates the time span for an input value of the ‘DateRange’ (DateRange) type in the example on the left in three variants: |
||
► NOTE ◄ For return values of the Relative date with time resolver, the expression for the time span in milliseconds should generally be (1ms+input.end-input.start), as the end value is defined 1ms too early by default. |
||||
entity |
If the reference object in the context of the value resolver is a numerical value (with or without unit) or can be converted into a numerical value, this is available via the variable name entity. |
convert(input,entity) |
Converts the input value into the unit of a 'Unit number', which is available as a reference object. |
|
$index$length |
Current iteration index ($index) and scheduled number of iterations ($length) within a For each loop event action. |
round(($index+1)/$length*100) |
'Progress': Degree of processing with regard to the iterations when executing a loop (in percentage points). |
|
►NOTE◄ Depending on the context (e.g. depending on events or the selection in an overview), further variables can be automatically preset. However, these (like the entity variable) can only be used directly in a calculation expression in exceptional cases, as they mainly contain more complex data objects and not the numerical values expected in the label expression. |
||||
External context variables (storage) of the value resolver |
In principle, any variable names can be used within labelling expressions. However, the restrictions listed on the right must be observed. To prevent variable names such as '17+4' or '2022m3' from being calculated or parsed in the expression, they can be enclosed in single or double inverted commas in the expression. This also allows the use of spaces in the variable name. The escape character (e.g. for inverted commas as text characters) can also be used as a backslash within inverted commas. |
►IMPORTANT◄
|
profit profit2020 profit_2020 "1D"'1D' "2020_profit"'2020_profit' "2020-profit"'2020-profit' "Profit 2020"'Profit 2020' "Inbound/Outbound"'Inbound/Outbound' "Sales 'AOB'"'Sales \'AOB\'' |
If the value of a variable is not a numerical value or a 'Unit number', an attempt is made to interpret its content as a number. The string image is not automatically used for more complex data objects (e.g. values of dynamic enumerations). Only if the variable already contains a string like 1.5e2 as value, this can be read as a numerical value (1500). If the conversion into a numerical value fails, then the value 0 (without unit) is used as the value of the variable instead. |
Specially defined variables for the (inner) context of the value resolver.
|
Within the configuration of the value resolver, any number of explicit value assignments for existing or newly introduced variables (with the specified Variable name) can be added by clicking on the Assignments for the context of the calculation do not change the value of variables already defined in the outer context. They are only temporarily overridden in the inner context, so that the 'outer values' cannot be included in the calculation. |
►IMPORTANT◄
|
►IMPORTANT◄ In order to output the calculation result in days, the conversion via convert(D*24-2.5H,D) cannot simply be used here, because D is temporarily considered as a long value without unit here and not as '1 day'! |
|
The example on the right demonstrates how the alias D (for the Time unit 'day') is temporarily overridden by an assignment for the Variable name D, because in the special context the variable D is supposed to specify a certain 'number of days' (without unit). For a value of D = 1 the calculation expression gives concretely 1*24-2.5H = 22.5 (hours), where the alias H used in the minuend contributes the unit 'hours' for the result value. |
||||
Brackets |
( <Expression> ) |
Pairs of brackets structure aggregates or delimit contained expressions from operators and operands (constants, variables, functions) specifically from each other to explicitly regulate the precedence between operators. |
5+4*3^2 |
149 = 5+(4*3)² |
5+4*(3^2) |
41 = 5+4*(3²) |
|||
(5+4)*3^2 |
729 = (9*3)² |
|||
(5+4)*(3^2) |
8 = 9 * 9 |
|||
8^2/3 |
21,333... = 64/3 |
|||
8^(2/3) |
4 = cbrt(8^2) |
|||
sqrt((width)^2+(width/16*9)^2) |
Diagonal of a 16:9 proportioned rectangle with width according to the width variable. |
|||
Operators |
+ |
Addition or positive sign |
1250kg + 2.5t |
3750kg |
- |
Subtraction or negative sign |
actual - target |
Difference between actual and set point value in one variable each. |
|
* |
Multiplication |
bottomLine * 1.25 |
Markup of 25% on a balance value in the variable bottomLine . |
|
/ |
Division |
profit/capita EUR/CHF |
'Profit per capita'. 'Exchange rate' for Swiss francs (CHF) in the sense of a bulk quotation (with 1 EUR as reference in 'local currency') based on the conversion factors in the enumeration Currency; see also convert()function |
|
% |
Modulo (remainder of the integer division) |
totalPallets % 24 |
Number of pallets for a partial load, if the transport volume specified in the totalPallets variable is to be filled in containers with 24 pallet spaces each. |
|
^ |
Exponentiation |
squaredErrors^0.5 |
Square root ('to the power of 1/2') of the 'sum of squared errors' aggregated in the variable squaredErrors. |
|
Functions |
abs(a) |
Unsigned absolute value (math.: |a|) |
abs(target-actual) |
Absolute amount of the difference between target and actual values in variables. |
sgn(a) |
Signum value: 1 for (a>0), -1 for (a<0), 0 for (a=0) |
sgn(target-actual) |
'Sign value' of the difference between target and actual values in variables. |
|
ceil(a) |
Round up to the next highest integer |
ceil(totalPallets) |
Number of containers required (with 24 pallet spaces each) for the number of pallets specified in the totalPallets variable. |
|
floor(a) |
Round up to the next highest integer |
floor(totalPallets/24) |
Number of completely loaded containers (with 24 pallet spaces each) for the number of pallets specified in the totalPallets variable. |
|
round(a) |
Integer rounding (from 0.5 is rounded up) |
round(profit/capita/1000)*1000 |
'Profit per capita' (from variables) rounded to 1000 currency units. |
|
min(a,b) |
Minimum of two values |
min(actual,estimate) |
The smaller value of two variables for 'actual' and 'estimate' of a quantity. |
|
max(a,b) |
Returns the larger of the two values |
max(actual,estimate) |
The larger value of two variables for 'actual' and 'estimate' of a quantity. |
|
sqrt(a) |
Square root, correspondingly: a^(1/2) |
sqrt(squaredErrors) |
Square root of the 'sum of squared errors' aggregated in the squaredErrors variable. 'Sum of squared errors'. |
|
cbrt(a) |
Cubic root, correspondingly: a^(1/3) |
cbrt(totalVolume*0.75/pi) |
Radius of a sphere with the volume specified in the totalVolume variable. |
|
ln(a) |
Natural logarithm of a |
ln(maxNumber)/ln(2) |
The binary logarithm of the value in the maxNumber variable. |
|
log(a) |
Base 10 logarithm |
log(actual/target) |
The 'order of magnitude' of the deviation between an actual and a target value (in variables) as a signed power of ten (e.g. -1 if the actual value is only one tenth of the target). |
|
convert(a,b) |
Convert value a to the unit of value b |
convert(load,capacity) |
Converts the freight (quantity) in the variable load into the unit of the capacity specification (capacity variable). |
|
convert(totalCost,EUR) |
Converts the total cost in the totalCost variable to the EUR Currency. |
|||
deg(a) |
Convert radian angle a to angular degrees |
deg(atan(-1)) |
-45 (°) |
|
rad(a) |
Convert degree angle a to radians |
sin(rad(30)) |
0.5 |
|
sin(a) |
Sine value for radian angle a |
sin(pi/2) |
1.0 |
|
cos(a) |
Cosine value for radian angle a |
cos(pi/2) |
0.0 |
|
tan(a) |
Tangent for radian angle a |
tan(pi/4) |
1.0 |
|
asin(a) |
Arc sine value (in radians) for a (sine value) |
asin(1)/pi |
0.5 |
|
acos(a) |
Arc cosine value (in radians) for a (cosine value) |
acos(0)/pi |
0.5 |
|
atan(a) |
Arc tangent value (in radians) for a (tangent value) |
deg(atan(1)) |
45 (°)(atan()Supplies radians) |
|
sinh(a) |
Sine hyperbolic value for a |
sinh(0) |
0 |
|
cosh(a) |
Consinus hyperbolic value for a |
cosh(0) |
1 |
|
tanh(a) |
Tangent hyperbolic value for a |
tanh(0) |
0 |
Examples
Calculate a time span in days with decimals
Through Lobster Data Platform / Orchestration server, users can report particular operational incidents (faults, accidents, delays, etc.) by creating an entity of a specially defined type ('event'), classifying the incident by specific characteristics.
When creating the event entity, the system checks when an incident with a similar classification was last reported. If this search returns a match, a message indicates how much time (in days with one decimal) has passed since this incident.
Runtime example:
Configuration:
The event handling shown on the right reacts to the Triggering event (see Common action event) 'Create', which is triggered, among other things, when the user saves an entity in a data input form. In the Validating rule, check type ensures that an entity of the 'Event' type is created. As an Action on passed rule, the Search (Event action) is executed first, which searches for 'comparable' incidents among all events created so far. Details about the criteria for the search are irrelevant for the further workflow.
|
|
On the right are details about the configuration of the Calculate value value resolver:
►NOTE◄ The Timestamp data type cannot be interpreted directly as a numerical value. Otherwise you could access it in the expression via input.created without a diversion via a variable. ►NOTE◄The conversion of the millisecond difference to days relies on conversion rules in the dynamic enumeration Time unit, which are not calendar-specific operations, but only 'mediate' between the time units millisecond (ms) and day (D). Corresponding conversions could also be handled here directly and without conversion by dividing the milliseconds by 86,400,000. That's the number of milliseconds in a day. However, the convert()function makes it comparatively easy to convert the output to other target time units if necessary, by using their alias (such as the H for hours) instead of D. |
|
Calculating the package volume from length x width x height (with variable length unit)
For a package, the dimensions 'length', 'width' and 'height' are available in numerical fields, whose Length unit can be selected by the user – if necessary differently for each dimension.
From this information, the volume of the cuboid idealized package is calculated in a selectable Volume unit within an event handling and written to the Volume variable as a value of the 'Unit number' type.
To specify the desired Volume unit, it is pre-assigned to the Volume variable so that it already contains a value such as '0 liters' or '0 gallons' before the calculation.
Configuration:
The suitably initialized target variable Volume (with the default for the target Volume unit) is at the beginning of a concatenation of value resolvers as shown on the right. For our example, '0 liters' should be preset.
|
|
The screenshot on the right shows how the assignment of the variables for the input data length, width and height was solved in our example for test purposes:
►NOTE◄ The decimal separator ‘comma’ only affects the representation in the input context. 1.2 would have to be written directly in the calculation expression to achieve the same result.
For operational practice, assigning static values for the three variables does not make sense. Assuming that the information for the three dimensions of the package exists, for example, as fields (or attributes) of a common data object, this could be defined as a reference object in the context of the value explorer by an Execute with event action, in order to then access it in the assignments for the length, width , and height variables via the entity variable. For example, in the context of an unspecified entity, accessing an itemLength field for assignment to the length variable would look as follows:
|
|
►NOTE◄ It is not described here how the length, width and height variables – apart from the test with static values – are actually supplied with values.
Typically, Object property resolvers would be used here, which assign suitable values from the external reference object to the variables.
If several values are read from the same reference object and are 'calculated' directly, it would actually make sense to use the reference object as the input value and to address the individual fields in the calculation expression via the input variable.
Configuration variant:
The screenshot on the right shows a value resolver chain that is supplied directly with the data object for the package as an input value (here: as a reference object). The dimensions to be calculated should be available in the ‘length’ (length) , ‘width’ (width) and 'height' (height) fields, each as a ‘Unit number’. The calculation expression is basically structured as described above, but with the following adjustments:
►NOTE◄ The explicit ‘assignment’ of the numerical input values to variables is completely omitted here. However, this access only works as long as the read data is available directly as numerical values (here: with a unit) in the input. ►NOTE◄ A Create instance with values resolver can be added as the start of the value resolver chain for tests, for example, in order to provide a ‘package’ as a client object. |
|
Evaluate the 'range' of the logged-in user account in an association criterion
Users are classified using a 'range' key figure, which is defined as the product of the number of Roles and Company accounts that can be selected at login.
An association criterion should apply if the ‘range’ of a user is at least 3.
Configuration:
In the context of a With rule that defines the evaluated user as a reference object (e.g. the User of session), the criterion shown in the screenshot on the right is checked:
►NOTE◄ The fact that the value in the Object property length here is only based on an internal calculation (for ‘lists’) and not on a persisted database field of the user is irrelevant for access via the data field path. |
|
Calculations with data from a map
Access via data field paths for details from a complex input value is also possible when a map is involved.
For the following example, a map is available in a sales variable, in which sales figures (number of units) for the completed quarters of the current year have been written using systematically named key values (‘Q1’, ‘Q2’, “Q3”, ‘Q4’).
The sum of all quarters for the current status is to be calculated and written to the map as an additional value under the key ‘TOTAL’.
Configuration:
The screenshot on the right shows an Execute with event action whose action block uses the map in the sales Variable as a temporary reference object. Calculation and value assignment can be handled within the same Set value event action:
|
|
Calculations with data from lists
Access to list values via index
If the input value is a list or contains list values, the calculation expression can access individual list values via their absolute index position.
The index always starts at 0.
The first list value of a list of numerical values available as an input value can therefore be addressed as input.0 in the calculation expression.
If a list value is a complex object, the data field path can be continued after the index value in order to further resolve its structure.
The expression input.2.maxCapacity reads the value of the maxCapacity field of an object that is the third entry in the list provided as an input value (if available).
►IMPORTANT◄ In contrast to the context of a form, where the get (Read value from data field) function enables access to list values via a variable index value, this is not possible here. Index values can only be defined statically and absolutely in the calculation expression.
A Custom entity type ‘Aircraft’ (Aircraft) lists areas of an aircraft in the list field, which can be further subdivided via another list field zones.
By convention, each relevant aircraft can be described by a maximum of four loading areas (areas), to each of which 1-2 zones (zones) are assigned.
A ‘load weight’ (weight) can be assigned to each zone via the0 weight field. At the same time, a fictitious ‘lever arm’ (arm) is specified for each zone, which is used to calculate the moment depending on the payload.
Before the aircraft takes off, it must be checked whether the total mass and the total moment are within the permissible operating range, taking into account the actual load and fuelling (here: modelled via the zones).
The following configuration shows how the total torque can be calculated for an Aircraft object defined in an acft variable.
Configuration:
The screenshot on the right shows a value resolver chain (see Chained resolver), which can be used to determine the ‘total moment’, e.g. as a message in a Show alert event action:
|
|
►NOTE◄ This example is intended to show how index access for list values can be performed for calculations with a defined (or at least finite) number of list values. Calculations for lists with variable length always enable a For each loop event action and – in special cases – the execution of a calculation (via value resolver, e.g. Calculate value or Simple calculation (+,-,*,/,%)) in a Collect values resolver.