User Rating 0.0
Total Usage 0 times
Range: −9007199254740992 to 9007199254740992. Floats are truncated.
Is this tool helpful?

Your feedback helps us improve.

About

Lexicographic ordering treats numeric strings as text. The value 9 sorts after 10 because the character 9 > 1. Key-value stores like LevelDB and JavaScript's native Array.sort() both default to this behavior. Storing raw integers as keys produces silently wrong iteration order - a defect that surfaces only under load and is expensive to debug. This tool implements the lexinum packing scheme: each integer is floored, its absolute value is zero-padded to 16 digits (covering up to 253), and prefixed with P or N. Negative values undergo a nines-complement transformation so that −100 sorts before −1, matching true numeric order. Non-integer floats are truncated. Values outside the safe integer range (±9007199254740992) will produce incorrect results because JavaScript loses precision beyond 253.

lexicographic sort integer encoding sortable string leveldb keys lexinum pack unpack string padding

Formulas

The packing algorithm converts an integer n into a fixed-width string that preserves numeric order under lexicographic comparison.

pack(n) =

{
"P" + pad(n, 16) if n 0"N" + complement(pad(|n|, 16)) if n < 0

Where pad(v, w) left-pads the decimal string of v with zeros to width w = 16 (the digit count of 253 = 9007199254740992).

The nines-complement function replaces each digit d with 9 d. This reverses the sort order within the N-prefixed group so that larger absolute values (more negative numbers) produce lexicographically smaller strings.

complement(s) = s.replace(each digit d, 9 d)

The unpack operation reverses the process: strip the prefix character, apply complement if N, parse to integer, and restore the sign.

Where n = input integer, w = pad width (16), d = individual digit, s = padded digit string.

Reference Data

Integer InputPacked StringSort Position (among examples)
−9007199254740992N00000000000000001 (smallest)
−1000000N89999999990000002
−9999N99999999999900003
−100N99999999999998994
−10N99999999999999895
−1N99999999999999986
0P00000000000000007
1P00000000000000018
10P00000000000000109
100P000000000000010010
9999P000000000000999911
1000000P000000000100000012
9007199254740992P900719925474099213 (largest)
3.14 (float)P0000000000000003 (floored) -
−7.99 (float)N9999999999999992 (floored to −7) -

Frequently Asked Questions

Without complement, the packed string for −1 would be N0000000000000001 and for −100 it would be N0000000000000100. Lexicographically, N...0001 sorts before N...0100, implying −1 < −100, which is numerically wrong. The nines-complement inverts the digit ordering so that −100 maps to N9999999999999899 and −1 maps to N9999999999999998. Now N...9899 sorts before N...9998, correctly placing −100 before −1.
All floats are truncated toward zero using Math.floor(Math.abs(n)). So 3.7 becomes 3 and −2.9 becomes −2 (the absolute value 2.9 is floored to 2, then the negative sign is reapplied). This is by design - the encoding handles integers only.
JavaScript represents all numbers as IEEE 754 double-precision floats. Integer precision is guaranteed only up to 253 (9007199254740992), which is Number.MAX_SAFE_INTEGER &plus; 1. The pad width of 16 digits exactly accommodates this maximum. Integers beyond this range lose precision before they even reach the packing logic, producing silently wrong results.
Yes. A common pattern in LevelDB is to concatenate a namespace string with a separator (such as ! or ~) and the packed integer. For example: user!P0000000000000042. The packed integer portion will sort correctly within each namespace prefix. Ensure your separator character does not collide with N or P in the encoding alphabet.
The bytewise module handles arbitrary types (buffers, arrays, booleans, dates, null) and produces byte-level encodings suitable for complex keyspaces. This lexinum encoding handles only integers and produces human-readable ASCII strings. Choose lexinum when you need debuggable, printable keys and only deal with integer ordering. Choose bytewise when you need to sort heterogeneous types or nested structures.
Zero is always packed as positive: P0000000000000000. There is no N0000000000000000 for negative zero. JavaScript's −0 is treated as 0 because Math.abs(−0) &equals; 0 and the sign check (n < 0) returns FALSE for −0.