Summary
Under ns.REAL (and ns.FLOAT), numeric substrings are parsed with Python's
float(). Any value larger than the IEEE-754 double maximum (~1.8e308)
overflows to inf. Two distinct, clearly-ordered values that both overflow
therefore compare equal, and natsorted cannot order them — the output
depends on input order (sort stability), not on the actual numeric magnitude.
Reproduction
>>> from natsort import natsorted, ns
>>> natsorted(["1e400", "1e500"], alg=ns.REAL)
['1e400', '1e500']
>>> natsorted(["1e500", "1e400"], alg=ns.REAL)
['1e500', '1e400']
Both calls "succeed", but the two results disagree about whether 1e400 or
1e500 is larger — because both parsed to inf:
>>> from natsort import natsort_keygen
>>> k = natsort_keygen(alg=ns.REAL)
>>> k("1e400"), k("1e500")
(('', inf), ('', inf))
Mathematically 1e500 > 1e400, but the sort treats them as equal.
Why this matters
The failure is silent — no exception, no warning — and the incorrect order is
plausible-looking. Any dataset containing very large numeric tokens (scientific
data, identifiers with large exponents, synthetic stress inputs) can be sorted
incorrectly with no indication that anything went wrong.
Suggested fix
Two reasonable options:
-
Document the limit. Note in the ns.REAL/ns.FLOAT docs that values are
limited to IEEE-754 double range and overflow to inf, collapsing order.
-
Parse to an arbitrary-precision type when overflow is detected. When
float() yields inf but the source string is finite, fall back to
decimal.Decimal (or compare the normalized string form) so ordering is
preserved. This is heavier but removes the silent-error class entirely.
How this was found
While building and differentially testing a Rust port of natsort. The Rust port
uses f64 and therefore reproduces the exact same behavior (both values become
inf), so this is not a port defect — it is an upstream characteristic that the
differential testing surfaced. Happy to open a PR for the documentation option
if that is preferred.
Environment
- natsort 8.4.0 (latest release on PyPI at time of writing)
- Python 3.12
- Reproducible on a clean install; no other dependencies involved.
Summary
Under
ns.REAL(andns.FLOAT), numeric substrings are parsed with Python'sfloat(). Any value larger than the IEEE-754 double maximum (~1.8e308)overflows to
inf. Two distinct, clearly-ordered values that both overflowtherefore compare equal, and
natsortedcannot order them — the outputdepends on input order (sort stability), not on the actual numeric magnitude.
Reproduction
Both calls "succeed", but the two results disagree about whether
1e400or1e500is larger — because both parsed toinf:Mathematically
1e500 > 1e400, but the sort treats them as equal.Why this matters
The failure is silent — no exception, no warning — and the incorrect order is
plausible-looking. Any dataset containing very large numeric tokens (scientific
data, identifiers with large exponents, synthetic stress inputs) can be sorted
incorrectly with no indication that anything went wrong.
Suggested fix
Two reasonable options:
Document the limit. Note in the
ns.REAL/ns.FLOATdocs that values arelimited to IEEE-754 double range and overflow to
inf, collapsing order.Parse to an arbitrary-precision type when overflow is detected. When
float()yieldsinfbut the source string is finite, fall back todecimal.Decimal(or compare the normalized string form) so ordering ispreserved. This is heavier but removes the silent-error class entirely.
How this was found
While building and differentially testing a Rust port of natsort. The Rust port
uses
f64and therefore reproduces the exact same behavior (both values becomeinf), so this is not a port defect — it is an upstream characteristic that thedifferential testing surfaced. Happy to open a PR for the documentation option
if that is preferred.
Environment