Math Functions
Every math function returns null on null input. Functions with
a restricted domain (e.g. math.sqrt of a negative number) return
null rather than raising.
Overview
| Goal | Function |
|---|---|
| Absolute value | math.abs(n) |
| Round | math.ceil, math.floor, math.trunc, math.round, math.sign |
| Root, power, log | math.sqrt, math.hypot, math.pow, math.exp, math.log, math.ln, math.log10, math.log_base |
| Bounds and interpolation | math.min, math.max, math.clamp, math.lerp |
| Number formatting and predicates | number.format, number.to_base, number.from_base, number.to_roman, number.from_roman, number.is_integer, number.is_even, number.is_odd, number.is_positive |
| Trig | math.sin, math.cos, math.tan, math.asin, math.acos, math.atan, math.atan2 |
| Unit conversion | math.degrees, math.radians |
| Constants | math.pi(), math.e() |
| Random | math.random() / random() |
| Arithmetic | + - * / % ^ |
Rounding and absolute value
| Function | Behaviour |
|---|---|
math.abs(n) | Absolute value — Int stays Int, Float stays Float |
math.ceil(n) | Round up to the nearest integer |
math.floor(n) | Round down |
math.trunc(n) | Drop the fractional part, toward zero |
math.round(n[, digits[, mode]]) | Round to nearest; default mode is half_up |
math.sign(n) | -1, 0, or 1 |
RETURN math.abs(-3.5); // 3.5
RETURN math.ceil(3.1); // 4
RETURN math.floor(3.9); // 3
RETURN math.trunc(-3.9); // -3
RETURN math.round(3.5); // 4
RETURN math.round(2.5); // 3 (default half-up rounding)
RETURN math.sign(-9); // -1
RETURN math.sign(0); // 0
RETURN math.sign(9) // 1Rounding modes
math.round(n) defaults to half-up rounding and returns an integer.
Pass digits to round to a decimal place. Pass a mode string to choose
another strategy: 'half_up', 'half_even', 'ceil', 'floor', or
'trunc'.
RETURN math.round(3.14159, 2); // 3.14
RETURN math.round(2.5); // 3
RETURN math.round(2.5, 0, 'half_even') // 2.0Roots, powers, logs
| Function | Domain | Returns |
|---|---|---|
math.sqrt(n) | n ≥ 0 | Float; null on negative input |
math.hypot(a, b) | numeric inputs | sqrt(a² + b²) without intermediate overflow |
math.pow(a, b) | numeric inputs | a raised to b |
math.log(n) / math.ln(n) | n > 0 | Natural log; null out of domain |
math.log10(n) | n > 0 | Base-10 log; null out of domain |
math.log_base(n, base) | n > 0, base > 0, base != 1 | Logarithm in an arbitrary base |
math.exp(n) | any | e^n |
RETURN math.sqrt(16); // 4.0
RETURN math.hypot(3, 4); // 5.0
RETURN math.pow(2, 10); // 1024.0
RETURN math.sqrt(-1); // null
RETURN math.log(math.e()); // 1.0
RETURN math.log10(1000); // 3.0
RETURN math.log_base(8, 2); // 3.0
RETURN math.exp(1) // 2.7182818…Hypotenuse
WITH 3 AS a, 4 AS b
RETURN math.hypot(a, b) // 5.0For 2D Cartesian points, geo.distance does this.
Bounds and Interpolation
math.min(a, b, ...) and math.max(a, b, ...) compare numeric
arguments inside a single row. They are scalar helpers, not aggregate
functions. Use min(expr) and max(expr)
when you need the smallest or largest value across rows in a group.
All arguments must be finite numbers. A null, string, map, list, or
non-finite float returns null.
RETURN math.min(3, 1, 2); // 1
RETURN math.max(3, 1, 2); // 3
RETURN math.min(3, 1.5, 2); // 1.5
RETURN math.max(3, null); // null
RETURN math.clamp(125, 0, 100); // 100
RETURN math.lerp(10, 20, 0.25) // 12.5math.clamp(x, lo, hi) constrains a value to an inclusive range.
math.lerp(a, b, t) returns a + (b - a) * t, which is useful for
normalising scores and building weighted formulas.
Number Formatting And Predicates
The number.* namespace contains numeric presentation helpers and
integer predicates. Base conversion supports radices from 2 through 36.
Invalid digits, unsupported bases, and overflow return null.
RETURN number.format(12345.678, 2, ','); // '12,345.68'
RETURN number.to_base(255, 16); // 'ff'
RETURN number.from_base('ff', 16); // 255
RETURN number.to_roman(1994); // 'MCMXCIV'
RETURN number.from_roman('MCMXCIV') // 1994Predicates are intentionally type-aware:
RETURN number.is_integer(42); // true
RETURN number.is_integer(42.5); // false
RETURN number.is_even(42); // true
RETURN number.is_odd(42); // false
RETURN number.is_even(42.0); // null
RETURN number.is_positive(0.1); // true
RETURN number.is_negative(-1); // true
RETURN number.is_zero(0.0); // true
RETURN number.is_nan(0.0 / 0.0) // truenumber.is_even and number.is_odd accept integer values. Use
number.is_integer first when data may arrive as floats. Sign
predicates accept both integers and floats.
Trigonometry
All angles are in radians. Domain violations (e.g. math.asin(2))
return null rather than raising.
| Function | Notes |
|---|---|
math.sin(x), math.cos(x), math.tan(x) | Standard trig |
math.asin(x), math.acos(x), math.atan(x) | Inverse trig; domain [-1, 1] for asin/acos |
math.atan2(y, x) | Two-argument arctangent — y first |
math.degrees(r) / math.radians(d) | Unit conversion |
RETURN math.sin(math.pi() / 2); // 1.0
RETURN math.cos(0); // 1.0
RETURN math.tan(math.pi() / 4); // 0.9999… (float rounding)
RETURN math.asin(1); // 1.5707… (π/2)
RETURN math.asin(2); // null (out of domain)
RETURN math.atan2(1, 1); // 0.7853… (π/4)
RETURN math.degrees(math.pi()); // 180.0
RETURN math.radians(180) // 3.1415…Work in degrees
Most geometry inputs are degrees — wrap every trig call:
WITH 30 AS deg
RETURN math.sin(math.radians(deg)),
math.cos(math.radians(deg))Bearing between two points
WITH 4.89 AS lon1, 52.37 AS lat1,
4.40 AS lon2, 51.00 AS lat2
WITH math.radians(lat1) AS phi1, math.radians(lat2) AS phi2,
math.radians(lon2 - lon1) AS d_lambda
RETURN (math.degrees(math.atan2(
math.sin(d_lambda) * math.cos(phi2),
math.cos(phi1) * math.sin(phi2) - math.sin(phi1) * math.cos(phi2) * math.cos(d_lambda)
)) + 360) % 360 AS bearingApproximation — use geo.distance for real geodesic
distance between WGS-84 points.
Constants
RETURN math.pi(); // 3.14159…
RETURN math.e() // 2.71828…Random
math.random() returns a Float in [0, 1). The bare
random() form is an alias for the same function.
RETURN math.random(); // e.g. 0.42389…
RETURN math.random() * 100; // a Float in [0, 100)
RETURN toInteger(math.random() * 100) // an Int in [0, 99]Not cryptographically secure — seeded from system-time nanoseconds. Do not use for key generation or sampling that must be unpredictable.
Random sample
Each row gets its own math.random() value:
MATCH (u:User)
RETURN u
ORDER BY math.random()
LIMIT 100Weighted pick
MATCH (p:Prize)
WITH p, math.random() * p.weight AS score
ORDER BY score DESC
LIMIT 1
RETURN pArithmetic operators
| Op | Example | Notes |
|---|---|---|
+ | a + b | Also concatenates strings and lists |
- | a - b | Unary -x allowed |
* | a * b | |
/ | a / b | Two integers divide as integers, truncating toward zero; a Float operand gives a Float. Integer divide by zero fails the query; float divide by zero → null |
% | a % b | Remainder, signed like the dividend; a Float operand gives a Float. Integer mod by zero fails the query; float mod by zero → null |
^ | a ^ b | Exponent; an integral result that fits in Int comes back as Int |
RETURN 10 / 3; // 3 (integer division)
RETURN 10 / 4.0; // 2.5
RETURN 10 % 3; // 1
RETURN 7.5 % 2; // 1.5
RETURN 2 ^ 10; // 1024
RETURN 1 / 0 // error: integer division by zero+, -, *, /, % and unary - on integers are overflow-checked: a
result outside the 64-bit range fails the query instead of wrapping.
See Integer overflow.
Mixed-type arithmetic
RETURN 1 + 2.5; // 3.5 (Float)
RETURN 10 / 3.0 // 3.333…Any Float operand promotes the result to Float. For an exact
quotient of two integers, make one of them a float:
RETURN toFloat(10) / 3 // 3.333…Numeric precedence
Unary -/+ binds tightest, then ^, then * / / / %, then
binary + / -, then comparisons. Use parentheses freely.
RETURN 1 + 2 * 3; // 7
RETURN (1 + 2) * 3; // 9
RETURN -2 ^ 2; // 4 (binds as (-2)^2)
RETURN -(2 ^ 2) // -4Common patterns
Clamp a value
WITH $raw AS raw, 0 AS lo, 100 AS hi
RETURN math.clamp(raw, lo, hi) AS clampedNormalise to 0..1
MATCH (m:Metric)
WITH min(m.value) AS lo, max(m.value) AS hi
MATCH (m:Metric)
RETURN m.id,
(m.value - lo) / (hi - lo) AS normalisedBucket a number
MATCH (p:Product)
RETURN (p.price / 10) * 10 AS bucket, count(*) AS n
ORDER BY bucketLog-scale bucket
MATCH (p:Post)
WITH p, CASE WHEN p.views > 0 THEN toInteger(math.log10(p.views)) ELSE 0 END AS decade
RETURN decade, count(*) AS posts
ORDER BY decadeExponential decay (recency score)
MATCH (p:Post)
WITH p, temporal.between(p.published_at, temporal.now()).days AS age
RETURN p.id, p.title,
p.views * math.exp(-age * 0.05) AS score
ORDER BY score DESC
LIMIT 20Half-life of roughly 14 days at 0.05 — tune the constant to taste.
Percent change
MATCH (m:Metric)
RETURN m.id,
m.current,
m.previous,
CASE
WHEN m.previous = 0 OR m.previous IS NULL THEN null
ELSE (m.current - m.previous) * 100.0 / m.previous
END AS pct_changeGuard against zero/null — see
CASE.
Weighted average
MATCH (r:Review)
RETURN toFloat(sum(r.stars * r.weight)) / sum(r.weight) AS weighted_meanEdge cases
Integer overflow
Integer +, -, *, /, % and unary - are checked, and so are
list.sum, list.product and list.scan. A result outside
the i64 range fails the query with a LORA_VALIDATION error such as
integer addition overflowed — it never wraps or panics:
RETURN 9223372036854775807 + 1
// error: integer addition overflowedFor potentially huge inputs, coerce to Float with
toFloat first.
NaN / Infinity
Float division by zero never produces Infinity or NaN — it returns
null (integer division by zero fails the query). Math functions guard
their domains the same way.
RETURN 1.0 / 0.0; // null
RETURN 0.0 / 0.0; // null
RETURN math.sqrt(-1) // null (Cypher-level domain guard, not NaN)If a NaN value does reach a query, IEEE 754 applies: NaN is neither less than nor greater than any
value, and NaN == NaN is false.
Integer division truncates
RETURN 7 / 2; // 3
RETURN -7 / 2; // -3
RETURN 7 / 2.0 // 3.5Make one operand a float (toFloat) when you want the exact quotient.
Limitations
- Integer
+,-,*,%and unary-fail the query on overflow instead of wrapping. Coerce toFloatwithtoFloaton potentially huge inputs.list.sumover integers is not overflow-checked. NaNandInfinityfollow IEEE 754 —NaN == NaNevaluates tofalse, andNaNis neither less nor greater than any other value.math.random()/random()is not cryptographically secure.
See also
- Scalars → Integer / Float — numeric types.
- WHERE — arithmetic in filters.
- Spatial Functions —
geo.distanceas the geodesic alternative. - Aggregation Functions —
sum,avg, percentiles.