This document contains general and reference information to help the user create formulas from data cells coming from modules loaded in the moodss application. Once created, the formulas are displayed in formulas tables, described in the general moodss documentation.

This document particularly covers the mathematical expressions that can be used in formulas, including their syntax and the various available operators and functions.

In moodss and moomps, a formula consists of a user defined name, comments and a mathematical expression made of data cells, mathematical operators and functions. The expression is the core of the formula.

An expression consists of a combination of operands (data cells, numbers, mathematical functions, ...), operators (+, -, ...), and parentheses. White space may be used between the operands and operators and parentheses; it is ignored when the result of the formula is internally calculated.

For example, the screen shot below shows the expression used to calculate the memory usage of a computer in percent, obtained by dividing the used memory by the available memory and multiplying the result by 100.

You may notice that something is wrong with this expression, since its result seems to be **0**, unexpected since there is some actual memory used. What is happening is that the internal calculation engine (called the **calculator** in this document), when possible, interprets the operands as integer values.

What we want in this case is to force floating-point numbers calculations, which can be achieved by using a math function to convert one of the memory operands to floating-point, as shown below.

We will now cover in more details all the available features of expressions.

Where possible, operands are interpreted as integer values (such as **123**), else treated as floating-point numbers (such as **12.345**) if that is possible.

An operand may be directly input as a constant value by the user (such as the **100** multiplier in the screen shots above), or dropped from any source of data cells (such as **used memory** and **available memory**).

Conversion among internal representations for integer and floating-point operands is done automatically as needed. For arithmetic computations, integers are used until some floating-point number is introduced, after which floating-point is used. For example, the result of *5/4* is *1*, while *5/4.0* gives *1.25*.

Floating-point results are always displayed and used with a **.** (dot) or an *e* so that they will not look like integer values. For example, the result of *20.0/5.0* is *4.0*, not *4*.

An operand may also be a mathematical function whose arguments have any of the above forms for operands, such as **double(127544)** (see the functions section).

The valid operators are listed below, grouped in decreasing order of precedence:

**- + ~ !**Unary minus, unary plus, bit-wise NOT, logical NOT. Bit-wise NOT may be applied only to integers.*** / %**Multiply, divide, remainder. Remainder may be applied only to integers. The remainder will always have the same sign as the divisor and an absolute value smaller than the divisor.**+ -**Add and subtract.**<< >>**Left and right shift. Valid for integer operands only. A right shift always propagates the sign bit.**< > <= >=**Boolean less, greater, less than or equal, and greater than or equal. Each operator produces 1 if the condition is true, 0 otherwise.**== !=**Boolean equal and not equal. Each operator produces a zero/one result.**&**Bit-wise AND. Valid for integer operands only.**^**Bit-wise exclusive OR. Valid for integer operands only.**|**Bit-wise OR. Valid for integer operands only.**&&**Logical AND. Produces a 1 result if both operands are non-zero, 0 otherwise. Valid for boolean and numeric (integers or floating-point) operands only.**||**Logical OR. Produces a 0 result if both operands are zero, 1 otherwise. Valid for boolean and numeric (integers or floating-point) operands only.

The following specific functions take strictly one data cell (dragged and dropped in moodss formulas interface) as sole argument. They internally use the value of the data cell at the last update of the formula, which means that they return an undefined value the first time they are invoked, since, obviously, there was no previous value for the data cell.

**delta(***cell***)**Returns the difference between the current value of a data cell and its last value, in*64 bit integer*form. Equivalent to:**wide(***cell***- last(***cell***))**.*Note: handles 64 bit counters that always grow and wrap around:*

wide(1 - 18446744073709551615) = 2**delta32(***cell***)**Returns the difference between the current value of a data cell and its last value, in*32 bit integer*(*always positive*) form. Equivalent to:**(***cell***- last(***cell***)) & 0xFFFFFFFF**.*Note: handles 32 bit counters that always grow and wrap around:*

(1 - 4294967295) & 0xFFFFFFFF = 2, (1 - 2) & 0xFFFFFFFF = 4294967295**diff(***cell***)**Returns the difference between the current value of a data cell and its last value, in*floating point*form, with maximum precision. Equivalent to:**double(***cell***- last(***cell***))**.**last(***cell***)**Returns the value of a data cell at the last update time.

**Notes**:

- Before moodss 21.2 and moomps 5.6,
**delta()**behaved differently on 32 and 64 bit platforms: this has been solved by using either**delta()**or**delta32()**based on the handled data and expected behavior. - A formula is usually updated by the core (moodss or moomps), at the time the dashboard is refreshed, as defined by its poll time. A formula update means the result of the formula is evaluated, using the values of the embedded data cells at the current time, and possibly the values of some of the cells at the time of the last update of the formula (if
**diff()**,**delta()**,**delta32()**or**last()**functions are used). If the formula contains any data cell belonging to an asynchronous module instance, then the formula is updated (or evaluated) at any time the value of a composing asynchronous data cell changes, independently of the dashboard refresh rate (poll time). The value of the last update time (see**diff(time)**) is updated every time the formula is evaluated.

There is also a special specific function which returns the time difference between updates:

**diff(time)**Returns the difference in seconds between the current time and its value at the last update, in**floating point**form. For example, the formula "**diff(***cell***) / diff(time)**" gives the growth rate of a data cell.

The following mathematical functions are also supported in expressions. They work solely with floating-point numbers unless otherwise noted:

**abs(***number***)**Returns the absolute value of*number*.*Number*may be either integer or floating-point, and the result is returned in the same form.**acos(***number***)**Returns the arc cosine of*number*, in the range [*0,PI*] radians.*Number*should be in the range [*-1,1*].**asin(***number***)**Returns the arc sine of*number*, in the range [*-PI/2,PI/2*] radians.*Number*should be in the range [*-1,1*].**atan(***number***)**Returns the arc tangent of*number*, in the range [*-PI/2,PI/2*] radians.**atan2(***y,x***)**Returns the arc tangent of*y/x*, in the range [*-PI,PI*] radians.*x*and*y*cannot both be*0*. If*x*is greater than*0*, this is equivalent to**atan(***y/x***)**.**ceil(***number***)**Returns the smallest integral floating-point value (i.e. with a zero fractional part) not less than*number*.**cos(***number***)**Returns the cosine of*number*, measured in radians.**cosh(***number***)**Returns the hyperbolic cosine of*number*. If the result would cause an overflow, an error is returned.**double(***number***)**If*number*is a floating-point value, returns*number*, otherwise converts*number*to floating-point and returns the converted value.**exp(***number***)**Returns the exponential of*number*, defined as*e*to the power of*number*. If the result would cause an overflow, an error is returned.**floor(***number***)**Returns the largest integral floating-point value (i.e. with a zero fractional part) not greater than*number*.**fmod(***x,y***)**Returns the floating-point remainder of the division of*x*by*y*. If*y*is*0*, an error is returned.**hypot(**x,y**)**Computes the length of the hypotenuse of a right-angled triangle**sqrt(***x*x+y*y***)**.**int(***number***)**If*number*is an integer value of the same width as the machine word, returns*number*, otherwise converts*number*to an integer (of the same size as a machine word, i.e. 32-bits on 32-bit systems, and 64-bits on 64-bit systems) by truncation and returns the converted value.**log(***number***)**Returns the natural logarithm of*number*.*Number*must be a positive value.**log10(***number***)**Returns the base*10*logarithm of*number*.*Number*must be a positive value.**pow(***x,y***)**Computes the value of*x*raised to the power*y*. If*x*is negative,*y*must be an integer value.**round(***number***)**If*number*is an integer value, returns*number*, otherwise converts*number*to integer by rounding and returns the converted value.**sin(***number***)**Returns the sine of*number*, measured in radians.**sinh(***number***)**Returns the hyperbolic sine of*number*. If the result would cause an overflow, an error is returned.**sqrt(***number***)**Returns the square root of*number*.*Number*must be non-negative.**tan(***number***)**Returns the tangent of*number*, measured in radians.**tanh(***number***)**Returns the hyperbolic tangent of*number*.**wide(***number***)**Converts*number*to an integer value at least 64-bits wide (by sign-extension if*number*is a 32-bit number) if it is not one already.

Error handling is handled by the internal calculator, and most messages are easy to understand, but careful reading and thorough thinking is always useful...
**Note**: for experts, it is actually the **expr** command in a safe Tcl interpreter that reports errors.

Some typical error messaged are explained here (*please request new entries as you see fit*):

*syntax error in expression "...": variable references require preceding $*: means that probably some stray alphabet characters or an invalid mathematical function were left in the expression.*syntax error in expression "...": premature end of expression*: a closing parentheses may be missing.

*(to be implemented)*

Operands integer values may be specified in decimal (the normal case), in octal (if the first character of the operand is **0**), or in hexadecimal (if the first two characters of the operand are **0x**).

Floating-point numbers may be specified in any of the ways accepted by an ANSI-compliant C compiler (except that the **f**, **F**, **l**, and **L** suffixes are not permitted). For example, all of the following are valid floating-point numbers: **2.1**, **3.**, **6e4**, **7.91e+16**. If no numeric interpretation is possible, then it is an error and the result of the expression is **?**.

The following operator is also valid:

**x?y:z**if-then-else, as in C. If**x**evaluates to non-zero, then the result is the value of**y**. Otherwise the result is the value of**z**.

The following random functions are also supported in expressions:

**rand(****)**Returns a pseudo-random floating-point value in the range [*0,1*]. Each result from rand completely determines all future results from subsequent calls to rand. The seed of the generator is initialized from the internal clock of the machine or may be set with the**srand**function.**srand(***number***)**The*number*, which must be an integer, is used to reset the seed for the random number generator of rand. Returns the first random number (see**rand**) from that seed.

Finally, for users fluent in the **Tcl** language, you may use all the features of the *expr* command, including strings as operands, as the formula text is directly passed to the **expr** command, after filling the values of the data cells of course.