Skip to content
Classroom

Math Macros

Arithmetic, trigonometry and number theory in question control code.

Several familiar PHP names are not available

Control code runs against a fixed allowlist. pow, asin, acos, atan, deg2rad, rad2deg, log10, factorial and random are not on it — earlier versions of this page documented all nine. The engine's spellings are arcsin / arccos / arctan, and the rest are covered below.

Core math macros load automatically; no loadlibrary call is needed.

Arithmetic

abs($x), round($x, $decimals), floor($x), ceil($x)

$value = abs(-5)              // 5
$rounded = round(3.14159, 2)  // 3.14
$down = floor(3.7)            // 3
$up = ceil(3.2)               // 4

max($a, $b, …), min($a, $b, …)

$largest = max(3, 9, 2)   // 9

mod($p, $n)

Remainder of $p divided by $n, always between 0 and $n - 1 for positive $n (mod(-7, 5) is 3). The % operator also works in control code but keeps the sign of $p (-7 % 5 is -2). Both truncate non-integer operands to integers, and mod($p, 0) returns false.

$remainder = mod(17, 5)   // 2

fmod($a, $b) handles non-integer operands.

Powers and roots

Exponentiation is ^

There is no pow. Write ^, which the interpreter rewrites to safepow:

$square = $x^2
$cube = 2^3        // 8

safepow($base, $exponent)

The same operation as a callable macro. It is "safe" because it handles cases plain exponentiation does not: a negative base with a fractional exponent resolves to the real odd root where one exists, so safepow(-8, 1/3) gives approximately -2 (-1.9999999999999998 — round before comparing) rather than NAN. Conversely 0^0 prints 0^0 is undefined and yields NAN, not the 1 that PHP's own pow returns.

sqrt($x) and root($n, $x)

root takes the degree first:

$hyp = sqrt($a^2 + $b^2)
$cubeRoot = root(3, 27)     // ≈ 3 (2.9999999999999996) — degree first, then the radicand; round before comparing

exp($x), log($x), ln($x), nthlog($base, $x)

ln is the natural logarithm. log is the common (base-10) logarithm: the interpreter rewrites log( to PHP's log10(, so log(100) is 2. The name log10 itself is not allowlisted. For any other base use nthlog, which takes the base first:

$natural = ln($x)
$common = nthlog(10, 1000)   // ≈ 3 (2.9999999999999996) — round before comparing
$binary = nthlog(2, 8)       // 3

Trigonometry

sin($x), cos($x), tan($x), sec($x), csc($x), cot($x)

Arguments are in radians.

$height = 10 * sin(pi/6)

arcsin($x), arccos($x), arctan($x)

Not asin / acos / atan

IMathAS spells the inverse functions arcsin, arccos and arctan. The a-prefixed forms are not macros and fail the question outright. This is the single most common mistake in inherited question code.

$angle = arctan($opposite / $adjacent)

atan2($y, $x) is available, and is the right choice when you need the correct quadrant.

Degrees and radians

There is no deg2rad or rad2deg. Convert with pi:

$radians = $degrees * pi / 180
$degrees = $radians * 180 / pi

sinn($n, $x), cosn($n, $x), tann($n, $x), secn, cscn, cotn

These raise the function to a power — the exponent comes first

sinn(2, $x) is sin²(x), not sin(2x). Reading it the other way round silently produces a plausible wrong answer key.

$sinSquared = sinn(2, $x)

Constants

pi and e are available as bare names — no $ and no parentheses.

$area = pi * $r^2
$growth = e^($k * $t)

Number theory

gcd($a, $b, …) and lcm($a, $b, …)

Both are variadic. gcd also accepts a single array, so it works directly on a generated data set; lcm does not — lcm($numbers) prints an error and returns 1, so pass the values as separate arguments.

$divisor = gcd(12, 18)              // 6
$divisor = gcd(12, 18, 24)          // 6
$divisor = gcd($numbers)            // an array works too
$multiple = lcm(4, 6)               // 12

Non-numeric input prints an error and returns 1.

Factorial is the ! operator

factorial(...) is not allowlisted, so calling it by name fails the question. Write the postfix ! operator instead. The interpreter rewrites $n! to the engine's internal factorial function (!= is not affected).

$n = rand(4, 7)
$ways = $n!
$pairs = $n! / (2! * ($n - 2)!)

sgn($x) / sign($x), is_nicenumber($x)

clamp is not reliably available: it is allowlisted only when the server's PHP has a native clamp (PHP 8.6+), and on PHP 8.5 it fails the question. Use min($max, max($min, $x)) instead.

sgn returns -1, 0 or 1. sign is not an alias: it never returns 0 (sign(0) is 1), and sign($x, true) returns the string "-" or "+". is_nicenumber returns true when a value is numeric and finite (not NAN or INF) — useful as a where guard against impossible values such as the square root of a negative. It does not check that a number is short or easy to type: is_nicenumber(1/3) is true.

$direction = sgn($slope)
$c = rand(-9, 9) where (is_nicenumber(sqrt($c)))

Choosing between values

ifthen($condition, $then, $else)

An inline conditional.

$word = ifthen($slope > 0, "increasing", "decreasing")

cases($value, $inputs, $outputs, $default, $tol)

A lookup table — matches $value against $inputs and returns the matching entry of $outputs, falling back to $default. Numbers match when they are equal within a relative tolerance $tol (default 0.0015; write it as a string with a leading |, such as "|0.01", for an absolute tolerance). The inputs are not thresholds, so cases cannot sort a score into grade bands — use if conditions for that. (Do not name a variable $score: it is reserved, and using it fails the whole control block.)

$n = rand(1, 3)
$word = cases($n, array(1, 2, 3), array("one", "two", "three"), "many")

Working with fractions and expressions

Macro Purpose
decimaltofraction($d, $format, $maxden) convert a decimal to a fraction
evalnumstr($str, $docomplex) evaluate a numeric string
getnumbervalue($a) coerce a value to a number
definefunc($func, $varlist) / evalfunc($farr) build and evaluate a function
normalizefunc($a, $vars) put a function expression in normal form

Display helpers such as makereducedfraction and prettysigfig live on the Format Macros page.

Random numbers

Randomization has its own page. In brief: rand($min, $max) returns an integer, and rrand($min, $max, $step) is how you get decimals. There is no random. See Randomizers.

Examples

A right triangle with a clean answer

$i = rand(0, 3)
$as = array(3, 5, 8, 7)
$bs = array(4, 12, 15, 24)
$a = $as[$i]
$b = $bs[$i]
$c = sqrt($a^2 + $b^2)   // 5, 13, 17 or 25
$angle = round(arctan($a / $b) * 180 / pi, 1)

Reduce a randomly generated fraction

$n = nonzerorand(-20, 20)
$d = nonzerorand(2, 12)
$g = gcd($n, $d)
$rn = $n / $g
$rd = $d / $g

Compound growth

$p = rrand(1000, 5000, 100)
$r = rrand(0.02, 0.08, 0.01)
$t = rand(3, 10)
$amount = round($p * e^($r * $t), 2)

See Also