Math Instructions
Perform arithmetic on two numeric sources and write the result to a destination tag. Math instructions act like coils — place them on the right side of a rung.
rungs.dev models its math behavior on Studio 5000 Logix Designer® — division, rounding, and type coercion follow the same conventions. Rare edge cases may differ.
Available Math Instructions
| Instruction | Symbol | Purpose |
|---|---|---|
ADD | ADD Source A sourceA Source B sourceB Dest dest | Writes sourceA + sourceB into the destination tag. |
SUB | SUB Source A sourceA Source B sourceB Dest dest | Writes sourceA − sourceB into the destination tag. |
MUL | MUL Source A sourceA Source B sourceB Dest dest | Writes sourceA × sourceB into the destination tag. |
DIV | DIV Source A sourceA Source B sourceB Dest dest | Writes sourceA ÷ sourceB into the destination tag. Behavior depends on operand and destination types — see Division Semantics below. |
Operands
| Name | Type |
|---|---|
sourceA | DINT | REAL |
sourceB | DINT | REAL |
dest | DINT | REAL |
How It Works
When the rung is true, the instruction reads both sources, performs the operation, and writes the result to the destination — once per scan. If the rung stays true, the instruction runs every scan.
Example — Running Total
XIC(PartDetected)ONS(EdgeBit)ADD(TotalParts,1,TotalParts)
Each rising edge of PartDetected adds 1 to TotalParts.
Example — Scale a Reading
Convert a raw ADC value (0–4095) into a percentage (0–100).
MUL(RawValue,100,Scaled);DIV(Scaled,4095,Scaled)
If Scaled is a DINT, the division truncates toward zero — RawValue = 2047 becomes Scaled = 49, not 49.99. Declare Scaled as REAL if you need the fractional precision.
How DIV decides what to give you
DIV is the math instruction that surprises people most often. The result you get depends on the types of the source values and the destination tag.
The simplest example: divide 7 by 2. Mathematically that's 3.5. What DIV writes depends on where it's writing:
| Rung | Result | Why |
|---|---|---|
DIV(7, 2, DintDest) | 3 | All integers, integer destination → truncate to zero |
DIV(7, 2, RealDest) | 3.5 | REAL destination keeps the fraction |
DIV(7.0, 2, DintDest) | 4 | A REAL operand makes it float division (3.5), then banker rounding ties even |
DIV(5.0, 2, DintDest) | 2 | Same — 2.5 rounds to even (2) |
DIV(-7, 2, DintDest) | -3 | Integer division truncates toward zero, not down |
The pattern: if both source operands are DINT and the destination is DINT, you get integer division. Anywhere a REAL shows up — operand or destination — you get float math, possibly followed by banker rounding when the destination is still DINT.
See Arithmetic and Comparison Operators for the full table including banker rounding details.
Division by zero
Dividing by zero is normally an error. DIV handles it without halting the program. What gets written depends on the source operand types and the destination type:
| You wrote | Result |
|---|---|
DIV(5, 0, DintDest) | DintDest = 5 — Source A copied (DINT/DINT) |
DIV(0, 0, DintDest) | DintDest = 0 — Source A copied |
DIV(5.0, 0.0, DintDest) | DintDest = 2147483647 — +Infinity clamps to MAX_DINT |
DIV(-5.0, 0.0, DintDest) | DintDest = -2147483648 — -Infinity clamps to MIN_DINT |
DIV(0.0, 0.0, DintDest) | DintDest = 0 — NaN becomes 0 |
DIV(5.0, 0.0, RealDest) | RealDest = +Infinity |
DIV(0.0, 0.0, RealDest) | RealDest = NaN |
For a DINT destination, all-DINT division copies the left operand (Source A); when any source is REAL, the float result is clamped into the DINT range so an integer tag never holds Infinity. A REAL destination keeps the raw +Infinity, -Infinity, or NaN value. The rung continues in every case.
If you'd rather detect the zero explicitly and do something different, gate the DIV with a compare:
NE(Divisor,0)DIV(Numerator,Divisor,Result)
Common Mistakes
- Running an
ADDaccumulator without anONS— the value runs away as it adds every scan. - Expecting
DINT / DINTinto aDINTdestination to round — it truncates toward zero. Use aREALdestination, or aREALoperand, to keep the fraction. - Assuming
DIVby zero raises a fault —DINTdestinations receive Source A,REALdestinations receiveInfinity/NaN. - Writing the operation the wrong way around — the destination is the last operand.
Related
- MOVE — copy a value without computing
- Compare instructions — act on the result of a calculation
- One Shot — guard per-scan accumulation