What a bound is

A limit is not a prediction

Measured from n = 64 to n = 4,096, this site's hybrid merge sort fits a linear class better than n log n. Measured out to n = 65,536, the ranking reverses. Nothing changed but the range — and this is not a flaw in the method, it is the method finding the exact place where measurement stops being able to help.

This site measures operation counts and fits complexity classes to them. It is worth being exact about what that procedure can and cannot establish, because the machinery is persuasive and the persuasion outruns the logic.

A finite set of measurements cannot establish an asymptotic claim. Not with more data points, not with a wider range, not with a better fit. The claim f(n)=Θ(g(n))f(n) = \Theta(g(n)) is about the behaviour of ff as nn \to \infty, and every measurement stops somewhere. Infinitely many functions agree with any finite sample and diverge from each other beyond the last point. Choosing between them is not something the sample can do.

This is not a philosophical quibble to be acknowledged and set aside. On this site it happened, in the ordinary course of building the thing, to an algorithm whose class everybody already knows.

Comparison counts against n, reversed inputMeasured counts on logarithmic axes, where a power law is a straight line and its exponent is the slope. The quadratic algorithms rise at twice the gradient of the linearithmic ones, and the vertical gaps between the parallel lines are the constants the notation discards.10010³10⁴10³10⁴10⁵10⁶ncomparisonsMergeMergea power law is a straight line herecomparisons, counted exactly
Fig. 1 Merge sort with an insertion-sort cutoff, on reversed input, plotted against plain merge sort. Over the left two-thirds of this range the hybrid’s line looks straight with a gradient near 1 — it looks linear. Over the whole range it does not. The two halves of the same plot support different conclusions.

Why no amount of data settles it

The logical point is worth stating carefully, because it is easy to nod at and then forget.

Suppose an algorithm’s counts have been measured at every size up to a million and they fit nlognn \log n beautifully. Consider the function that equals this algorithm’s count everywhere up to a million and equals n2n^2 thereafter. It agrees with every measurement taken. It is a different asymptotic class. No further measurement below a million distinguishes them, and measuring above a million just moves the problem.

That construction is artificial, but the real cases are not. Every algorithm with a threshold in it — a cutoff, a fallback, a precomputation that pays for itself only above some size, a data structure that switches representation when it grows — has exactly this shape, and the threshold is often far above where anyone measures. The insertion-sort cutoff every production sort implements is a threshold of this kind, and it is the reason the hybrid’s counts do what they do above.

There is also a mundane version of the problem that has nothing to do with infinity. Measurements stop somewhere because of resources, and where they stop is decided by the slowest algorithm in the comparison. This site’s fits run from n = 32 to n = 4,096 largely because selection sort at n = 100,000 is five billion comparisons — about a minute of build time for one point on one curve. The range is a budget decision, and budget decisions constrain conclusions.

The case

Merge sort with an insertion-sort cutoff is Θ(nlogn)\Theta(n \log n). This is not in doubt: the recursion is the same as merge sort’s above the cutoff, and below it a bounded amount of insertion sorting happens on each of n/cn/c subarrays, contributing Θ(n)\Theta(n). The sum is Θ(nlogn)\Theta(n \log n) and the proof is two lines.

The site’s algorithm table originally declared exactly that, for all four input kinds. On three of them the fit granted it. On reversed input the fit refused, and the refusal was correct.

Fitted from n = 64 to n = 4,096, the counts on reversed input match:

candidate class spread
nn 1.69
nlognn \log n 1.92

Linear wins. Both are outside the tolerance of 1.6, so neither is granted — but the ranking is unambiguous, and if the tolerance had been 1.75 the site would have confidently labelled a linearithmic algorithm as linear.

Fitted from n = 64 to n = 65,536:

candidate class spread
nn 2.15
nlognn \log n 1.97

The ranking reverses. Nothing about the algorithm changed. Nothing about the measurement method changed. The range changed.

Why it happens

The hybrid’s comparison count on reversed input is a sum of two terms of roughly the shape

anc+bnlog2nca \cdot n \cdot c + b \cdot n \log_2 \frac{n}{c}

where cc is the cutoff. The first term comes from the insertion sorting, the second from the merging. On reversed input the insertion phase is at its worst — a reversed subarray is insertion sort’s catastrophe case, costing c2/2c^2/2 per subarray — so the first term is large. The second is small, because merging two ascending runs where every element of one exceeds every element of the other terminates early.

So below a few thousand elements the linear term dominates, and the total is genuinely close to linear. The logarithmic factor only asserts itself once log2(n/c)\log_2(n/c) has grown enough to matter, which on this data happens somewhere past n = 10,000.

Neither term is an error. The function really does look linear over one range and linearithmic over a wider one, because it is a sum of a linear thing and a linearithmic thing and the crossover is where it is.

What the fit did about it

Refused to grant a class, and stopped.

That is the correct behaviour and it is worth dwelling on what the alternatives would have been. The site could have granted nlognn \log n on the grounds that the proof says so — but then the fit is not testing anything, it is decorating a conclusion arrived at some other way, and it would have granted nlognn \log n to a broken implementation equally happily. It could have granted nn on the grounds that the measurement says so — but the measurement is a measurement over a range, and extending the range changes it.

What it does instead is decline. The algorithm table has no declared class for the hybrid on reversed input. The gate does not test one. An essay says why.

The cost of that is small: one missing label among about forty algorithm-and-input pairs. The benefit is that every other label on the site is a claim the measurements actually support.

The same phenomenon, in a formula

Complexity classes are not the only place where a limit gets mistaken for a prediction, and the clearest example on this site is in a closed form rather than a class.

The expected number of probes to insert a key into a hash table under linear probing, at load factor α\alpha, is

12(1+1(1α)2)\frac{1}{2}\left(1 + \frac{1}{(1-\alpha)^2}\right)

This is Knuth’s result and it is exact — in the limit as the table size goes to infinity. Applied to a table of a particular size it is an approximation, and the error is measurable.

How wrong the asymptotic formula is on a table you would actually allocateThe vertical axis is the measured probe count minus the formula's, as a fraction of the formula's. At a load factor of 0.5 the formula is within 4.2% at every size. At 0.95 a table of 256 slots comes in 48% below it, and the gap closes as the table grows. The formula is not wrong; it is a limit, and a limit is a claim about a sequence rather than a prediction for any member of it.-50%-40%-30%-20%-10%0%10%20%2561,0244,09616,384α = 0.5α = 0.8α = 0.9α = 0.95table size (slots)measured minus formula, relativemean of 6 fills per pointgreen band: within 5% of the formula
Fig. 2 Measured probe counts minus the formula’s prediction, relative, against table size. At a load factor of 0.5 the formula is accurate at every size measured. At 0.95 a table of 256 slots comes in almost half below the prediction, and the gap closes as the table grows. The formula is not wrong; it is a limit, and a limit is a claim about a sequence rather than a value for any member of it.

At α=0.95\alpha = 0.95 and 256 slots, the measured mean is 48% below the formula. At 32,768 slots the discrepancy is a few percent. The condition under which the asymptotic form is trustworthy is roughly m(1α)31m(1-\alpha)^3 \gg 1, and at 256 slots and α=0.95\alpha = 0.95 that product is 0.03 — nowhere near the regime the formula describes.

Somebody sizing a hash table by that formula at high load would over-provision substantially, and would be doing so on the authority of a correct theorem applied outside its range. The essay on the probe formula works through the whole comparison.

What measurement can do

Having established what it cannot do, the positive case is worth stating precisely, because it is not nothing.

Refute. If an algorithm claims Θ(nlogn)\Theta(n \log n) and its counts fit n2n^2 with a spread of 1.03 across three decades, the claim is wrong, or the implementation is wrong, or the input assumption is wrong. One of those, definitely, and finding out which is worth doing. Refutation is logically available to finite evidence in a way that confirmation is not — a single counterexample settles a universal claim, and no quantity of confirming instances settles it the other way. This asymmetry is the whole reason the site’s fitting machinery is worth building.

Measure the constant. The factor the notation discards is a finite quantity and finite measurement is exactly the right tool for it — as is the distance from an algorithm to its floor, which is a ratio between two numbers rather than a claim about a limit. Merge sort’s 0.838 comparisons per nlog2nn \log_2 n is a real number obtained honestly.

Catch the gap between the proof and the code. A proof about a recurrence is about the recurrence. The measurement is of the program that will actually run. Where they diverge — a bug, an accidental copy, a base case firing more often than expected — the measurement notices and the proof does not. This is not a criticism of proofs; it is a description of what they are about.

Show where the asymptotic regime begins. This one is undervalued. Knowing that an algorithm is Θ(nlogn)\Theta(n \log n) is less useful than knowing that its counts do not look linearithmic until n is past ten thousand. That threshold is measurable, it is exactly what asymptotic notation is silent about, and for anyone whose n is small it is the only part that matters.

The floor, computed two waysThe exact bound log₂(n!) summed term by term, Stirling's closed form laid over it, and n log₂ n above both for comparison. The exact sum and the approximation agree to better than one part in a million across this range. The gap to n log₂ n is n log₂ e, about 1.44n, which is why an algorithm at exactly n log₂ n comparisons is not optimal but is within a factor that shrinks towards 1.1010010³10⁴10010³10⁴10⁵ncomparisonsn log₂ nlog₂(n!)Stirlingthe two routes agree to 5.1e-7 relativeexact sum · Stirling
Fig. 3 The other direction: a limit that behaves. log₂(n!) computed exactly by summing logarithms, with Stirling’s closed form laid over it. Here the approximation and the exact value agree to better than one part in a million across the whole range, so using the closed form costs nothing. Whether a limit is a safe substitute for the thing it describes is a question with a measurable answer, and the answer differs from case to case.

What it looks like when the limit behaves

None of this means closed forms and asymptotic classes are unreliable in general. Some of them are extremely well behaved, and the difference between the two situations is itself measurable.

Stirling’s approximation to log2(n!)\log_2(n!) is the good case. The exact value — summed logarithm by logarithm — and the closed form agree to better than five parts in ten million at every size this site uses, including n = 8. There is no regime where using the closed form would mislead anyone about anything, and the site uses it as an independent check on the exact sum rather than as a substitute for it.

The probe formula is the bad case, and the difference between them is not that one is a better approximation in some abstract sense. It is that Stirling’s error term is O(1/n)O(1/n) while the probe formula’s error depends on m(1α)3m(1-\alpha)^3, which stays small precisely in the regime — high load — where people most want the answer.

The lesson is not “distrust asymptotics”. It is: the size of the error is a separate question from the correctness of the limit, and it has an answer. For any closed form worth relying on, the error at the size in question can be measured, and measuring it takes an afternoon.

Probes per insertion against load factor, table of 8,192The line is Knuth's closed form for linear probing, integrated over the fill; the points are a table actually filled and counted. They agree to within 2.3% everywhere. At a load factor of 0.5 an insertion averages 1.49 probes; at 0.9 it averages 5.39. The formula that matters for insertion is the unsuccessful-search one, ½(1 + 1/(1−α)²), and using the successful-search form instead is an error that hides at low load and is glaring at high load.1234560.000.250.500.75formulameasuredload factor αprobes per insertion8,192 slots, mean of 8 fills, seeds stated in lib/structures.jstwo routes agree to 2.3%
Fig. 4 The same formula in the regime where it works. At a table of 8,192 slots and load factors up to 0.9, the closed form and a table actually filled agree to within about 3%. The formula is fine here. It is the same formula that is 48% out at 256 slots and 95% load, and nothing about the formula changed.

Two things this site does about it

States the range on everything. Every fitted class here carries the range it was fitted over, every constant carries its input distribution, and no figure claims that its measurements say anything about sizes it did not measure. This is cheap and it is not standard.

Declines to label when the measurements do not support a label. Two of roughly forty algorithm-and-input pairs on this site have no declared class, and this essay is about one of them. The other is bubble sort on nearly sorted input, where neither linear nor quadratic fits — the count is nn times a slowly growing factor, and no candidate class describes it within tolerance.

The temptation in both cases was to round to the answer the reader expects. Resisting it costs two labels and buys the credibility of the other thirty-eight.

Comparisons used, as a multiple of the floor, n = 256The information-theoretic floor at n = 256 is 1,684 comparisons: a binary decision tree with 256! leaves cannot be shallower than that. The bar is what each algorithm averaged over 16 random inputs, divided by the floor. Merge sort comes within 2% of it; Selection sort uses 19 times as many.the floorMerge sort1.02×Quicksort, first1.23×Quicksort, random1.24×Merge sort + cutoff1.29×Quicksort, median-31.32×Shellsort1.45×Heapsort1.96×Insertion sort9.69×Bubble sort19.26×Selection sort19.38×floor = log₂(256!) = 1,684 comparisonsmean of 16 runs, against a proved bound
Fig. 5 An example of a claim that does not have this problem at all. The information-theoretic floor is not an asymptotic statement — it is exact at every n, derived by counting leaves in a tree, and nothing here can get under it at any size. Where a bound is genuinely finite and exact, the whole difficulty in this essay evaporates, which is one reason the floors are worth having.

The honest statement of what this site is doing

Every page here that reports a fitted class is reporting that a set of measurements over a stated range is consistent with that class, and that the alternatives are not. That is a weaker statement than a proof and a stronger one than a glance at the loops.

Where a proof exists — as it does for merge sort, for the comparison-sorting floor, for the amortised bound on a doubling array — the proof is the reason to believe the claim and the measurement is a check on the machinery. Where a proof exists but the implementation might not match it, the measurement is checking the implementation. And where the measurement disagrees with the expected answer, as it did twice during this site’s construction, the disagreement is the most valuable output the whole apparatus produces.

The one thing it never does is claim that measuring further would settle a question about infinity. That question is not the kind of thing measurement settles, and the case in this essay is the site’s own demonstration of why.

Every sort measured on random input, and its claim testedThe exponent fitted to each algorithm's comparison count across n from 32 to 4096, beside the class it claims. The two groups separate cleanly — nothing measures between 1.3 and 1.9 — and every claim on this input is the class that actually fits. The fitted exponent for a linearithmic algorithm sits near 1.2 rather than 1.0 because n log n is not a power law.fitted exponent of the comparison count1.01.52.0Merge sort with a cutoff1.16n log nQuicksort, median of three1.19n log nQuicksort, first-element1.21n log nMerge sort1.21n log nHeapsort1.22n log nQuicksort, random pivot1.24n log nShellsort1.25n log nInsertion sort2.00n^2Selection sort2.01n^2Bubble sort2.01n^2n from 32 to 4096comparisons, counted exactly · random input
Fig. 6 The audit, with the caveat attached. Every exponent here is fitted over n = 32 to 4,096 on random input, and every one of them would be a slightly different number over a different range. The classification is robust — nothing is close to a boundary — and the numbers behind it are range-dependent, and both statements are true at once.