Math Expression (UTK)
One node for every calculation — with image width/height and a few tricks
- a
- b
- c
- INT
- FLOAT
ComfyUI's per-operation math nodes (Add, Multiply, Divide…) are fine until you need something that isn't a single operation - say, a weighted formula for CFG, or a resolution computed from two inputs with a rounding step. Math Expression (UTK) is one text box that does the whole job, from ComfyUI-UniversalToolkit. You type an expression, it evaluates it, and you get both an INT and a FLOAT out. It's the "just give me a calculator" node, and once you use it you'll stop wiring three math nodes in series.
How it works
The expression is parsed with Python's ast module and evaluated through a whitelist of operators - not a raw eval(), which is the difference between "a calculator" and "arbitrary code execution." You get the usual arithmetic (+ - * / // % **), bitwise ops, boolean and/or/not, and comparisons (which return 1 or 0, handy for conditional math). Newlines are collapsed so you can paste a multi-line expression without breaking it.
Beyond the operators there's a function list that makes it genuinely useful:
round(x, dp),ceil(x),floor(x),sqrt(x),int(x)min(...),max(...)- variadicrandomint(min, max),randomchoice(a, b, c, ...)iif(condition, true_val, false_val)- inline if, the one-liner conditional
And the killer feature: if you connect an IMAGE or LATENT into inputs a, b, or c, you can reference a.width and a.height in the expression. That's how you write "canvas width plus a 64px margin" without a size-detection node. Internally it walks the AST, looks up a/b/c, and for images returns the tensor's spatial dims (latents get multiplied by 8 to recover pixel size).
If randomint or randomchoice appears in your expression, the node marks itself as always-changed, so it re-rolls every execution instead of caching. That's a thoughtful detail - otherwise ComfyUI would cache the result and you'd get the same "random" number forever.
Inputs and outputs
expression(STRING, multiline) - the math. Required.a,b,c- optional inputs of any type, mostly useful via.width/.height.
Outputs: INT and FLOAT - the same value in both formats, so you don't need a cast node. It's an output node, so the result also shows in the UI.
Install and gotchas
Install via ComfyUI Manager (search "ComfyUI-UniversalToolkit") or:
cd ComfyUI/custom_nodes
git clone https://github.com/whmc76/ComfyUI-UniversalToolkit
pip install -r requirements.txt
Restart ComfyUI. No models, no keys, stdlib only.
Gotchas: variables other than a/b/c don't exist - if you try x it raises "Name not found." Referencing an image by name without .width/.height errors on purpose ("complex types need to reference their width/height"), so remember the dot-suffix. And comparisons return integers, not booleans - 1 if a>b else 0 is the same as a > b here, so use whichever reads better. If your expression throws, the error message names the exact function or operator, which keeps debugging quick.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| expression | STRING | — | |
| aopt | * | — | |
| bopt | * | — | |
| copt | * | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| INT | INT | — |
| FLOAT | FLOAT | — |