Appearance
Digit functions
Most rules compare whole numbers. Sometimes you need to talk about the digits inside a number instead: "the leading digit must not be 9", "the result must end in 0", "no digit may be a 5". Five built-in functions cover that.
All five operate on the absolute value of their argument. The sign is ignored, so digits(-47) and digits(47) are identical.
The five functions
| Function | Returns | Example |
|---|---|---|
digits(x) | Array of all digits, most significant first | digits(123) → [1, 2, 3] |
highest_digit(x) | The most significant (leading) digit | highest_digit(123) → 1 |
lowest_digit(x) | The least significant (trailing) digit | lowest_digit(123) → 3 |
number_of_digits(x) | Count of digits | number_of_digits(123) → 3 |
digitAt(x, place) | The digit at the named decimal place | digitAt(123, 10) → 2 |
Four of them take exactly one argument. digitAt takes exactly two. Passing the wrong number of arguments is an error, and so is calling a function with no arguments at all.
Using them
A function call can appear anywhere a number can — on either side of a comparison, inside IN, or as an argument to another function.
highest_digit(prev_sum) < 5 -- leading digit of the running total is under 5
lowest_digit(current_value) = 0 -- candidate must end in 0
number_of_digits(current_sum) <= 2 -- result must be at most two digitsThe argument does not have to be a bare variable. Arithmetic is allowed inside it:
highest_digit(prev_sum + current_value) != 9And the result can be tested with IN / NOT IN just like any other number:
highest_digit(current_value) IN (1, 3, 5, 7, 9) -- leading digit must be odd
lowest_digit(current_sum) NOT IN (0, 5) -- result must not end in 0 or 5digits and quantifiers
digits(x) is the odd one out: it returns an array, not a number, so it is not useful in a plain comparison. Its job is to feed a quantifier, which applies a condition to each digit in turn:
EVERY d IN digits(prev_sum): d < 9 -- no nines anywhere in the running total
SOME d IN digits(current_value): d = 0 -- at least one digit of the candidate is zeroThere is a shorthand for exactly this shape — ALL_DIGITS(x) and SOME_DIGITS(x). Both are covered on the quantifiers page.
Leading digit vs. highest place
highest_digit returns the value of the leading digit, not the place it sits in. For 1234 it returns 1, not 1000. If you want to know which decimal place a step affects, that is place, not a digit function.
Edge cases
These follow from how the functions are implemented, and are worth knowing before a rule surprises you:
| Expression | Result | Why |
|---|---|---|
digits(0) | [0] | Zero has one digit |
number_of_digits(0) | 1 | Same reason |
highest_digit(-70) | 7 | Sign is stripped first |
lowest_digit(-70) | 0 | Sign is stripped first |
digitAt(47, 100) | 0 | Places above the number read as 0 |
digitAt in brief
digitAt(value, place) reads the digit of value sitting at the decimal place you name — 1 for ones, 10 for tens, 100 for hundreds, and so on. Formally it is floor(abs(value) / place) reduced to its last digit.
digitAt(current_value, 10) = 4 -- the tens digit of the candidate is 4
digitAt(prev_sum, 100) IN (0, 5) -- hundreds digit of the running total is 0 or 5Unlike the derived variables place, formula and digitBefore, digitAt works on values that touch several decimal places at once — for current_value = 47 it happily reports 4 at the tens and 7 at the ones. That is its main reason to exist, and it is covered properly on the decimal places page. Read that page before reaching for digitAt: in most rules the derived variables are the shorter and clearer tool.