@rbxts/bint
v0.4.0
Published
Arbitrary-precision signed integer library for Luau with operator support, multiple algorithms, and TypeScript typings.
Maintainers
Readme
bint
Arbitrary-precision signed integer library for Luau.
bint stores integers as little-endian base-2^24 limbs, so values can grow without fixed-width overflow. It supports idiomatic operators (+, -, *, //, %, ^, comparisons), plus a lower-level core API with mutating and non-mutating functions.
v0.4.0 adds a tuning API for runtime dispatch control, restructures internals into a clearly-scoped internals export, splits the schoolbook multiplication path for better small-operand performance, retunes dispatch thresholds, and fixes Luau strict-mode operator overloads in TypeScript declarations.
Latest release: 0.4.0.
Features
- Arbitrary-precision signed integers.
- Constructors from Lua numbers, strings (base 2-36), and raw limb arrays.
- Conversion to/from strings and byte strings (little/big endian).
- Floor and truncated division APIs.
- Integer exponentiation and integer square root.
- Multiple multiplication/division algorithms chosen by operand size.
- Luau + TypeScript declaration file support (
src/index.d.ts).
Usage
local mod = require(path.to.bint)
local bint = mod.bint
local core = mod.core
local a = bint("123456789012345678901234567890")
local b = bint.from_int(42)
local sum = a + b
local prod = a * b
local q, r = core.divmod(a, b) -- floor division
print(sum:to_string()) -- method form
print(bint.to_string(prod)) -- function form
print(q, r)bint(v) is an alias for bint.new(v).
For roblox-ts / TypeScript users, the standard non-mutating arithmetic/comparison operations are also available as instance methods (for example a:add(b), a:mul(b), a:divmod(b)), which avoids relying on Luau operator metamethod syntax in typed code. Mutating operations remain on core.
API summary
Constructors
bint.from_int(n: number): Bint(converts the current Luaunumbervalue)bint.from_string(s: string, base?: number): Bintbint.from_limbs(limbs: {number}, signum?: -1 | 0 | 1): Bintbint.zero(): Bintbint.one(): Bintbint.new(v: Bint | number | string): Bintbint(v)(callable module alias)
Conversion helpers
bint.to_string(a: Bint, base?: number): stringbint.to_number(a: Bint): numberbint.to_sci(a: Bint): (number, number)— lossy scientific notation(coefficient, exponent)bint.to_le(a: Bint, trim?: boolean): stringbint.to_be(a: Bint, trim?: boolean): stringbint.from_le(s: string): Bintbint.from_be(s: string): Bint
core operations
core provides low-level signed arithmetic on canonical Bint values. No input coercion or validation is performed — arguments must already be Bint instances. Reach for core when you need mutating operations (_mut variants) or want to avoid repeated allocation; use the bint class for everyday ergonomic use.
- Comparison:
cmp,eq,lt,le - Sign:
abs,abs_mut,neg,neg_mut - Arithmetic:
add,add_mut,sub,sub_mut,mul,mul_mut - Division (floor):
divmod,idiv,mod - Division (truncated):
tdivmod,tdiv,tmod - Other:
pow,sqrt,lshift,rshift,lshift_words,rshift_words
tuning
Runtime control over algorithm dispatch crossover points. All changes take effect immediately and apply to every subsequent operation.
tuning.get_thresholds(): BintThresholds— returns the current configuration.tuning.set_thresholds(config: BintThresholds)— atomically updates all thresholds; rejects missing keys, NaN, and out-of-range values.tuning.reset_thresholds()— restores built-in defaults.
BintThresholds fields (all in limb counts unless noted):
| Field | Default | Description |
|---|---|---|
| mul_split_thr | 33 | max limbs for exact-safe unsplit schoolbook (must be ≤ 33) |
| karatsuba_thr | 44 | min limbs to enter Karatsuba |
| toom3_thr | 145 | min limbs to enter Toom-3 |
| sqrt_kar_thr | — | min limbs to enter Karatsuba sqrt |
| burnikel_dispatch_thr | 98 | min divisor limbs to enter Burnikel-Ziegler |
| burnikel_leaf_thr | 98 | recursion leaf size for Burnikel-Ziegler |
| burnikel_off | 59 | min numerator-denominator limb offset for Burnikel-Ziegler |
Infinity is accepted for karatsuba_thr, toom3_thr, sqrt_kar_thr, burnikel_dispatch_thr, and burnikel_off to disable that tier.
internals (unstable)
Low-level access for benchmarking and testing. Marked @internal — the shape may change between releases without a semver bump.
Operator behavior
Supported metamethods:
+,-,*,//,%,^, unary-==,<,<=tostring(x)andx:to_string()#xreturns decimal digit count of magnitude
/ is intentionally unsupported and throws an error. Use // for integer division.
Semantics and caveats
bint.from_int(n)converts the already-represented Luaunumberexactly; Luau numbers are IEEE-754 doubles, so integer literals above2^53may already be rounded. Usebint.from_string(...)for exact large integer literals.bint.from_string/bint.to_stringsupport bases2..36.core.divmodand//use floor division semantics.core.tdivmoduses truncated (toward zero) semantics.core.rshift(a, n)uses arithmetic (sign-preserving) semantics, equivalent tofloor(a / 2^n).core.lshift_words/core.rshift_wordsare limb-count shifts (base-2^24words), not bit shifts.core.sqrt(a)returns0fora <= 0.bint.to_le/bint.to_beserialize magnitude only (sign is not encoded).bint.to_numberis exact only up to magnitude2^53.bint.to_sciis lossy by design; useful for display/formatting, not exact arithmetic.
Running tests
lune run libs/specs # full suite (all tags)
lune run libs/specs --tag fast # quick local validation
lune run libs/specs --tag full # CI-style: fast + full tests
lune run libs/specs --tag stress # everything including slow/deep checks
lune run libs/specs --list-tags # show available tags and countsChangelog format
This repository uses the Keep a Changelog structure.
