PLC Math Instructions: ADD, SUB, MUL, DIV, and CPT Explained
PLC math instructions explained — ADD, SUB, MUL, DIV, MOD, and the compute (CPT) instruction, integer vs float pitfalls, overflow, and ladder examples.
PLC math instructions are the backbone of every calculation a controller performs — from simple tank-level totals to multi-variable PID setpoint conversions. Yet they trip up more engineers than almost any other instruction type, because the rules for integer truncation, division order, and overflow behavior are subtle and platform-specific. This guide walks through every core arithmetic instruction, shows you exactly where precision disappears and why, and gives you tested ladder rung patterns you can adapt today.
PLC Math Basics
A PLC executes math instructions during the output scan — the processor evaluates the rung condition (normally an XIC or always-true rung), performs the operation, and writes the result to a destination tag before moving on. Two things govern every math result:
- Data type of the destination tag. The processor does not automatically promote operands to a wider type. If your destination is
INT(16-bit signed), the result is truncated to fit — silently. - Math status flags. After every math instruction, the processor updates status bits: Carry (C), Overflow (V/OV), Zero (Z), and Sign (S). These sit in the processor status file (Allen-Bradley:
S2:0; Siemens: stored per block in the accumulator flags). If you are not reading them, you may never know a result was clipped.
Understanding these two points before writing a single rung saves hours of late-night troubleshooting.
The Basic Instructions (ADD, SUB, MUL, DIV, MOD, NEG, ABS)
Every IEC 61131-3-compliant PLC supports a standard set of arithmetic instructions. In Allen-Bradley (Logix) ladder, each appears as a box on the rung. Siemens TIA Portal uses equivalent FC blocks or inline Structured Text. The inputs are labeled Source A, Source B, and Dest (destination).
ADD — Addition
|----[ ]----------[ ADD ]----------|
| Start_PB Source A: Tank_Liters |
| Source B: Fill_Liters |
| Dest: Total_Liters|
Adds Source A and Source B, stores the sum in Dest. Simple — until the sum exceeds the destination data type's maximum. For a 16-bit signed INT, that maximum is 32,767. Add 20,000 + 15,000 into an INT destination and you get –30,537 with the Overflow flag set.
Rule: If accumulated values can exceed 32,767, use DINT (32-bit, max 2,147,483,647) or REAL (32-bit float).
SUB — Subtraction
Source A: Setpoint_Temp
Source B: Actual_Temp
Dest: Error_Temp
Subtracts Source B from Source A. Watch the sign: if Actual exceeds Setpoint, Error becomes negative. Make sure your destination tag is a signed type — an unsigned UINT destination wraps around on negative results.
MUL — Multiplication
Multiplication is the instruction most likely to overflow silently. Two INT values multiplied together can produce a result requiring 32 bits.
Source A: RPM_Scaled (INT, max 3,000)
Source B: Gear_Ratio (INT, max 12)
Dest: Output_RPM (INT)
3,000 × 12 = 36,000. That overflows a 16-bit signed INT. Always promote at least one operand or the destination to DINT before multiplying.
DIV — Division
Integer division discards the fractional remainder entirely — it does not round, it truncates toward zero.
Source A: 7 (INT)
Source B: 2 (INT)
Dest: 3 (INT) ← not 3.5
This matters enormously in scaling calculations. See the Integer vs Floating-Point section for the full impact.
MOD — Modulo (Remainder)
MOD returns what DIV discards — the integer remainder after division.
Source A: 17 (INT)
Source B: 5 (INT)
Dest: 2 (INT) ← because 17 = (5 × 3) + 2
Practical uses include batch counting (trigger every N cycles: MOD(Cycle_Count, Batch_Size)), converting a raw second counter into minutes and seconds, and distributing product across lanes.
NEG — Negate
Flips the sign of Source A. Equivalent to multiplying by –1 but faster and cleaner. Useful when subtracting a value that is already computed as a negative error.
ABS — Absolute Value
Returns the magnitude of Source A regardless of sign. Essential for dead-band comparisons:
ABS(Error) < Deadband → inhibit output
The CPT/Compute Instruction (Full Expression)
The Compute (CPT) instruction (Allen-Bradley Logix) lets you write a full mathematical expression in a single rung rather than chaining multiple math boxes. The expression evaluates left-to-right with standard algebraic precedence unless you add parentheses.
|----[ ]----[ CPT ]-------------------------------------|
| Dest: Scaled_EU |
| Expression: |
| (Raw_Input - Raw_Min) * EU_Span / |
| (Raw_Max - Raw_Min) + EU_Min |
This is the canonical analog scaling formula — the same one used in PLC analog input scaling. Written as five separate math boxes it requires five tags and five rungs; the CPT collapses it to one.
Key CPT rules:
- The CPT destination data type governs the final result type, but the expression evaluates internally at the widest type used — mix a
REALoperand and the entire expression promotes toREAL. - Parentheses are fully supported and strongly recommended.
- Division-before-multiplication pitfalls still apply if all operands are integers — see the next section.
- Siemens TIA Portal has no direct CPT equivalent; use an inline Structured Text assignment instead (see Structured Text programming guide).
Integer vs Floating-Point (Truncation, Division Order Pitfalls)
This is the section that saves production lines.
The Classic Integer Division Pitfall
Suppose you need to convert a raw 0–4095 ADC count to 0–100% and you write:
CPT Expression: Raw_Count / 4095 * 100
With integer operands, this evaluates left-to-right:
Raw_Count / 4095→ truncates to 0 for any Raw_Count below 40950 * 100→ 0
Your scaling output is 0% for the entire range except exactly full-scale. The fix is to multiply before dividing:
CPT Expression: Raw_Count * 100 / 4095
Now step 1 produces a number up to 409,500, and step 2 performs a meaningful division. The result is still an integer (no decimal places), but the error is at most ±1 count rather than losing the entire value.
The golden rule: in integer math, multiply before dividing.
Doing It Right with REAL
For any measurement that needs decimal precision, declare your destination tag as REAL and cast at least one operand:
CPT Expression: REAL(Raw_Count) / 4095.0 * 100.0
The REAL() conversion instruction promotes Raw_Count to a 32-bit float. The division now yields a true fractional result. The destination Scaled_EU receives a value like 73.486...
REAL limitations to know:
REALuses IEEE 754 single precision: 7 significant decimal digits. For values above ~10,000,000 with decimal fractions, precision degrades.- Never compare
REALvalues with equal-to (EQU) — use a dead-band (ABS(A - B) < Tolerance). - Conversion from
REALback toDINTtruncates, not rounds. Add 0.5 before converting if you need rounding:TRUNC(Value + 0.5).
Overflow and Math Status Flags
Every arithmetic instruction sets processor status bits on completion. In Allen-Bradley ControlLogix, these are in the Math Status Flags area of the GSV instruction or accessible via the Controller Status file. In RSLogix 5/500 (SLC/MicroLogix), they live in S2:0.
| Flag | Name | Set when |
|---|---|---|
| S | Sign | Result is negative |
| Z | Zero | Result is exactly zero |
| V / OV | Overflow | Result exceeds destination range |
| C | Carry | Unsigned overflow (carry out of MSB) |
How to use them in ladder:
|----[ ADD ]----[ OSR ]----[ SET ]------|
| OV_Flag Math_Alarm |
Read the Overflow flag immediately after the math instruction using a One-Shot Rising (OSR) to latch a Math_Alarm bit. This prevents silent data corruption from propagating to downstream logic.
Siemens S7: the ENO (Enable Out) output of a math block goes low on overflow or divide-by-zero. Wire it to a fault coil or use #RET_VAL for structured error handling in function blocks.
Order of Operations in CPT Expressions
CPT expressions follow standard algebraic precedence — but knowing the exact order prevents surprises:
- Parentheses — evaluated innermost first
- Functions —
ABS(),SQRT(),SIN(),LN(), etc. - Unary negation —
-x - Exponentiation —
**orXPY - Multiplication, Division, Modulo — left to right
- Addition, Subtraction — left to right
When in doubt, use parentheses. A rung that reads (A + B) * C / D is unambiguous; A + B * C / D may not do what you expect.
Common mistake:
CPT: Average = A + B / 2 ← computes A + (B/2)
CPT: Average = (A + B) / 2 ← correct
Worked Examples
Example 1 — Averaging Three Tank Levels
Problem: Average three level transmitter readings (0–100%, stored as REAL) to get a blended fill level.
CPT Dest: Avg_Level_PCT
CPT Expression: (Tank1_PCT + Tank2_PCT + Tank3_PCT) / 3.0
Using 3.0 (a float literal) ensures the division is floating-point even if the source tags were integers. Store result in a REAL destination.
Example 2 — Unit Conversion (PSI to Bar)
Problem: Convert a pressure reading in PSI to Bar for display on an HMI using the European convention.
CPT Dest: Pressure_Bar
CPT Expression: Pressure_PSI * 0.0689476
Keep Pressure_Bar as REAL. If you need one decimal place on the HMI, scale the display in the HMI tag rather than truncating the PLC value — preserve precision at the source.
Example 3 — Analog Scaling (Raw Count to Engineering Units)
This is the most common real-world application of CPT. A 4–20 mA level transmitter wired to a 0–32767 count analog input module needs converting to 0–10.0 metres.
CPT Dest: Level_Metres
CPT Expression: (REAL(Raw_AI) - 6554.0) / (32767.0 - 6554.0) * 10.0
Where 6554 = 20% of 32767 (representing 4 mA). For the full derivation and clamping logic for sensor faults, see the dedicated PLC analog input scaling tutorial.
Example 4 — Batch Counter with MOD
Problem: Signal a batching alarm every 100 cycles without resetting the master counter.
CPT Dest: Batch_Remainder
CPT Expression: MOD(Cycle_Count, 100)
|---[EQU Batch_Remainder = 0]---[OTE Batch_Alarm]---|
When Cycle_Count reaches 100, 200, 300... the remainder is zero and the alarm fires for one scan.
Siemens and Allen-Bradley Platform Notes
Allen-Bradley (Logix 5000 / Studio 5000)
- The six individual instructions (ADD, SUB, MUL, DIV, MOD, NEG) and the CPT instruction are all available in ladder and function block diagram.
- Tag-based addressing: use descriptive tag names (
Motor_Speed_RPM) rather than file addresses. - For REAL math, ensure the destination tag is declared
REALin the tag database — the instruction does not auto-promote. SQRT,SIN,COS,TAN,LOG,LN,DEG,RADare available inside CPT expressions.- Math overflow sets the
Minor Faultbit (Type 4, Code 4) if configured in Controller Properties → Minor Faults.
Allen-Bradley (SLC 500 / MicroLogix)
- Math instructions write to integer files (N7) by default. Use float files (F8) for
REALoperations. CPTis available on SLC 5/03 and higher with OS 302 or later.- The math status flags are in
S2:0bits 0–3 and are reset on every math instruction — read them on the same rung or the next rung immediately.
Siemens TIA Portal (S7-1200 / S7-1500)
- Ladder math blocks are available but most Siemens engineers prefer Structured Text (SCL) for math-heavy code — see Structured Text programming guide.
- Explicit type casting is required:
INT_TO_REAL(),REAL_TO_INT(). - No CPT equivalent; use a single SCL assignment:
Scaled_EU := (REAL(Raw_Input) - Raw_Min) * EU_Span / (Raw_Max - Raw_Min) + EU_Min; - The
ENOoutput of each math block goes low on error (overflow, divide-by-zero). Connect it to a diagnostic bit or use structured error handling.
For a broader comparison of how math fits across all IEC 61131-3 languages, see the PLC programming languages complete guide. For the data types that underpin every math decision — signed/unsigned integers, REAL, DWORD — the PLC data types explained article goes deeper.
Frequently Asked Questions
What are PLC math instructions?
PLC math instructions are ladder logic (or function block) commands that perform arithmetic operations — addition, subtraction, multiplication, division, modulo, negation, and absolute value — on tag values stored in the controller's memory. They execute once per scan when their rung condition is true and write the result to a destination tag.
What is the CPT instruction?
The Compute (CPT) instruction, available in Allen-Bradley Logix platforms, evaluates a full algebraic expression (including nested functions like SQRT or SIN) in a single rung and writes the result to one destination tag. It replaces a chain of individual math boxes and supports standard operator precedence with parentheses.
Why does integer division lose precision?
When both operands and the destination are integer types, the PLC discards the fractional part of the quotient — it does not round. 7 / 2 stores 3, not 3.5. For scaling calculations this can produce zero output across most of the input range if you divide before multiplying. The fix is to multiply before dividing (to keep numbers large) or to cast at least one operand to REAL before dividing.
How do you do math in ladder logic?
Place a math instruction box (ADD, SUB, MUL, DIV, or CPT) on a rung with a controlling contact. Set Source A and Source B to the input tags and Dest to the output tag. Ensure the destination tag's data type is wide enough for the largest possible result. For expressions involving division or fractional results, declare the destination as REAL and cast integer sources using REAL() before the operation.


