Math — ADD / SUB / MUL / DIV / MOD
Reference for Ladder Logic math instructions in rungs.dev — ADD, SUB, MUL, DIV, MOD — performing arithmetic on two sources and writing the result to a destination tag.
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.
Modeled on Studio 5000 Logix Designer
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. |
MOD | MOD Source A sourceA Source B sourceB Dest dest | Writes the remainder of sourceA ÷ sourceB into the destination tag. |
These five combine two sources. The one-input math instructions — ABS, SQRT, and
NEG — have their own page.
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
0
PartDetected
EdgeBit
ADD
Source A
TotalParts
Source B
1
Dest
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).
0
MUL
Source A
RawValue
Source B
100
Dest
Scaled
1
DIV
Source A
Scaled
Source B
4095
Dest
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.
Practice
Try the math in the Scale exercise — convert a raw 4–20 mA signal into an engineering-unit temperature.
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:
0
NE
Source A
Divisor
Source B
0
DIV
Source A
Numerator
Source B
Divisor
Dest
Result
MOD — the remainder
MOD writes what is left over after dividing Source A by Source B. Classic uses: split a
count into full boxes ("144 parts, 12 per box — how many don't fit?"), or make something
happen every Nth part.
0
MOD
Source A
TotalParts
Source B
12
Dest
LeftOver
| Rung | Result | Why |
|---|---|---|
MOD(7, 3, DintDest) | 1 | 7 = 2×3 + 1 |
MOD(-7, 3, DintDest) | -1 | the sign follows Source A (the dividend) |
MOD(7, -3, DintDest) | 1 | same rule — Source B's sign is ignored |
MOD(7.5, 2.0, RealDest) | 1.5 | REAL operands keep the fraction |
MOD(7, 0, DintDest) | 0 | integer MOD by zero writes 0 — unlike DIV, which copies Source A |
MOD(7.5, 0.0, RealDest) | +Infinity | REAL MOD by zero gives Infinity with the sign of Source A |
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
LIMIT — Range Check
LIMIT in rungs.dev passes power when a test value is inside [lowLimit, highLimit]; if lowLimit is greater than highLimit, the bounds reverse to outside-the-band.
ABS / SQRT / NEG — One-Input Math
Reference for the one-input Ladder Logic math instructions in rungs.dev — ABS (absolute value), SQRT (square root), and NEG (negate). Each reads one Source and writes one Dest.