Skip to content

The q* stdlib docs

qnumber: arbitrary-precision arithmetic

qnumber provides the number.* built-ins: exact, arbitrary-precision arithmetic backed by qvalue's BigDecimal and BigInt. Where math.* is fast f64 that may round, number.* never rounds to a fixed range — it handles any-length integers, exact decimals, and scientific-notation input. Use it for money, very large integers, and any computation where 0.1 + 0.2 must equal exactly 0.3.

What it gives you#

qnumber registers seven public built-ins. Most accept multiple positional arguments and fold over them; div and cmp take exactly two. Results are returned as Decimal values (exact), except cmp which returns an Int.

FunctionArgumentsReturnsBehavior
number.addn valuesDecimalExact sum (starts from 0, folds all args).
number.subn valuesDecimalFirst arg minus each remaining arg, in order.
number.muln valuesDecimalExact product (folds from the first arg).
number.neg1 valueDecimal0 minus the argument (negation).
number.abs1 valueDecimalAbsolute value (negate only when below zero).
number.diva, bDecimala divided by an integer divisor b, to 20 extra digits.
number.cmpa, bInt-1 if a<b, 0 if equal, 1 if a>b.

Input coercion to BigDecimal#

Each argument is read as an exact BigDecimal. Numeric Value types convert directly; a Str is parsed as a decimal (this is how you pass values beyond f64 range and scientific notation). Anything that is neither numeric nor a parseable numeric string becomes 0.

Division rules#

number.div(a, b) requires an INTEGER divisor b. Internally it determines the magnitude and sign of b: if b is a whole number it divides a by that magnitude carrying 20 extra digits of precision, then applies the sign. If b is zero, or not a whole number (it contains a decimal point), the function returns 0 — the caller is expected to validate the divisor. So number.div(1, 8) gives the exact 0.125, but number.div(1, 0) and number.div(1, 2.5) both give 0.

never rounds to a fixed range
Add/sub/mul/neg/abs are exact: adding two 30-digit integers gives the exact 30-digit result, and 0.1 + 0.2 is exactly 0.3.
div precision
Division carries 20 extra digits beyond the operands.
cmp
Uses the value model's compare; non-numbers default to 0 for the comparison.

Resource budget#

Unlike fast f64 math.*, exact number.* allocates arbitrary-precision digit buffers, folds over the arguments, and (for div) carries 20 extra digits — cost is proportional to operand width. Every number.* function declares a 2048-byte (2 KB) memory budget and zero storage.

Examples#

The defining example: exact decimal addition. In f64, 0.1 + 0.2 is 0.30000000000000004; in number.* it is exactly 0.3.

Request

number.add(0.1, 0.2)

# wire form (decimals passed as numeric values):
{ "0": {"Decimal": "0.1"}, "1": {"Decimal": "0.2"} }

Response

{ "result": { "Decimal": "0.3" } }

Output

0.3

Request

number.add("111111111111111111111111111111", "111111111111111111111111111111")
number.div(1, 8)
number.cmp(2, 9)

Response

{ "result": { "Decimal": "222222222222222222222222222222" } }
{ "result": { "Decimal": "0.125" } }
{ "result": { "Int": -1 } }

Output

222222222222222222222222222222
0.125
-1