Topic: DMD0085

Help File Version: 2.10.0.636

MATH - Calculate Expression


The Calculate Expression (MATH) instruction is used to perform complex mathematical calculations, using a format similar to that used in a spreadsheet or common programming languages. Each expression can be nested or chained to generate simple to complex expressions. Parentheses can be nested up to 8 levels deep.

 

After entering the contents of the expression, click OK to save the contents and close the editor, click Cancel to close the editor without saving the changes, or click Expression Help to open the Help topic for all of the math operators and functions that can be used in an expression.

 


C/C++ rules (not PEMDAS) are used to solve the math expression. Liberal use of parentheses to remove any ambiguity in the processing order is encouraged.

 

The precedence rule order used is as follows:

Unary Operator Group (-)

Exponential Group (**)

Multiply Group (* / %)

Add Group (+ -)

Shift Op Group (<< >> >>>)

Inequality Group (< > <= >=)

Equality Group (== !=)

& (Bit-wise AND)

^ (Bit-wise XOR)

| (Bit-wise OR)

&& (logical AND)

|| (logical OR)

 

Note: parentheses will be added by the editor when saving mixed-operator math expressions. If the expression that is saved by the editor is NOT what is expected, reopen the editor and manually add the parentheses required to get the desired expression.

Math Promotion / Demotion

The Do-more CPU is natively a 32-bit processor. Although many different data formats and sizes are supported, whenever an instruction must do a calculation with a PLC element that is NOT a 32-bit value, that value gets " promoted". This means that whenever elements that are UNSIGNED BYTE, SIGNED BYTE, UNSIGNED WORD, or SIGNED WORD are used in a math calculation, they are processed natively as 32 bit signed integer. All of these data types easily fit and all of their values are supported as native 32 bit signed integers.

 

Most mathematical calculations that take integers for their inputs will also return an integer. For example, when dividing two integers, the CPU performs integer division, not floating point division, meaning that integer 5 divided by integer 2 is integer 2, not the Real value 2.5.

 

However, if a real value is ever part of a mathematical calculation, as soon as the real value is introduced into the calculation, the math processor starts performing floating point calculations on ALL operations going forward. This will include automatically promoting any intermediate integer values to their floating point equivalent. For example, the equation (5 + 2) / 2.0 will calculate 5 + 2 as integer and the intermediate result will be integer 7, but when the integer 7 is divided by the floating point value 2.0, the math processor performs a floating point divide operation, which will promote the integer 7 to 7.0, and the result will be the real value of 3.5.

 

There is an exception to this rule that involves the math calculation processing a math function that returns an integer value, like TRUNC() or ROUND(). If the math processor was processing real operations, then processing any of the math functions that return an integer will return the math processor to using integer math going forward.

 

The most common mistake occurs when dividing two integer values but the desired result is a fractional real result. Use the TOREAL() function to promote an integer value or integer expression to its real equivalent. For example, if you want to divide D10 by D11, and get a fractional floating point result, either of the following will give the desired result:

 

  • TOREAL(D10) / D11
     

  • D10 / TOREAL(D11)
     

  • TOREAL(D10) / TOREAL(D11)

 

The thing to remember is that when a calculation involves both integer and floating point types, the integer types will be automatically promoted to floating point values so that the calculation can be performed using all floating point types. Floating point types are automatically truncated to integers when the program expects an integer value, for example, when a floating point variable is assigned to an integer variable.

 

When assigning an integer or real value to a Bit element, integer and real values of zero / non-zero are evaluated as OFF / ON for the Bit.

 

All error conditions that arise while calculating an expression will be reported on the System Status page of the System Information dialog, and an appropriate system-level Bit location ($IndexError, $OutOfRange, $Overflow, $DivedByZero, etc.) will also be set ON.

Math Execution Speed

Integer math is FAST, and Integer math is ACCURATE. Do-more CPUs have 32 bits of integer accuracy, which is +/- 2 billion. If a million BYTE values of 255 are added together and the result (255,000,000 will fit in a 32-bit D location.

 

Floating point math is SLOWER (not SLOW, just SLOWER). It has 24 bits of ”accuracy” (7 bits for exponent, 1 bit for sign, for all 32 bits). For example, an attempt to add 1,000,000 (one million) to .0000001 (one millionth), will not result in 1,000,000.0000001, because a single REAL cannot hold THAT much accuracy in 32 bits. Real locations have the ability to store a large range of possible values within one 32 bit register, from very small to very large numbers (e.g. 0.0000001 and 1,000,000 or even 6.02 x 1023). There is a loss of accuracy, e.g. you cannot store EXACTLY 3.3, and you can’t add really large and really small numbers together and retain all of the accuracy of both numbers.

 

A single MATH box allows the programmer to freely mix REAL and integers, so the questions arise: when is accuracy lost? When is speed lost?

 

The Do-more CPU will attempt to use integer math for all computations because it is fast and accurate. But when a REAL value is introduced, from that point forward, the remaining calculations will all be done in REAL. This is a bit of an oversimplification, because, when you have sub-expressions, each sub-expression obeys this rule, not just left-to-right at the ASCII expression level).

 

Here's an example: the calculation (CT0.Acc + CT1.Acc + CT2.Acc) / 3 is performed using all integer math. The calculation result is integer. Integer division is one case where you do lose accuracy; it TRUNCATES. 1 / 3 is 0. 2 / 3 is 0. 3 / 3 is 1. 4 / 3 is 1. However, remember that the calculation will start using FLOATING POINT MATH for all subsequent calculations once it is introduced.

 

If the alter the calculation to (CT0.Acc + CT1.Acc + CT2.Acc) / 3.0, Integer math is used on the on the 3 counter accumulators in the numerator (which is great for speed and accuracy), but the division is done with the REAL value 3.0, not the INTEGER value 3.

 

When the division is done with a REAL the calculation is performed as a floating point operation. This will produce the desired result as long as that result is stored in a REAL memory location.

 

What if the denominator is a non-REAL memory location, like V? For example: (CT0.Acc + CT1.Acc + CT2.Acc) / V10. Since V memory locations contain integer values, and the desired result is a REAL, the value in the V location must be converted to REAL value. Note: in this case do not use casts, for example: do not use V10:R. Casting is for reinterpreting the bit pattern, not for data conversions.

 

The MATH function called TOREAL() will perform the needed conversion. It takes the expression that is in parentheses and converts it TO REAL. If the expression is an integer, it converts it to a REAL. If the expression is already a REAL value, it doesn’t do anything.

 

If V10 contains the integer value 3 then (CT0.Acc + CT1.Acc + CT2.Acc) / TOREAL(V10) would generate the desired result.

 

Alternatively, TOREAL(CT0.Acc + CT1.Acc + CT2.Acc) / V10 would give the same result, but floating point calculations would be performed for the entire calculation instead of just the division.

 

The rule of thumb is to do integer math as long as possible when you know you will not lose accuracy. Addition and subtraction are always good for integers. Multiplication and division are usually good with integers, but multiplying two large 32 bit numbers that will exceed 32 bits won’t work, the multiplication must be done as floating point. Division is good with integers when decimal point accuracy is not needed.

 


Parameters:

Note: Use the F9 key or click the 'three dot box' at the right edge of the parameter field to open the Default Element Selection Tool (the Element Picker or the Element Browser) or use the Down-Arrow key (Auto-Complete) on any parameter field to see a complete list of the memory locations that are valid for that parameter of the instruction.

 

Result is a location to store the result of the math computation. This can be any writable numeric location or an array reference.

Note: as of Do-more Technology Version 1.4, if the result is an array reference, the array index can be a full expression, e.g. D[V10 +32] .

Expression contains the memory locations, mathematical operators, and / or math functions from the following tables that make up the formula to calculate. This can be any valid combination of constant values, bit or numeric memory locations, math operators, nested parentheses, and math functions up to a maximum of 1024 characters. Expressions can be nested up to 8 levels deep and chained between operators within function parameters, and as array indices, so use of parentheses is recommended to ensure proper evaluation order.


Arithmetic Operators

Description

Example

+

Add

D0 + D1

-

Subtract

D0 - D1

*

Multiply

D0 * D1

/

Divide

D0 / D1

%

Modulus / Remainder

D0 % D1

**

Raise to a Power

D0 ** D1

-

Negate

-D0

 

Binary / Bit-wise Operators

Description

Example

&

Bit-wise AND

D0 & 0x7FFF

|

Bit-wise OR

D0 | 0xFFFF

^

Bit-wise XOR

D0 ^ D1

~

Bit-wise Invert

~D0

<<

Shift Left

D0 << 1

>>

Shift Right

D0 >> 1

>>>

Unsigned Shift Right

D0 >>> 1

 

Logical Operators

Description

Example

<

Less Than

D0 < D1

<=

Less Than or Equal To

D0 <= D1

==

Equal To

D0 == D1

!=

Not Equal To

D0 != D1

>=

Greater Than or Equal To

D0 >= D1

>

Greater Than

D0 > D1

&&

Logical AND

X0 && X1

||

Logical OR

X0 || X1

!

Logical Not

!X0

 

Common Functions

Description

Example

ABS

Absolute Value

ABS(D0)

MAX

Maximum Between Two Expressions

MAX(D0 * D1, V2)

MIN

Minimum Between Two Expressions

MIN(D0 * D1, V2)

 

REAL Functions

Description

Example

CEILING

Adjust Up to Significance

CEILING (R0, 2)

E

Euler's Constant e

E()

FLOOR

Adjust Down to Significance

FLOOR (R0, 2)

FRAC

Fractional Portion of a Real Number

FRAC(R0)

LN

Natural Log

LN(R0)

LOG

Log Base 10

LOG(R0)

MROUND

Round to Multiple

MROUND (R0, 2)

PI

Returns the value of PI (3.14159)

PI()

ROUND

Round Real to Nearest Whole Number

ROUND(R0)

SQRT

Square Root

SQRT(R0)

TOINT

Convert to Integer

TOINT(SQRT(R0))

TOREAL

Convert to Real

TOREAL(D0 + D1)

TRUNC

Truncate Real to a Whole Number

TRUNC(R0)

 

Trigonometric Functions

Description

Example

ACOS

Arccosine in Radians

ACOS(R0)

ASIN

Arcsine in Radians

ASIN(R0)

ATAN

Arctangent in Radians

ATAN(D0)

COS

Cosine of Radian Angle

COS(R0)

DEG

Convert Radians to Degrees

DEG(R0)

RAD

Convert Degrees to Radians

RAD(R0)

SIN

Sine of Radian Angle

SIN(R0)

TAN

Tangent of Radian Angle

TAN(R0)

 

Statistical Functions

Description

Example

AVGR

Average of a Range of Values

AVGR(D0,10)

MAXR

Maximum Value Across a Range of Values

MAXR(D0,10)

MINR

Minimum Values Across a Range of Values

MINR(D0, 10)

RANDINT

Get Random Integer in Range 0 ... 2147483647

RANDINT()

RANDREAL

Get Random Real in Range 0.0 ... 1.0

RANDREAL()

STDEVPR

Population Standard Deviation of a Range

STDEVPR(R20, 8)

STDEVR

Sample Standard Deviation of a Range

STDEVR(R20, 8)

SUMR

Sum of a Range of Values

SUMR(D0,10)

 

Conditional Functions

Description

Example

COUNTIFEQ

Count If Equal to Expression

COUNTIFEQ(42, D0, 10)

COUNTIFNE

Count If Not Equal to Expression

COUNTIFNE(42, D0, 10)

COUNTIFGE

Count If Greater Than or Equal to Expression

COUNTIFGE(42, D0, 10)

COUNTIFGT

Count If Greater Than Expression

COUNTIFGT(42, D0, 10)

COUNTIFLE

Count If Less Than or Equal to Expression

COUNTIFLE(42, D0, 10)

COUNTIFLT

Count If Less Than Expression

COUNTIFLT(42, D0, 10)

IF

If / Else Expression

IF(C7, D0, D1)

SUMIFEQ

Sum if Equal to Expression

SUMIFEQ(42, D0, 10)

SUMIFNE

Sum if Not Equal to Expression

SUMIFNE(42, D0, 10)

SUMIFGE

Sum If Greater Than or Equal to Expression

SUMIFGE(42, D0, 10)

SUMIFGT

Sum if Greater Than Expression

SUMIFGT(42, D0, 10)

SUMIFLE

Sum if Less Than or Equal to Expression

SUMIFLE(42, D0, 10)

SUMIFLT

Sum if Less Than Expression

SUMIFLT(42, D0, 10)

 

Time Functions

Description

Example

NOW

Get Date/Time Stamp as a 32-bit Integer (1970 Epoch)

NOW()

TICKms

Get Millisecond System Timer Value

TICKms()

TICKus

Get Microsecond System Timer Value

TICKus()

 

Memory Functions

Description

Example

REF

Read Value Indirectly

REF(D0, V0)

[ ]

Array Index Expression

D[ (V10 * 16) + V11 ]

 


Rung Example: