<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">
  <channel>
    <title>Ali Madooei</title>
    <link>https://madooei.com/</link>
    <atom:link href="https://madooei.com/feed.xml" rel="self" type="application/rss+xml"/>
    <description>Notes on teaching, projects, and ideas.</description>
    <lastBuildDate>Fri, 10 Jul 2026 13:13:42 GMT</lastBuildDate>
    <language>en</language>
    <generator>Lume 3.2.4</generator>
    <author>
      <name>Ali Madooei</name>
    </author>
    <item>
      <title>The Average Case of Quicksort</title>
      <link>https://madooei.com/posts/quicksort-average-case/</link>
      <guid isPermaLink="false">https://madooei.com/posts/quicksort-average-case/</guid>
      <description>
        A careful, student-friendly derivation of quicksort's average number of comparisons, showing why random pivots give about 1.39 n lg n comparisons.
      </description>
      <content:encoded>
        <![CDATA[<p>This post is the formal companion to the quicksort chapter in my data structures course. In the course notes, we justify quicksort's average-case performance mostly by intuition: a good pivot splits the array into two reasonably balanced pieces, and a sequence of reasonably balanced splits leads to <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0278em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span> work. Here we do the calculation.</p>
<p>The prerequisites are modest. You should know how quicksort partitions around a pivot, what Big-O notation means, what logarithms are, and the basic idea of probability. You do not need a discrete mathematics course. When we use a tool that may be new, such as expected value, I will spell out what it means.</p>
<p>We will assume the array contains <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span> distinct values and that quicksort chooses its pivot uniformly at random from the current slice each time it partitions. If your implementation always chooses the first item as pivot, this is the same kind of analysis you get after randomly shuffling the input first.</p>
<p>Quicksort sorts by partitioning around a pivot: values smaller than the pivot go to one side, values larger than the pivot go to the other, and then quicksort recursively sorts the two sides. Almost all of the algorithmic work we care about here is in comparisons: each partition step compares values against the pivot. So we will count comparisons, averaged over all the random pivot choices.</p>
<p>The final answer will be that random-pivot quicksort makes</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">2</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0813em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">4</span><span class="mord mathnormal">n</span></span></span></span></span></p>
<p>comparisons on average, where</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0813em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">3</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="minner">⋯</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>For large <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span>, that is about</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord">1.39</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">l<span style="margin-right:0.0139em;">g</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mord">.</span></span></span></span></span></p>
<p>So the familiar <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0278em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span> average-case running time is not just a slogan. It comes from a precise count of the comparisons quicksort is likely to make.</p>
<h2 id="averaging-a-sum-one-pair-at-a-time" tabindex="-1"><a href="https://madooei.com/posts/quicksort-average-case/#averaging-a-sum-one-pair-at-a-time" class="header-anchor">Averaging a sum one pair at a time</a></h2>
<p>The total number of comparisons is hard to track directly, because it depends on the whole sequence of pivots. Instead of trying to follow the whole run at once, we will look at one pair of values at a time.</p>
<p>Number the values by their place in sorted order. Let <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> be the smallest value, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> the next smallest, and so on up to <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>, the largest. This numbering is not the array index during the algorithm. It is the value's rank in sorted order.</p>
<p>Take any two values, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7167em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span>, with <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6986em;vertical-align:-0.0391em;"></span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">&lt;</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.854em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0572em;">j</span></span></span></span>. During one run of quicksort, this pair is either compared exactly once or never compared at all.</p>
<p>It cannot be compared more than once. Two values are compared only when one of them is the pivot in a partition step. Once a value is chosen as a pivot, it is placed in its final sorted position and is never used in another partition. So the same two values cannot meet again later as pivot and non-pivot.</p>
<p>Now define a small counter for this pair:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">ij</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:3em;vertical-align:-1.25em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size4">{</span></span><span class="mord"><span class="mtable"><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.69em;"><span style="top:-3.69em;"><span class="pstrut" style="height:3.008em;"></span><span class="mord"><span class="mord">1</span></span></span><span style="top:-2.25em;"><span class="pstrut" style="height:3.008em;"></span><span class="mord"><span class="mord">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.19em;"><span></span></span></span></span></span><span class="arraycolsep" style="width:1em;"></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.69em;"><span style="top:-3.69em;"><span class="pstrut" style="height:3.008em;"></span><span class="mord"><span class="mord text"><span class="mord">if </span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord text"><span class="mord"> and </span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span><span class="mord text"><span class="mord"> are compared</span></span><span class="mpunct">,</span></span></span><span style="top:-2.25em;"><span class="pstrut" style="height:3.008em;"></span><span class="mord"><span class="mord text"><span class="mord">otherwise.</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.19em;"><span></span></span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p>
<p>The total number of comparisons in the whole run is the sum of these little counters over all pairs:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.4638em;vertical-align:-1.4138em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em;"><span style="top:-1.8723em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">&lt;</span><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span style="top:-3.05em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4138em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">ij</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span><span class="mord">.</span></span></span></span></span></p>
<p>For example, if <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">6</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> are compared, then <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span><span class="mpunct mtight">,</span><span class="mord mtight">6</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span> contributes <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> to the total. If they are not compared, it contributes <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span>.</p>
<p>Now we average. The expected value of a random quantity is its long-run average: if you ran the same randomized algorithm many times and averaged the result, the average would approach the expected value. We write <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="mclose">]</span></span></span></span> for the expected value of <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.0785em;">X</span></span></span></span>.</p>
<p>The key rule we need is that the expected value of a sum is the sum of the expected values:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:3.1638em;vertical-align:-1.4138em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size4">[</span></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em;"><span style="top:-1.8723em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">&lt;</span><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span style="top:-3.05em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4138em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">ij</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size4">]</span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.4638em;vertical-align:-1.4138em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em;"><span style="top:-1.8723em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">&lt;</span><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span style="top:-3.05em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4138em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mopen">[</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">ij</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span><span class="mclose">]</span><span class="mord">.</span></span></span></span></span></p>
<p>In words: to find the average total number of comparisons, we can add up the average contribution of each pair. This rule works even though the different pair counters are not independent.</p>
<p>Each <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9694em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">ij</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span> is only <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span> or <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>. Its average is therefore just the probability that it is <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>. If a pair is compared with probability <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span></span></span></span>, then over many runs it contributes <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> about a <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span></span></span></span> fraction of the time and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span> the rest of the time, so its average contribution is <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span></span></span></span>.</p>
<p>Therefore</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0361em;vertical-align:-0.2861em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mopen">[</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">ij</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1.0361em;vertical-align:-0.2861em;"></span><span class="mop">Pr</span><span class="mopen">[</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord text"><span class="mord"> and </span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span><span class="mord text"><span class="mord"> are compared</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mclose">]</span><span class="mpunct">,</span></span></span></span></span></p>
<p>and the expected total number of comparisons is</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.4638em;vertical-align:-1.4138em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em;"><span style="top:-1.8723em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">&lt;</span><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span style="top:-3.05em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4138em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">Pr</span><span class="mopen">[</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord text"><span class="mord"> and </span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span><span class="mord text"><span class="mord"> are compared</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mclose">]</span><span class="mord">.</span></span></span></span></span></p>
<p>Now we need that probability.</p>
<h2 id="when-are-two-values-compared" tabindex="-1"><a href="https://madooei.com/posts/quicksort-average-case/#when-are-two-values-compared" class="header-anchor">When are two values compared?</a></h2>
<p>Consider the values <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> through <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">8</span></span></span></span>, already in sorted order, so <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6595em;"></span><span class="mord mathnormal">i</span></span></span></span>. Take the pair <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">6</span></span></span></span>, and look at the block of values between them, ends included: <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">{</span><span class="mord">2</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">3</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">4</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">5</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">6</span><span class="mclose">}</span></span></span></span>.</p>
<p>The key fact is this: <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">6</span></span></span></span> are compared if and only if the first pivot chosen from that block is either <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span> or <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">6</span></span></span></span>.</p>
<p>To see why, follow what happens as pivots are chosen. As long as no pivot comes from the block <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">{</span><span class="mord">2</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">3</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">4</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">5</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">6</span><span class="mclose">}</span></span></span></span>, all five of those values stay together in one slice. A pivot from outside the block cannot separate them. A pivot of <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> is smaller than all five, so they all go to its right. A pivot of <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">7</span></span></span></span> or <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">8</span></span></span></span> is larger than all five, so they all go to its left. Either way, the block stays whole.</p>
<p>So the first pivot that falls inside the block is the first one to touch these values, and there are three cases:</p>
<ul>
<li>The first such pivot is <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span>. Then <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span> is compared against every value in its slice, and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">6</span></span></span></span> is still in that slice, so <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">6</span></span></span></span> are compared.</li>
<li>The first such pivot is <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">6</span></span></span></span>. By the same reasoning, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">6</span></span></span></span> is compared against <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span>.</li>
<li>The first such pivot is a middle value, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">3</span></span></span></span>, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">4</span></span></span></span>, or <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">5</span></span></span></span>. Say it is <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">4</span></span></span></span>. Partitioning around <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">4</span></span></span></span> sends <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">3</span></span></span></span> to its left and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">5</span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">6</span></span></span></span> to its right. Now <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">6</span></span></span></span> sit in different slices, and nothing ever brings them back together, so they are never compared. Each is compared against <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">4</span></span></span></span>, but not against each other.</li>
</ul>
<p>So <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">6</span></span></span></span> are compared exactly when the first pivot from the block is one of the two ends, not one of the middle values.</p>
<h2 id="the-probability" tabindex="-1"><a href="https://madooei.com/posts/quicksort-average-case/#the-probability" class="header-anchor">The probability</a></h2>
<p>The same reasoning works for any pair. The block between <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7167em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span> is</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0361em;vertical-align:-0.2861em;"></span><span class="mopen">{</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mbin mtight">+</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2083em;"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner">…</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span><span class="mclose">}</span><span class="mord">.</span></span></span></span></span></p>
<p>This block has</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.854em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0572em;">j</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7429em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span></span></p>
<p>values: it starts at position <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6595em;"></span><span class="mord mathnormal">i</span></span></span></span>, ends at position <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.854em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0572em;">j</span></span></span></span>, and includes both ends.</p>
<p>The values in this block stay together until one of them is chosen as a pivot. Once the first pivot from this block is chosen, there are two possibilities:</p>
<ul>
<li>If the first pivot from the block is <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> or <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7167em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span>, then the pair is compared.</li>
<li>If the first pivot from the block is one of the values strictly between them, then the pair is separated and is never compared.</li>
</ul>
<p>Because pivots are chosen at random, the first value chosen from this block is equally likely to be any of the <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.854em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0572em;">j</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7429em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> values in the block. One way to picture this is to imagine that the values in the block are waiting in a random order to become pivots. The one that appears first in that random order is equally likely to be any of them.</p>
<p>There are <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.854em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0572em;">j</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7429em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> possible first pivots from the block. Exactly two of them, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7167em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span>, make the pair get compared. Therefore</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0361em;vertical-align:-0.2861em;"></span><span class="mop">Pr</span><span class="mopen">[</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord text"><span class="mord"> and </span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span><span class="mord text"><span class="mord"> are compared</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.2019em;vertical-align:-0.8804em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0572em;">j</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.8804em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>The closer two values are in sorted order, the more likely they are compared. Neighbors, where <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.854em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0572em;">j</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7429em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>, have a block of two and are compared with probability <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">2/2</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>, always. The smallest and largest values have a block of <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span> and are compared with probability only <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">2/</span><span class="mord mathnormal">n</span></span></span></span>.</p>
<h2 id="adding-it-up" tabindex="-1"><a href="https://madooei.com/posts/quicksort-average-case/#adding-it-up" class="header-anchor">Adding it up</a></h2>
<p>Now put that probability into the expected-value sum:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.7352em;vertical-align:-1.4138em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em;"><span style="top:-1.8723em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">&lt;</span><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span style="top:-3.05em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4138em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0572em;">j</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.8804em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>We could add this by looping over all choices of <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6595em;"></span><span class="mord mathnormal">i</span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.854em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0572em;">j</span></span></span></span>, but it is cleaner to group pairs by how far apart they are in sorted order.</p>
<p>Let</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.854em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0572em;">j</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6595em;"></span><span class="mord mathnormal">i</span><span class="mord">.</span></span></span></span></span></p>
<p>This <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span></span></span></span> is the gap between the two values. If <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>, the values are neighbors in sorted order. If <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span>, there is one value between them. In general, a gap of <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span></span></span></span> means the block from <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> to <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7167em;vertical-align:-0.2861em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0572em;">j</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2861em;"><span></span></span></span></span></span></span></span></span></span> has <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> values, so each such pair is compared with probability</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.0908em;vertical-align:-0.7693em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.7693em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>How many pairs have gap <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span></span></span></span>? The smaller value can be <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6389em;vertical-align:-0.2083em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner">…</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.044em;">z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361em;"><span style="top:-2.55em;margin-left:-0.044em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mbin mtight">−</span><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2083em;"><span></span></span></span></span></span></span></span></span></span>. After that, the larger value is forced: it must be <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span></span></span></span> positions later. So there are <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span></span></span></span> pairs with gap <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span></span></span></span>.</p>
<p>Therefore</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:3.1032em;vertical-align:-1.3021em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.8011em;"><span style="top:-1.8479em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.05em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mbin mtight">−</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3021em;"><span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.0908em;vertical-align:-0.7693em;"></span><span class="mord mathnormal">d</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.7693em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>This formula is already the exact average number of comparisons. Now we simplify it.</p>
<p>Set <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>. When <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span>. When <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span>. Also, since <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>,</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mord">.</span></span></span></span></span></p>
<p>So the sum becomes</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.9535em;vertical-align:-1.3021em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6514em;"><span style="top:-1.8479em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span><span class="mrel mtight">=</span><span class="mord mtight">2</span></span></span></span><span style="top:-3.05em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3021em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>Split the fraction:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.0574em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1.</span></span></span></span></span></p>
<p>Then</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.9535em;vertical-align:-1.3021em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6514em;"><span style="top:-1.8479em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span><span class="mrel mtight">=</span><span class="mord mtight">2</span></span></span></span><span style="top:-3.05em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3021em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">.</span></span></span></span></span></p>
<p>There are two pieces here:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.9535em;vertical-align:-1.3021em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6514em;"><span style="top:-1.8479em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span><span class="mrel mtight">=</span><span class="mord mtight">2</span></span></span></span><span style="top:-3.05em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3021em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.4em;vertical-align:-0.95em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">3</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="minner">⋯</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mpunct">,</span></span></span></span></span></p>
<p>and</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.9535em;vertical-align:-1.3021em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6514em;"><span style="top:-1.8479em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span><span class="mrel mtight">=</span><span class="mord mtight">2</span></span></span></span><span style="top:-3.05em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3021em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1.</span></span></span></span></span></p>
<p>Therefore</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.4em;vertical-align:-0.95em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">3</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="minner">⋯</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">.</span></span></span></span></span></p>
<p>The sum</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">3</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="minner">⋯</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p>
<p>is called the $n$th harmonic number and is written <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0813em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>. Since</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">3</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="minner">⋯</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0813em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8389em;vertical-align:-0.1944em;"></span><span class="mord">1</span><span class="mpunct">,</span></span></span></span></span></p>
<p>we get</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;">(</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0813em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mclose delimcenter" style="top:0em;">)</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">.</span></span></span></span></span></p>
<p>Expanding the expression gives the standard exact formula:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">2</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0813em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">4</span><span class="mord mathnormal">n</span><span class="mord">.</span></span></span></span></span></p>
<p>That is the average number of comparisons made by random-pivot quicksort on <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span> distinct values.</p>
<h2 id="why-this-is-o-n-log-n" tabindex="-1"><a href="https://madooei.com/posts/quicksort-average-case/#why-this-is-o-n-log-n" class="header-anchor">Why this is O(n log n)</a></h2>
<p>The exact formula contains <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0813em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>, so we need to know how fast <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0813em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> grows.</p>
<p>The harmonic number</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0813em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">3</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="minner">⋯</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p>
<p>grows like <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span></span></span></span>. Intuitively, this sum is a discrete version of the area under the curve <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1/</span><span class="mord mathnormal">x</span></span></span></span>. The area under <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1/</span><span class="mord mathnormal">x</span></span></span></span> from <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> to <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span> is <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span></span></span></span>, so the sum <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1/2</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="minner">⋯</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1/</span><span class="mord mathnormal">n</span></span></span></span> grows at the same logarithmic rate.</p>
<p>That means</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0813em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0278em;">O</span><span class="mopen">(</span><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mord">.</span></span></span></span></span></p>
<p>So from the exact formula,</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0576em;">E</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.0785em;">X</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">2</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0813em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8389em;vertical-align:-0.1944em;"></span><span class="mord">4</span><span class="mord mathnormal">n</span><span class="mpunct">,</span></span></span></span></span></p>
<p>the main term grows like <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span></span></span></span>. The <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">−</span><span class="mord">4</span><span class="mord mathnormal">n</span></span></span></span> part is only linear, and the <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">2</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span></span></span></span> factor in front of <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0813em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> is proportional to <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span>. Therefore the expected number of comparisons is</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0278em;">O</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mord">.</span></span></span></span></span></p>
<p>This is the formal version of the intuition from the course notes: random pivots tend to produce enough reasonably balanced splitting that the average cost is logarithmic levels of partitioning, with about <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span> comparison work per level.</p>
<h2 id="the-leading-constant" tabindex="-1"><a href="https://madooei.com/posts/quicksort-average-case/#the-leading-constant" class="header-anchor">The leading constant</a></h2>
<p>The exact formula also tells us the leading constant. Since <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0813em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> grows like <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span></span></span></span>, the dominant part of</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">2</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0813em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:-0.0813em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">4</span><span class="mord mathnormal">n</span></span></span></span></span></p>
<p>is</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord">2</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mord">.</span></span></span></span></span></p>
<p>Computer science usually writes sorting lower bounds and comparison counts with base-two logarithms. Since</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">2</span><span class="mclose">)</span><span class="mopen">(</span><span class="mop">l<span style="margin-right:0.0139em;">g</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mpunct">,</span></span></span></span></span></p>
<p>we get</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord">2</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">l<span style="margin-right:0.0139em;">g</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mord">.</span></span></span></span></span></p>
<p>And because</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8389em;vertical-align:-0.1944em;"></span><span class="mord">1.386</span><span class="mpunct">,</span></span></span></span></span></p>
<p>random-pivot quicksort makes about</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord">1.39</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">l<span style="margin-right:0.0139em;">g</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span></span></span></span></span></p>
<p>comparisons on average, ignoring lower-order terms.</p>
<p>No comparison sort can average fewer than about <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">l<span style="margin-right:0.0139em;">g</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span></span></span></span> comparisons in the leading term, so quicksort's random-pivot average is only about forty percent above that floor. That is the precise sense in which quicksort is fast on average, and it stands well clear of the <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0641em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0278em;">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span> behavior that bad pivot choices can produce.</p>
]]>
      </content:encoded>
      <pubDate>Fri, 10 Jul 2026 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>Choosing the Base for a Polynomial String Hash</title>
      <link>https://madooei.com/posts/choosing-a-hash-base/</link>
      <guid isPermaLink="false">https://madooei.com/posts/choosing-a-hash-base/</guid>
      <description>
        Why polynomial string hashes usually use odd bases, why shared factors with the table size are dangerous, and why primes are a useful habit rather than a magic rule.
      </description>
      <content:encoded>
        <![CDATA[<p>This post is the formal companion to the string hashing discussion in my data structures course. In the course notes, we usually say that a string hash multiplies by a base and adds the next character. Here we slow down and ask what the base is doing, why <code>31</code> is such a common choice, and why &quot;use a prime&quot; is useful advice but not the whole story.</p>
<p>The prerequisites are modest. You should know what a hash table is, what a hash collision is, and what the remainder operation does. You should also be comfortable with binary numbers at the level of &quot;multiplying by 2 shifts bits left.&quot; You do not need a discrete mathematics course. When we use words such as factor, prime, or relatively prime, I will explain them.</p>
<p>A hash table stores a value under a key by turning the key into an array index. For string keys, one common way to get that index is to fold the string down into a single integer, then reduce that integer to a slot.</p>
<p>The fold reads the characters one at a time. Each character has a numeric code (<code>'A'</code> is <code>65</code> in the usual encoding, <code>'B'</code> is <code>66</code>, and so on up the alphabet). Keep a running integer <code>h</code>, start it at <code>0</code>, and for each character multiply <code>h</code> by a fixed number, the <em>base</em>, and add the character's code:</p>
<pre><code class="language-java">int h = 0;
for (int i = 0; i &lt; s.length(); i++) {
  h = base * h + s.charAt(i);
}
</code></pre>
<p>At the end, <code>h</code> is the string's hash code. To turn it into a slot in an array of <code>capacity</code> slots, reduce it modulo <code>capacity</code>. Mathematically, that means choosing a number from <code>0</code> through <code>capacity - 1</code> with the same remainder as <code>h</code>. In Java, <code>%</code> can be negative when <code>h</code> is negative, so real code has to correct for that or use a power-of-two mask. The mathematical idea is still &quot;use the remainder to choose a slot.&quot;</p>
<p>This hash is called a <em>polynomial hash</em> because, if you expand the loop, the characters are weighted by powers of the base. For a three-character string with codes <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>, and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>, the loop computes</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">((</span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord mathnormal">b</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord mathnormal">b</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1.0141em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">b</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mpunct">,</span></span></span></span></span></p>
<p>where <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">b</span></span></span></span> is the base.</p>
<p>The base can be any number bigger than <code>1</code>. With a base of <code>1</code>, multiplying does nothing, so the fold just adds the character codes. Then every rearrangement of the same characters gets the same hash, which is terrible for strings.</p>
<p>But not every base above <code>1</code> is a good choice. The most important practical rule is that the base should be odd. A second rule is that the base should avoid sharing factors with the table size; choosing a prime base is a common way to help with that, but it is not a magic requirement. We will look at both rules.</p>
<h2 id="why-the-base-should-be-odd" tabindex="-1"><a href="https://madooei.com/posts/choosing-a-hash-base/#why-the-base-should-be-odd" class="header-anchor">Why the base should be odd</a></h2>
<p>Start with what multiplying does to the bits of <code>h</code>. Multiplying a binary number by <code>2</code> shifts every bit one place to the left and puts a <code>0</code> in the rightmost place. This is like multiplying a decimal number by <code>10</code>: the digits shift left and a <code>0</code> appears at the end.</p>
<p>Multiplying by <code>4</code> shifts two places left and puts two <code>0</code>s at the bottom. More generally, multiplying by an even number always puts a <code>0</code> in the lowest bit of the product, because every even number has a factor of <code>2</code>.</p>
<p>That matters because many hash tables use a power-of-two capacity. If the table has <code>4</code> slots, the slot is determined by the last two bits of the hash. If the table has <code>8</code> slots, the slot is determined by the last three bits. In general, reducing modulo <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8491em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8491em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span></span></span></span></span></span></span></span></span></span></span> keeps only the lowest <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span></span> bits.</p>
<p>Take a base of <code>4</code> and a table of <code>4</code> slots. To keep the arithmetic short, use small character codes: <code>A</code> is <code>1</code>, <code>B</code> is <code>2</code>, and <code>X</code> is <code>3</code>. Hash the two strings <code>&quot;AB&quot;</code> and <code>&quot;XB&quot;</code>, which differ only in their first letter:</p>
<pre><code class="language-plaintext">base 4:
 &quot;AB&quot;:  h = 0; 4*0 + 1 = 1;  4*1 + 2 = 6    -&gt;  6  mod 4 = 2
 &quot;XB&quot;:  h = 0; 4*0 + 3 = 3;  4*3 + 2 = 14   -&gt;  14 mod 4 = 2
</code></pre>
<p>Both land in slot <code>2</code>. In fact, with base <code>4</code> and capacity <code>4</code>, every two-character string that ends in <code>B</code> lands in slot <code>2</code>, no matter what the first character is. The reason is that multiplying the first character by <code>4</code> makes it a multiple of <code>4</code>, and multiples of <code>4</code> leave remainder <code>0</code> when divided by <code>4</code>. So the first character disappears from the slot calculation.</p>
<p>The same problem happens more generally with even bases and power-of-two capacities. The repeated multiplications push earlier characters out of the low bits, and the low bits are exactly what a power-of-two table reads.</p>
<p>Now change the base to <code>5</code>, an odd number, and keep everything else the same:</p>
<pre><code class="language-plaintext">base 5:
 &quot;AB&quot;:  h = 0; 5*0 + 1 = 1;  5*1 + 2 = 7    -&gt;  7  mod 4 = 3
 &quot;XB&quot;:  h = 0; 5*0 + 3 = 3;  5*3 + 2 = 17   -&gt;  17 mod 4 = 1
</code></pre>
<p>The two strings land in different slots, <code>3</code> and <code>1</code>. Since <code>5 mod 4</code> is the same as <code>1 mod 4</code>, the first character still affects the final remainder.</p>
<p>That is the reason for the odd rule. An even base loses information in the low bits, especially when the table size is a power of two. An odd base does not automatically make the hash good, but it avoids this particular failure: earlier characters can still influence the low bits that choose the slot.</p>
<h2 id="why-shared-factors-are-dangerous" tabindex="-1"><a href="https://madooei.com/posts/choosing-a-hash-base/#why-shared-factors-are-dangerous" class="header-anchor">Why shared factors are dangerous</a></h2>
<p>An odd base fixes the low-bit problem, but on its own it is not enough. A base can be odd and still line up badly with the table size.</p>
<p>A <em>factor</em> of a number is a number that divides it evenly. For example, <code>5</code> is a factor of <code>10</code>. Two numbers are <em>relatively prime</em> if they share no factor bigger than <code>1</code>. For example, <code>3</code> and <code>10</code> are relatively prime, but <code>5</code> and <code>10</code> are not.</p>
<p>The trouble appears when the base and the capacity share a factor. Take a table of <code>10</code> slots and a base of <code>5</code>. Five is odd, but it shares the factor <code>5</code> with <code>10</code>.</p>
<p>Hash a two-letter string with character codes <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>. The hash is</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7944em;vertical-align:-0.15em;"></span><span class="mord">5</span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mpunct">,</span></span></span></span></span></p>
<p>and the slot is</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">5</span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.0556em;"></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin"><span class="mord"><span class="mord mathrm">mod</span></span></span><span class="mspace" style="margin-right:0.0556em;"></span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">10.</span></span></span></span></span></p>
<p>Focus on the first character's contribution:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord">5</span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.0556em;"></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin"><span class="mord"><span class="mord mathrm">mod</span></span></span><span class="mspace" style="margin-right:0.0556em;"></span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">10.</span></span></span></span></span></p>
<p>If <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> is even, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7944em;vertical-align:-0.15em;"></span><span class="mord">5</span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> is a multiple of <code>10</code>, so the contribution is <code>0</code>. If <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> is odd, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7944em;vertical-align:-0.15em;"></span><span class="mord">5</span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> leaves remainder <code>5</code>. Those are the only two possibilities. So the first character can shift the slot by only <code>0</code> or <code>5</code>; it cannot help spread keys across all ten slots.</p>
<p>Change the base to <code>3</code>, which shares no factor with <code>10</code>. Now</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord">3</span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.0556em;"></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin"><span class="mord"><span class="mord mathrm">mod</span></span></span><span class="mspace" style="margin-right:0.0556em;"></span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">10</span></span></span></span></span></p>
<p>runs through</p>
<pre><code class="language-plaintext">3, 6, 9, 2, 5, 8, 1, 4, 7, 0
</code></pre>
<p>as <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> runs from <code>1</code> through <code>10</code>. It reaches every possible remainder. The first character can now move the hash anywhere in the table.</p>
<p>That is the real rule: the base should not share factors with the capacity. If the base and capacity are relatively prime, multiplication by the base does not trap a character's contribution inside a smaller set of slots. If they share a factor, some contributions get trapped.</p>
<h2 id="so-does-the-base-need-to-be-prime" tabindex="-1"><a href="https://madooei.com/posts/choosing-a-hash-base/#so-does-the-base-need-to-be-prime" class="header-anchor">So does the base need to be prime?</a></h2>
<p>A prime number is a number greater than <code>1</code> whose only positive factors are <code>1</code> and itself. Examples are <code>3</code>, <code>5</code>, <code>31</code>, and <code>16777619</code>. Composite numbers, such as <code>4</code>, <code>10</code>, and <code>33</code>, have additional factors.</p>
<p>Choosing a prime base is a useful habit because a prime has very few factors. A prime base can share a factor with the capacity only when the capacity is a multiple of that prime. That is less likely than with a composite base.</p>
<p>But &quot;prime&quot; is not the exact requirement. The exact requirement is about the relationship between the base and the table size.</p>
<p>If the capacity is a power of two, then every odd base is relatively prime to the capacity. In that setting, <code>31</code>, <code>33</code>, and <code>37</code> all avoid the shared-factor problem because none of them has a factor of <code>2</code>. This is one reason DJB2 can use <code>33</code> even though <code>33</code> is not prime.</p>
<p>If the capacity is a prime number, then almost any smaller base is relatively prime to it. The base itself does not need to be prime; it just needs not to be a multiple of the capacity.</p>
<p>So the careful version is:</p>
<ul>
<li>The base should be odd, especially for power-of-two table sizes.</li>
<li>The base should be relatively prime to the table sizes you use.</li>
<li>Choosing a prime base is a common way to reduce shared-factor problems, but it is a heuristic, not a proof that the hash is best.</li>
</ul>
<h2 id="the-bases-real-hashes-use" tabindex="-1"><a href="https://madooei.com/posts/choosing-a-hash-base/#the-bases-real-hashes-use" class="header-anchor">The bases real hashes use</a></h2>
<p>Java's <code>String.hashCode()</code> uses a base of <code>31</code>:</p>
<pre><code class="language-java">h = 31 * h + c;
</code></pre>
<p>The number <code>31</code> has several useful properties. It is odd, so it avoids the low-bit failure. It is prime, so it has very few shared-factor risks. It is also one less than <code>32</code>, and <code>32</code> is <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">5</span></span></span></span></span></span></span></span></span></span></span>, so</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord">31</span><span class="mord mathnormal">h</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mord">32</span><span class="mord mathnormal">h</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">h</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">h</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≪</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">5</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">h</span><span class="mord">.</span></span></span></span></span></p>
<p>That means a multiply by <code>31</code> can be implemented as a left shift by five bits followed by a subtraction. This mattered more on older processors, where a general multiplication was relatively expensive, but the tradition remains.</p>
<p>For a long string, the running value grows past what a 32-bit <code>int</code> can hold and wraps around, sometimes becoming negative. Java integer arithmetic is deterministic, so the same string still gets the same hash code every time. The hash code is not meant to preserve the original number; it is meant to produce a repeatable, well-spread integer.</p>
<p>DJB2, by Dan Bernstein, uses a base of <code>33</code> and usually starts <code>h</code> at <code>5381</code> instead of <code>0</code>. The base <code>33</code> is odd, but it is not prime:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">33</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">3</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">11.</span></span></span></span></span></p>
<p>It is still popular because it is fast and has tested well on many ordinary string sets:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord">33</span><span class="mord mathnormal">h</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mord">32</span><span class="mord mathnormal">h</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">h</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">h</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≪</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">5</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">h</span><span class="mord">.</span></span></span></span></span></p>
<p>This is a useful reminder that &quot;prime&quot; is not an absolute law. DJB2 follows the odd rule and performs well in practice despite using a composite base.</p>
<p>FNV-1a is another well-known string and byte hash. In its 32-bit version, it starts from the offset basis <code>2166136261</code>; for each byte, it XORs the byte into the hash and then multiplies by the FNV prime <code>16777619</code>:</p>
<pre><code class="language-plaintext">h = h xor byte
h = h * 16777619
</code></pre>
<p>Here the multiplier is odd and prime, and it was chosen for good bit behavior under repeated multiplication and XOR.</p>
<p>The specific numbers <code>31</code>, <code>33</code>, <code>5381</code>, <code>16777619</code>, and <code>2166136261</code> do not fall out of one simple formula. They come from a mix of arithmetic properties, speed, and testing on real data. A hash constant survives because it spreads typical keys well, not because one theorem declares it perfect.</p>
<h2 id="a-note-on-the-table-size" tabindex="-1"><a href="https://madooei.com/posts/choosing-a-hash-base/#a-note-on-the-table-size" class="header-anchor">A note on the table size</a></h2>
<p>The base and the table size interact, so one more point is worth making.</p>
<p>If the capacity is a power of two, reducing modulo the capacity keeps only the low bits of <code>h</code>. Dividing by <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8491em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8491em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span></span></span></span></span></span></span></span></span></span></span> leaves the last <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span></span> bits. This is fast because it can be done with a bit mask instead of a division. The cost is that all the responsibility falls on the low bits. An even base is especially bad here because it repeatedly clears or weakens those low bits.</p>
<p>If the capacity is prime, the modulo operation depends on more of the whole integer instead of only the lowest bits. That can forgive some weaker low-bit behavior, but division by an arbitrary prime is usually slower than a bit mask.</p>
<p>Java's <code>HashMap</code> takes the first road. It uses power-of-two capacities for speed, then applies an extra spreading step to the key's hash code so that some high-bit information is mixed down into the low bits before the slot is chosen.</p>
<p>So the practical answer is:</p>
<ul>
<li>Use an odd base.</li>
<li>Avoid sharing factors with the table sizes you use.</li>
<li>Treat prime bases as a good tradition, not a magic shield.</li>
<li>Trust testing over numerology when choosing exact constants.</li>
</ul>
<p>That is why <code>31</code>, <code>33</code>, and large FNV primes can all make sense in their own contexts. The base is not good by itself; it is good because it works well with the update rule, the table size, the slot calculation, and the kinds of keys you expect to store.</p>
]]>
      </content:encoded>
      <pubDate>Fri, 10 Jul 2026 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>The Birthday Paradox and Hash Collisions</title>
      <link>https://madooei.com/posts/birthday-collisions/</link>
      <guid isPermaLink="false">https://madooei.com/posts/birthday-collisions/</guid>
      <description>
        Why hash collisions appear long before a table is full, how the birthday paradox explains the square-root threshold, and why load factor is still the right performance control.
      </description>
      <content:encoded>
        <![CDATA[<p>This post is the formal companion to the hash table discussion in my data structures course. In the course notes, we say that collisions are unavoidable and that a hash table must have a collision-resolution strategy, such as chaining or probing. Here we work out why collisions appear so early, even when the table is mostly empty.</p>
<p>The prerequisites are modest. You should know what a hash table slot is, what a collision is, and what it means for a hash function to spread keys evenly. You should also be comfortable with fractions, percentages, and the basic idea of probability. You do not need a discrete mathematics course. When we use notation such as <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2em;vertical-align:-0.35em;"></span><span class="mord"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size1">(</span></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7454em;"><span style="top:-2.355em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span><span style="top:-3.144em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size1">)</span></span></span></span></span></span> or expected value, I will explain what it means.</p>
<p>We will use a simplified model called <em>uniform hashing</em>. The table has <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span></span></span></span> slots, numbered <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span> through <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>, and each key is equally likely to land in any one of those slots. Real hash functions are not perfectly random, but this model is the right starting point: it tells us what happens when the hash function is doing its job well.</p>
<p>A <em>collision</em> happens when two different keys receive the same slot number. You might expect collisions to become likely only when the table is close to full, with nearly <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span></span></span></span> keys competing for <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span></span></span></span> slots. They start much sooner than that. A table with thousands of empty slots can already be likely to contain at least one collision.</p>
<h2 id="a-warm-up-shared-birthdays" tabindex="-1"><a href="https://madooei.com/posts/birthday-collisions/#a-warm-up-shared-birthdays" class="header-anchor">A warm-up: shared birthdays</a></h2>
<p>Set hash tables aside for a moment and think about birthdays. There are 365 possible birthdays, ignoring leap years. Put some people in a room and ask whether two of them share a birthday. How many people do you need before a shared birthday is more likely than not?</p>
<p>The common guess is around 180, about half of 365. The real answer is 23. With 23 people, the chance that two of them share a birthday is already about 51%. With 50 people, it is about 97%. Shared birthdays appear far sooner than intuition expects, and this is known as the <em>birthday paradox</em>.</p>
<p>The reason is that a shared birthday is not about one particular pair of people. It is about <em>any</em> pair among all of them.</p>
<p>With 23 people, there are 253 different pairs of people. The notation for this is</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.4em;vertical-align:-0.95em;"></span><span class="mord"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">23</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">253.</span></span></span></span></span></p>
<p>The symbol <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2em;vertical-align:-0.35em;"></span><span class="mord"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size1">(</span></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7454em;"><span style="top:-2.355em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span><span style="top:-3.144em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size1">)</span></span></span></span></span></span> means &quot;the number of ways to choose 2 things from <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span> things.&quot; In this setting, it counts pairs. The formula is</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.4em;vertical-align:-0.95em;"></span><span class="mord"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.1076em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.113em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>Why divide by 2? Because <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal">A</span></span></span></span> paired with <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.0502em;">B</span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.0502em;">B</span></span></span></span> paired with <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal">A</span></span></span></span> are the same pair. The product <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">n</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span></span></span></span> counts both orders, so we divide by 2 to remove the duplicate counting.</p>
<p>With 23 people, every one of the 253 pairs is a chance for a birthday match. That is a lot of chances, and they add up quickly.</p>
<p>Hashing is the same situation with different labels. The people are the keys, and the 365 birthdays are the <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span></span></span></span> slots. Two people sharing a birthday is two keys sharing a slot, which is a collision. So the birthday paradox tells us that collisions appear far sooner than the table filling up would suggest.</p>
<h2 id="counting-the-chance-of-no-collision" tabindex="-1"><a href="https://madooei.com/posts/birthday-collisions/#counting-the-chance-of-no-collision" class="header-anchor">Counting the chance of no collision</a></h2>
<p>Here is the calculation behind that number 23, and it works for any number of slots.</p>
<p>Place keys into <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span></span></span></span> slots one at a time, and assume each key is equally likely to land in any slot. Follow the probability that <em>no</em> collision has happened yet, meaning every key so far sits in a slot of its own.</p>
<ul>
<li>The first key lands in some slot. There is nothing to collide with, so this step is certain. Its probability is <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>.</li>
<li>The second key collides only if it hits the one occupied slot. It avoids that slot with probability <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1.1901em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8451em;"><span style="top:-2.655em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">m</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>.</li>
<li>The third key must avoid the two occupied slots, which happens with probability <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1.1901em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8451em;"><span style="top:-2.655em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">m</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>.</li>
<li>In general, the <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6595em;"></span><span class="mord mathnormal">i</span></span></span></span>-th key must avoid the <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7429em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> slots already taken, with probability <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1.2007em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8557em;"><span style="top:-2.655em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">m</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mbin mtight">−</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>.</li>
</ul>
<p>For all <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span></span> keys to land in separate slots, every one of these steps has to succeed. We multiply the probabilities because each line is asking for the next key to avoid the slots already occupied, assuming all previous keys have avoided collisions.</p>
<p>So the exact probability of no collision among <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span></span> keys is</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.1389em;">P</span><span class="mopen">(</span><span class="mord text"><span class="mord">no collision</span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.4em;vertical-align:-0.95em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">m</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">m</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner">⋯</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">m</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">.</span></span></span></span></span></p>
<p>The first key's probability of <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> is not written because multiplying by <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> does not change the product.</p>
<p>The chance of at least one collision is whatever is left:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.1389em;">P</span><span class="mopen">(</span><span class="mord text"><span class="mord">collision</span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.1389em;">P</span><span class="mopen">(</span><span class="mord text"><span class="mord">no collision</span></span><span class="mclose">)</span><span class="mord">.</span></span></span></span></span></p>
<p>Each factor is a little less than <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>, and multiplying many numbers that are each a little less than <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> pulls the product down quickly. That is why the no-collision probability drops so fast as <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span></span> grows.</p>
<p>If <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7335em;vertical-align:-0.0391em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span></span></span></span>, then a collision is guaranteed: there are more keys than slots. The surprising part is what happens much earlier, when <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span></span> is still much smaller than <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span></span></span></span>.</p>
<h2 id="putting-numbers-in" tabindex="-1"><a href="https://madooei.com/posts/birthday-collisions/#putting-numbers-in" class="header-anchor">Putting numbers in</a></h2>
<p>With <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">365</span></span></span></span>, the product gives these chances of a collision for a few values of <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span></span>:</p>
<table>
<thead>
<tr>
<th>keys <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span></span></th>
<th>chance of a collision</th>
</tr>
</thead>
<tbody>
<tr>
<td>10</td>
<td>about 12%</td>
</tr>
<tr>
<td>23</td>
<td>about 51%</td>
</tr>
<tr>
<td>50</td>
<td>about 97%</td>
</tr>
</tbody>
</table>
<p>By 23 keys, the odds have already crossed one half. At least 342 of the 365 possible birthdays are still unused, and possibly more if a collision has already happened. The table is only about 6% full, yet a collision is already about as likely as not.</p>
<h2 id="the-square-root-rule" tabindex="-1"><a href="https://madooei.com/posts/birthday-collisions/#the-square-root-rule" class="header-anchor">The square-root rule</a></h2>
<p>There is a useful shortcut for where the halfway point lands, and it works for any <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span></span></span></span>.</p>
<p>The exact no-collision probability is</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.4em;vertical-align:-0.95em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">m</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">m</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner">⋯</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">m</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">.</span></span></span></span></span></p>
<p>When <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6595em;"></span><span class="mord mathnormal">i</span></span></span></span> is small compared with <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span></span></span></span>, the number <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">i</span><span class="mord">/</span><span class="mord mathnormal">m</span></span></span></span> is small, and</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.0225em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3365em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">m</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p>
<p>is close to</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.938em;"></span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.938em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">−</span><span class="mord mathnormal mtight">i</span><span class="mord mtight">/</span><span class="mord mathnormal mtight">m</span></span></span></span></span></span></span></span></span><span class="mord">.</span></span></span></span></span></p>
<p>This is a standard approximation: for small <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span>, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span> is close to <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7713em;"></span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7713em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">−</span><span class="mord mathnormal mtight">x</span></span></span></span></span></span></span></span></span></span></span></span>. You do not need the proof here; the point is that it turns a product into something easier to simplify.</p>
<p>Using that approximation,</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.1389em;">P</span><span class="mopen">(</span><span class="mord text"><span class="mord">no collision</span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.938em;"></span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.938em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">−</span><span class="mopen mtight">(</span><span class="mord mtight">1</span><span class="mbin mtight">+</span><span class="mord mtight">2</span><span class="mbin mtight">+</span><span class="minner mtight">⋯</span><span class="mbin mtight">+</span><span class="mopen mtight">(</span><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span><span class="mbin mtight">−</span><span class="mord mtight">1</span><span class="mclose mtight">))</span><span class="mord mtight">/</span><span class="mord mathnormal mtight">m</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.938em;"></span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.938em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">−</span><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span><span class="mopen mtight">(</span><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span><span class="mbin mtight">−</span><span class="mord mtight">1</span><span class="mclose mtight">)</span><span class="mord mtight">/</span><span class="mopen mtight">(</span><span class="mord mtight">2</span><span class="mord mathnormal mtight">m</span><span class="mclose mtight">)</span></span></span></span></span></span></span></span></span><span class="mord">.</span></span></span></span></span></p>
<p>The exponent contains</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="minner">⋯</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mord">.</span></span></span></span></span></p>
<p>That sum is</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.113em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>One way to remember this formula is to use &quot;number of terms times average term.&quot; There are <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> terms, from <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> through <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>. Their average is halfway between the first and last term:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.113em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.0574em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>So the sum is</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:2.0574em;vertical-align:-0.686em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.113em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>Now ask when a collision becomes about as likely as not. That happens when the no-collision probability is about <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1/2</span></span></span></span>:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.938em;"></span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.938em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">−</span><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span><span class="mopen mtight">(</span><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span><span class="mbin mtight">−</span><span class="mord mtight">1</span><span class="mclose mtight">)</span><span class="mord mtight">/</span><span class="mopen mtight">(</span><span class="mord mtight">2</span><span class="mord mathnormal mtight">m</span><span class="mclose mtight">)</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>Take natural logs of both sides:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.113em;vertical-align:-0.686em;"></span><span class="mord">−</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span><span class="mord mathnormal">m</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.4em;vertical-align:-0.95em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">.</span></span></span></span></span></p>
<p>Since <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop">ln</span><span class="mopen">(</span><span class="mord">1/2</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mord">−</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">2</span></span></span></span>, this becomes</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.113em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span><span class="mord mathnormal">m</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">2.</span></span></span></span></span></p>
<p>So</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord">2</span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">2.</span></span></span></span></span></p>
<p>For large <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span></span></span></span>, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span></span></span></span> is close to <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span>, so</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1.04em;vertical-align:-0.0589em;"></span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.9811em;"><span class="svg-align" style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord" style="padding-left:0.833em;"><span class="mord">2</span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">2</span></span></span><span style="top:-2.9411em;"><span class="pstrut" style="height:3em;"></span><span class="hide-tail" style="min-width:0.853em;height:1.08em;"><svg xmlns="http://www.w3.org/2000/svg" width="400em" height="1.08em" viewBox="0 0 400000 1080" preserveAspectRatio="xMinYMin slice"><path d="M95,702
c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14
c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54
c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10
s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429
c69,-144,104.5,-217.7,106.5,-221
l0 -0
c5.3,-9.3,12,-14,20,-14
H400000v40H845.2724
s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7
c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z
M834 80h400000v40h-400000z"/></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.0589em;"><span></span></span></span></span></span><span class="mord">.</span></span></span></span></span></p>
<p>Because <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.04em;vertical-align:-0.1078em;"></span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.9322em;"><span class="svg-align" style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord" style="padding-left:0.833em;"><span class="mord">2</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">2</span></span></span><span style="top:-2.8922em;"><span class="pstrut" style="height:3em;"></span><span class="hide-tail" style="min-width:0.853em;height:1.08em;"><svg xmlns="http://www.w3.org/2000/svg" width="400em" height="1.08em" viewBox="0 0 400000 1080" preserveAspectRatio="xMinYMin slice"><path d="M95,702
c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14
c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54
c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10
s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429
c69,-144,104.5,-217.7,106.5,-221
l0 -0
c5.3,-9.3,12,-14,20,-14
H400000v40H845.2724
s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7
c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z
M834 80h400000v40h-400000z"/></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.1078em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1.18</span></span></span></span>, this is often written as</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1.04em;vertical-align:-0.1908em;"></span><span class="mord">1.2</span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8492em;"><span class="svg-align" style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord" style="padding-left:0.833em;"><span class="mord mathnormal">m</span></span></span><span style="top:-2.8092em;"><span class="pstrut" style="height:3em;"></span><span class="hide-tail" style="min-width:0.853em;height:1.08em;"><svg xmlns="http://www.w3.org/2000/svg" width="400em" height="1.08em" viewBox="0 0 400000 1080" preserveAspectRatio="xMinYMin slice"><path d="M95,702
c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14
c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54
c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10
s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429
c69,-144,104.5,-217.7,106.5,-221
l0 -0
c5.3,-9.3,12,-14,20,-14
H400000v40H845.2724
s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7
c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z
M834 80h400000v40h-400000z"/></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.1908em;"><span></span></span></span></span></span><span class="mord">.</span></span></span></span></span></p>
<p>That is the square-root rule: a collision becomes likely after roughly <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.04em;vertical-align:-0.2397em;"></span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8003em;"><span class="svg-align" style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord" style="padding-left:0.833em;"><span class="mord mathnormal">m</span></span></span><span style="top:-2.7603em;"><span class="pstrut" style="height:3em;"></span><span class="hide-tail" style="min-width:0.853em;height:1.08em;"><svg xmlns="http://www.w3.org/2000/svg" width="400em" height="1.08em" viewBox="0 0 400000 1080" preserveAspectRatio="xMinYMin slice"><path d="M95,702
c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14
c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54
c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10
s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429
c69,-144,104.5,-217.7,106.5,-221
l0 -0
c5.3,-9.3,12,-14,20,-14
H400000v40H845.2724
s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7
c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z
M834 80h400000v40h-400000z"/></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2397em;"><span></span></span></span></span></span></span></span></span> keys, not <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span></span></span></span> keys. For <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">365</span></span></span></span>, this gives</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.04em;vertical-align:-0.0839em;"></span><span class="mord">1.2</span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.9561em;"><span class="svg-align" style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord" style="padding-left:0.833em;"><span class="mord">365</span></span></span><span style="top:-2.9161em;"><span class="pstrut" style="height:3em;"></span><span class="hide-tail" style="min-width:0.853em;height:1.08em;"><svg xmlns="http://www.w3.org/2000/svg" width="400em" height="1.08em" viewBox="0 0 400000 1080" preserveAspectRatio="xMinYMin slice"><path d="M95,702
c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14
c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54
c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10
s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429
c69,-144,104.5,-217.7,106.5,-221
l0 -0
c5.3,-9.3,12,-14,20,-14
H400000v40H845.2724
s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7
c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z
M834 80h400000v40h-400000z"/></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.0839em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8389em;vertical-align:-0.1944em;"></span><span class="mord">23</span><span class="mpunct">,</span></span></span></span></span></p>
<p>which matches the birthday table. For a table with one million slots, the halfway point is only about</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.24em;vertical-align:-0.2811em;"></span><span class="mord">1.2</span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.9589em;"><span class="svg-align" style="top:-3.2em;"><span class="pstrut" style="height:3.2em;"></span><span class="mord" style="padding-left:1em;"><span class="mord">1</span><span class="mord"><span class="mpunct">,</span></span><span class="mord">000</span><span class="mord"><span class="mpunct">,</span></span><span class="mord">000</span></span></span><span style="top:-2.9189em;"><span class="pstrut" style="height:3.2em;"></span><span class="hide-tail" style="min-width:1.02em;height:1.28em;"><svg xmlns="http://www.w3.org/2000/svg" width="400em" height="1.28em" viewBox="0 0 400000 1296" preserveAspectRatio="xMinYMin slice"><path d="M263,681c0.7,0,18,39.7,52,119
c34,79.3,68.167,158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120
c340,-704.7,510.7,-1060.3,512,-1067
l0 -0
c4.7,-7.3,11,-11,19,-11
H40000v40H1012.3
s-271.3,567,-271.3,567c-38.7,80.7,-84,175,-136,283c-52,108,-89.167,185.3,-111.5,232
c-22.3,46.7,-33.8,70.3,-34.5,71c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1
s-109,-253,-109,-253c-72.7,-168,-109.3,-252,-110,-252c-10.7,8,-22,16.7,-34,26
c-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26s76,-59,76,-59s76,-60,76,-60z
M1001 80h400000v40h-400000z"/></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2811em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1200</span></span></span></span></span></p>
<p>keys.</p>
<h2 id="load-factor-and-keeping-collisions-rare" tabindex="-1"><a href="https://madooei.com/posts/birthday-collisions/#load-factor-and-keeping-collisions-rare" class="header-anchor">Load factor and keeping collisions rare</a></h2>
<p>The birthday calculation explains when the <em>first</em> collision becomes likely. Hash table performance is a slightly different question. A real hash table does not need zero collisions. It needs collisions to stay controlled.</p>
<p>To see what &quot;controlled&quot; means, count colliding pairs. Among <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span> keys, there are</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.4em;vertical-align:-0.95em;"></span><span class="mord"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.1076em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.113em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p>
<p>pairs of keys. For any one pair, the probability that both keys land in the same slot is <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1/</span><span class="mord mathnormal">m</span></span></span></span>.</p>
<p>The expected value of a random quantity is its long-run average: if you built many hash tables under the same assumptions and averaged the number of colliding pairs, that average would approach the expected value. Since each pair has probability <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1/</span><span class="mord mathnormal">m</span></span></span></span> of colliding, adding those probabilities over all pairs gives the expected number of colliding pairs:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.113em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span><span class="mord mathnormal">m</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mord">1</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.1771em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.4911em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span><span class="mord mathnormal">m</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>This number grows quickly if <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span></span></span></span> is fixed and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span> keeps increasing. But hash tables do not keep <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span></span></span></span> fixed forever. They grow the array as more keys are inserted.</p>
<p>The quantity that controls the average crowding is the ratio of keys to slots, called the <em>load factor</em>:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1.7936em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.1076em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">m</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>The load factor is the average number of keys per slot. If <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span></span></span></span> is a small constant, each slot holds only a constant number of keys on average. In a chaining hash table, that means a lookup goes to one slot and checks a short list on average. In an open-addressing hash table, the details are different, but the same principle remains: performance depends strongly on keeping the table from becoming too crowded.</p>
<p>If <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span></span></span></span> is allowed to grow with <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span>, slots get crowded and lookups slow down. If <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span></span></span></span> is kept below a fixed bound, such as <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0.75</span></span></span></span>, the average amount of crowding stays bounded. That is what supports average-case <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0278em;">O</span><span class="mopen">(</span><span class="mord">1</span><span class="mclose">)</span></span></span></span> lookup under the uniform hashing assumption.</p>
<p>So a hash table watches its load factor. When <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span> grows and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span></span></span></span> passes the chosen bound, the table allocates a larger array and re-inserts every key, which drops <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span></span></span></span> back down.</p>
<p>This does not mean the total number of collisions in a large table is constant. If the table stores many keys, there may be many colliding pairs overall. The important point is local: the average amount of work per operation stays small because each key only has to deal with a bounded amount of crowding on average.</p>
<h2 id="what-this-means-for-a-hash-table" tabindex="-1"><a href="https://madooei.com/posts/birthday-collisions/#what-this-means-for-a-hash-table" class="header-anchor">What this means for a hash table</a></h2>
<p>Collisions are not a rare accident to be handled as an afterthought. The birthday paradox shows that the first collision appears while the table is still mostly empty. The pair count shows why crowding grows quickly if the table size is fixed. Load factor explains why resizing works: as the number of keys grows, the table grows too, keeping the average crowding per slot under control.</p>
<p>A working hash table needs both pieces. It needs a way to resolve collisions when they happen, and it needs a resizing rule that keeps the load factor bounded. Neither one alone is enough.</p>
]]>
      </content:encoded>
      <pubDate>Fri, 10 Jul 2026 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>Adding and Reading Papers</title>
      <link>https://madooei.com/posts/literature-vault/adding-papers/</link>
      <guid isPermaLink="false">https://madooei.com/posts/literature-vault/adding-papers/</guid>
      <content:encoded>
        <![CDATA[<h1>Adding and Reading Papers</h1>
<p>In the previous post, I set up the database module: a <code>connect()</code> function that opens a SQLite file and an <code>init_db()</code> function that creates the <code>papers</code> table. The module could create the table, but it could not yet do anything with it.</p>
<p>In this post, I want to add the first real database operations: inserting a paper record and reading it back. I am still going to pass the fingerprint in by hand, like I did before. Computing a real fingerprint from a PDF is its own topic, and I want to get the read-and-write path working first.</p>
<p>There is one decision in this post that is more interesting than it looks, and it is the reason I am doing insert before anything else: what should happen when I add the same paper twice?</p>
<h2 id="adding-a-paper" tabindex="-1"><a href="https://madooei.com/posts/literature-vault/adding-papers/#adding-a-paper" class="header-anchor">Adding a paper</a></h2>
<p>Let's start with the insert. Add this function to <code>src/literature_vault/db.py</code>:</p>
<pre><code class="language-python">def add_paper(
    connection: sqlite3.Connection,
    fingerprint: str,
    path: str,
    title: str | None = None,
    year: int | None = None,
) -&gt; bool:
    cursor = connection.execute(
        &quot;&quot;&quot;
        INSERT INTO papers (fingerprint, path, title, year)
        VALUES (:fingerprint, :path, :title, :year)
        ON CONFLICT (fingerprint) DO NOTHING
        &quot;&quot;&quot;,
        {
            &quot;fingerprint&quot;: fingerprint,
            &quot;path&quot;: path,
            &quot;title&quot;: title,
            &quot;year&quot;: year,
        },
    )
    connection.commit()
    return cursor.rowcount == 1
</code></pre>
<p>The function takes the connection and the fields for one paper. The <code>title</code> and <code>year</code> are optional, because there will be papers where I do not have that metadata yet. It runs an <code>INSERT</code>, commits, and returns a boolean.</p>
<p>A couple of things here are worth slowing down on.</p>
<p>The first is how I pass the values. Instead of putting the data directly into the SQL string, I use named placeholders like <code>:fingerprint</code> and hand the actual values in a separate dictionary. SQLite fills them in for me. This is the standard way to avoid SQL injection, and it also means I do not have to worry about quoting strings or escaping characters myself. The same idea works with <code>?</code> placeholders and a tuple, but I find the named version easier to read once there are more than two or three columns.</p>
<p>The second is the <code>ON CONFLICT (fingerprint) DO NOTHING</code> clause, which is the heart of this post.</p>
<h2 id="what-happens-when-i-add-the-same-paper-twice" tabindex="-1"><a href="https://madooei.com/posts/literature-vault/adding-papers/#what-happens-when-i-add-the-same-paper-twice" class="header-anchor">What happens when I add the same paper twice</a></h2>
<p>Back in the overview, I said I wanted <code>lv add</code> to be idempotent: if I add the same paper twice, the system should notice it has seen it before and skip it. The <code>papers</code> table already has the piece that makes this possible, which is the <code>UNIQUE</code> constraint on <code>fingerprint</code>. SQLite will not let me store two rows with the same fingerprint.</p>
<p>The question is what happens when I try anyway. By default, SQLite treats it as an error and raises an exception. That is not what I want for ingestion. Adding a paper I already have is a normal thing to do, not a failure.</p>
<p>So I have a few options:</p>
<ul>
<li>Catch the exception. Let the <code>INSERT</code> fail and wrap it in a <code>try</code>/<code>except</code> for <code>sqlite3.IntegrityError</code>. This works, but it uses an exception for something that is not really an error, and it makes the normal &quot;already seen&quot; path go through error handling.</li>
<li>Use <code>INSERT OR IGNORE</code>. This tells SQLite to silently skip the row on any constraint violation. It is short, but it is also blunt: it ignores <em>every</em> constraint, so if I later add a constraint I actually want to hear about, this would swallow it too.</li>
<li>Use <code>ON CONFLICT (fingerprint) DO NOTHING</code>. This says exactly which conflict I am choosing to ignore. If a row with this fingerprint already exists, do nothing. Any other problem still raises.</li>
</ul>
<p>I went with the last one. It is the most explicit: anyone reading the function can see that the duplicate-fingerprint case is handled on purpose, and that nothing else is being quietly swallowed.</p>
<p>That leaves one loose end. If the insert quietly does nothing on a duplicate, how does the caller know whether the paper was new or already there? That is what the return value is for. After the statement runs, <code>cursor.rowcount</code> tells me how many rows were actually inserted: <code>1</code> if it was new, <code>0</code> if the conflict skipped it. So <code>add_paper</code> returns <code>True</code> when it added a new paper and <code>False</code> when the paper was already in the vault. Later, the <code>add</code> command can use that to print &quot;added&quot; or &quot;already in vault&quot; without doing a separate lookup first.</p>
<h2 id="reading-a-paper-back" tabindex="-1"><a href="https://madooei.com/posts/literature-vault/adding-papers/#reading-a-paper-back" class="header-anchor">Reading a paper back</a></h2>
<p>I also want to read a paper back out, so I can confirm it is really there and so the rest of the app has a way to look one up. Add this function next:</p>
<pre><code class="language-python">def get_paper(
    connection: sqlite3.Connection, fingerprint: str
) -&gt; sqlite3.Row | None:
    return connection.execute(
        &quot;&quot;&quot;
        SELECT id, fingerprint, path, title, year, created_at
        FROM papers
        WHERE fingerprint = :fingerprint
        &quot;&quot;&quot;,
        {&quot;fingerprint&quot;: fingerprint},
    ).fetchone()
</code></pre>
<p>This looks a paper up by its fingerprint and returns the row, or <code>None</code> if there is no match. The <code>fetchone()</code> call returns the first matching row, and since <code>fingerprint</code> is unique there is at most one. Because I set <code>row_factory = sqlite3.Row</code> back in <code>connect()</code>, the row I get back lets me read columns by name, so the caller can write <code>paper[&quot;title&quot;]</code> instead of counting column positions.</p>
<p>Returning <code>None</code> when the paper is not found keeps the function simple. The caller decides what a missing paper means, which is usually different in different places: a lookup might want to print an error, while an &quot;is this already here?&quot; check just wants the absence.</p>
<h2 id="testing-it" tabindex="-1"><a href="https://madooei.com/posts/literature-vault/adding-papers/#testing-it" class="header-anchor">Testing it</a></h2>
<p>Now I can test the two functions together, since reading back is how I check that writing worked. Add these to <code>src/tests/test_db.py</code>.</p>
<p>First, the basic round trip: add a paper, read it back, and check the fields survived.</p>
<pre><code class="language-python">def test_add_paper_inserts_and_reads_back(tmp_path: Path) -&gt; None:
    db_path = tmp_path / &quot;vault.db&quot;
    connection = connect(db_path)

    try:
        init_db(connection)

        is_new = add_paper(
            connection,
            fingerprint=&quot;abc123&quot;,
            path=&quot;/papers/attention.pdf&quot;,
            title=&quot;Attention Is All You Need&quot;,
            year=2017,
        )

        assert is_new is True

        paper = get_paper(connection, &quot;abc123&quot;)

        assert paper is not None
        assert paper[&quot;fingerprint&quot;] == &quot;abc123&quot;
        assert paper[&quot;path&quot;] == &quot;/papers/attention.pdf&quot;
        assert paper[&quot;title&quot;] == &quot;Attention Is All You Need&quot;
        assert paper[&quot;year&quot;] == 2017
    finally:
        connection.close()
</code></pre>
<p>This uses the same <code>tmp_path</code> fixture as the previous post, so each test gets its own throwaway database file. It adds one paper, checks that <code>add_paper</code> reported it as new, then reads it back and checks every field.</p>
<p>The next test is the one I actually care about: adding the same fingerprint twice.</p>
<pre><code class="language-python">def test_add_paper_is_idempotent(tmp_path: Path) -&gt; None:
    db_path = tmp_path / &quot;vault.db&quot;
    connection = connect(db_path)

    try:
        init_db(connection)

        first = add_paper(
            connection,
            fingerprint=&quot;abc123&quot;,
            path=&quot;/papers/attention.pdf&quot;,
            title=&quot;Attention Is All You Need&quot;,
            year=2017,
        )
        second = add_paper(
            connection,
            fingerprint=&quot;abc123&quot;,
            path=&quot;/papers/moved.pdf&quot;,
            title=&quot;A Different Title&quot;,
            year=2020,
        )

        assert first is True
        assert second is False

        # The second add was ignored, so the original row is untouched.
        paper = get_paper(connection, &quot;abc123&quot;)

        assert paper is not None
        assert paper[&quot;path&quot;] == &quot;/papers/attention.pdf&quot;
        assert paper[&quot;title&quot;] == &quot;Attention Is All You Need&quot;
        assert paper[&quot;year&quot;] == 2017
    finally:
        connection.close()
</code></pre>
<p>The second add uses the same fingerprint but different values for everything else. Two things should be true. The first add returns <code>True</code> and the second returns <code>False</code>, so the function correctly reports that it had seen the paper before. And the row in the database still has the original values, not the second set. That second part matters: <code>DO NOTHING</code> means exactly that. It does not update the existing row with the new values, it leaves it alone. If I ever want adding a known paper to update its metadata, that would be a different choice (<code>DO UPDATE</code>), and I would make it on purpose.</p>
<p>The last test covers the miss: looking up a fingerprint that was never added.</p>
<pre><code class="language-python">def test_get_paper_returns_none_when_missing(tmp_path: Path) -&gt; None:
    db_path = tmp_path / &quot;vault.db&quot;
    connection = connect(db_path)

    try:
        init_db(connection)

        assert get_paper(connection, &quot;does-not-exist&quot;) is None
    finally:
        connection.close()
</code></pre>
<p>Run the tests:</p>
<pre><code class="language-bash">uv run pytest
</code></pre>
<p>The tests from the earlier posts should still pass, and now there are three new ones for the database operations.</p>
<pre><code class="language-plaintext">9 passed
</code></pre>
<p>This is another small step, but the database can now do the two things it could not do at the end of the last post: store a paper and find it again. And it does it in a way that already matches the idempotent behavior I want from <code>lv add</code>, before there is an <code>lv add</code> to speak of.</p>
<p>I have still been passing the fingerprint and path in by hand, and these functions still live only in the database layer. Nothing in the CLI or the MCP server touches them yet. In the next post, I will wire these operations up through the core layer and expose the first real command, so that adding and listing papers works from the terminal the way <code>greet</code> does now.</p>
]]>
      </content:encoded>
      <pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>Setting up the Database Layer</title>
      <link>https://madooei.com/posts/literature-vault/hello-database/</link>
      <guid isPermaLink="false">https://madooei.com/posts/literature-vault/hello-database/</guid>
      <content:encoded>
        <![CDATA[<h1>Setting up the Database Layer</h1>
<p>In the previous post, I set up the basic dependencies for Literature Vault. In this post, I want to do the same thing for the database.</p>
<p>The goal is not to build the full storage layer yet. I am not going to parse PDFs, extract metadata, create a full-text index, or store embeddings in this post. For now, I just want to make sure the app can create a local SQLite database, write a paper record to it, and read that record back through the same kind of clean application boundary I used for the CLI and MCP examples.</p>
<p>I already decided in the project overview that Literature Vault should use SQLite. Python has built-in support for SQLite; it has a standard library module called <code>sqlite3</code>. That is enough for a simple database, and it is the right choice for a local application that does not need to scale to multiple users or servers.</p>
<p><code>sqlite3</code> requires no extra installation, but it is also a very low-level interface. We would have to write SQL statements by hand, and we would have to manage the database connection and transactions ourselves. I'm fine with that!</p>
<h2 id="creating-the-database-module" tabindex="-1"><a href="https://madooei.com/posts/literature-vault/hello-database/#creating-the-database-module" class="header-anchor">Creating the Database Module</a></h2>
<p>The first thing I want is a small database module. Not the whole storage layer, just enough structure so the rest of the app does not have to know where the database lives or how the tables are created.</p>
<p>Create a new file called <code>src/literature_vault/db.py</code>:</p>
<pre><code class="language-python">from pathlib import Path
import sqlite3


def connect(db_path: Path) -&gt; sqlite3.Connection:
    connection = sqlite3.connect(db_path)
    connection.row_factory = sqlite3.Row
    return connection


def init_db(connection: sqlite3.Connection) -&gt; None:
    connection.execute(
        &quot;&quot;&quot;
        CREATE TABLE IF NOT EXISTS papers (
            id INTEGER PRIMARY KEY,
            fingerprint TEXT NOT NULL UNIQUE,
            path TEXT NOT NULL,
            title TEXT,
            year INTEGER,
            created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
        )
        &quot;&quot;&quot;
    )
    connection.commit()
</code></pre>
<p>Let's walk through this code.</p>
<ul>
<li>
<p>The import statements are straightforward. I need <code>Path</code> to work with file paths, and I need <code>sqlite3</code> to interact with the database.</p>
</li>
<li>
<p>The <code>connect()</code> function takes a <code>Path</code> to the database file and returns a <code>sqlite3.Connection</code> object. This function is responsible for opening the connection to the database. It also sets the <code>row_factory</code> to <code>sqlite3.Row</code>, which allows us to access columns by name instead of by index (see the discussion below).</p>
</li>
<li>
<p>The <code>init_db()</code> function takes a <code>sqlite3.Connection</code> and creates the necessary tables if they do not already exist. In this case, it creates a <code>papers</code> table with the specified columns.</p>
</li>
</ul>
<p>There are two small choices here that are worth pointing out.</p>
<p>First, <code>connect()</code> takes a <code>Path</code> instead of hard-coding a database location. This keeps the function easy to test, because tests can create a temporary database file and throw it away afterward. Later, the CLI can decide where the real database should live.</p>
<p>Second, I set <code>connection.row_factory = sqlite3.Row</code>. By default, SQLite rows come back as tuples, so you have to access values by position. With <code>sqlite3.Row</code>, the rows still behave like lightweight row objects, but I can access columns by name: so you can write <code>row[&quot;title&quot;]</code> instead of <code>row[3]</code>.</p>
<p>The string passed to <code>execute()</code> in <code>init_db()</code> is a SQL statement. It creates a table called <code>papers</code> with the following columns:</p>
<ul>
<li><code>fingerprint</code>, a unique identifier for the paper</li>
<li><code>path</code>, the location of the PDF on disk</li>
<li><code>title</code>, if I know it</li>
<li><code>year</code>, if I know it</li>
<li><code>created_at</code>, when the row was created</li>
</ul>
<p>The fingerprint is the important part. Eventually, this will be a hash of the PDF contents. In this post, I am going to pass it in manually so I can focus on the database layer. The <code>UNIQUE</code> constraint means SQLite will not allow the same fingerprint to be inserted twice, which is exactly what I want for idempotent ingestion later.</p>
<p>Before adding more application code, I want to test this module. We already have a test setup from the previous post, so the next step is to add a database test file.</p>
<p>Create <code>src/tests/test_db.py</code>:</p>
<pre><code class="language-python">from pathlib import Path
from literature_vault.db import connect, init_db


def test_init_db_creates_papers_table(tmp_path: Path) -&gt; None:
    db_path = tmp_path / &quot;vault.db&quot;
    connection = connect(db_path)

    try:
        init_db(connection)

        row = connection.execute(
            &quot;&quot;&quot;
            SELECT name
            FROM sqlite_master
            WHERE type = 'table' AND name = 'papers'
            &quot;&quot;&quot;
        ).fetchone()

        assert row is not None
        assert row[&quot;name&quot;] == &quot;papers&quot;
    finally:
        connection.close()


def test_connect_returns_rows_with_named_columns(tmp_path: Path) -&gt; None:
    db_path = tmp_path / &quot;vault.db&quot;
    connection = connect(db_path)

    try:
        row = connection.execute(&quot;SELECT 'hello' AS message&quot;).fetchone()

        assert row[&quot;message&quot;] == &quot;hello&quot;
    finally:
        connection.close()
</code></pre>
<p>These tests do not insert papers yet. They only check the behavior of the database module as it exists right now:</p>
<ul>
<li><code>connect()</code> opens a SQLite database and returns rows that can be accessed by column name</li>
<li><code>init_db()</code> creates the <code>papers</code> table</li>
</ul>
<p>Run the tests:</p>
<pre><code class="language-bash">uv run pytest
</code></pre>
<p>The existing tests should still pass, and now there should be two new database tests as well.</p>
<p>This is a small step, but it gives me a useful boundary: the database module can create the first table, and the tests can verify that without touching the CLI or MCP layer yet.</p>
<p>I will stop here for this post. In the next one, I will add the first actual database operation: inserting a paper record and reading it back.</p>
]]>
      </content:encoded>
      <pubDate>Wed, 17 Jun 2026 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>Hello World</title>
      <link>https://madooei.com/posts/literature-vault/hello-world/</link>
      <guid isPermaLink="false">https://madooei.com/posts/literature-vault/hello-world/</guid>
      <content:encoded>
        <![CDATA[<h1>Hello World</h1>
<p>In this post, I will set up the basic dependencies of Literature Vault and create a simple &quot;Hello World&quot; example to demonstrate that the dependencies are working correctly.</p>
<p>We decided to:</p>
<ul>
<li>Use Python as the programming language for this project</li>
<li>Use <a href="https://typer.tiangolo.com/">Typer</a> for building the CLI</li>
<li>Use <a href="https://gofastmcp.com/">FastMCP</a> for building the MCP interface</li>
<li>Use <a href="https://www.sqlite.org/">SQLite</a> for storage, with the <code>sqlite-vec</code> extension for vector search</li>
</ul>
<p>I'm going to use <a href="https://docs.astral.sh/uv/">uv</a> as the Python package manager. It is a modern alternative to tools like <code>pip</code> and <code>poetry</code>, and it has some nice features like fast dependency resolution and built-in support for virtual environments.</p>
<p>If you want to follow along, make sure you have Python and uv installed on your machine. I'm on macOS, so I installed both of them using <a href="https://brew.sh/">Homebrew</a>:</p>
<pre><code class="language-bash">brew install python uv
</code></pre>
<p>You can check that you have them installed by running:</p>
<pre><code class="language-bash">python --version
uv --version
</code></pre>
<p>On my machine, this shows:</p>
<pre><code class="language-plaintext">Python 3.13.12
uv 0.11.21
</code></pre>
<p>I created a new directory for the project and initialized a git repository. I suggest you do the same and add a reasonable <code>.gitignore</code> file for Python projects:</p>
<pre><code># Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
dist/
*.egg-info/
*.egg
.eggs/
develop-eggs/
downloads/
eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
MANIFEST

# Virtual environments
.venv/
venv/
env/
ENV/
.env
.env.*

# uv
.uv/

# Testing / coverage
.pytest_cache/
.coverage
.coverage.*
htmlcov/
.tox/
.nox/
coverage.xml
*.cover
.hypothesis/

# Type checkers / linters
.mypy_cache/
.dmypy.json
dmypy.json
.ruff_cache/
.pyre/
.pytype/

# Jupyter
.ipynb_checkpoints/

# IDEs / editors
.idea/
.vscode/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db
</code></pre>
<p>Next, I initialized a new Python project using <code>uv</code>:</p>
<pre><code class="language-bash">uv init --package --name literature-vault
</code></pre>
<p>This creates this directory structure:</p>
<pre><code class="language-plaintext">.
├── pyproject.toml
├── README.md
└── src
    └── literature_vault
        └── __init__.py
</code></pre>
<p>The <code>pyproject.toml</code> file is where uv tracks the project metadata and dependencies. Let's install the dependencies we need for this project:</p>
<pre><code class="language-bash">uv add typer fastmcp
</code></pre>
<p>We need a few development dependencies too, for testing and linting:</p>
<pre><code class="language-bash">uv add --dev pytest ruff
</code></pre>
<p><a href="https://docs.pytest.org/">pytest</a> is a popular testing framework for Python, and <a href="https://docs.astral.sh/ruff/">ruff</a> is a fast Python linter and code formatter.</p>
<p>We can do a quick test from the terminal to make sure this all works:</p>
<pre><code class="language-bash">uv run python -c &quot;import typer, fastmcp; print('stack ok')&quot;
</code></pre>
<p>On my machine, this prints: <code>stack ok</code>, which means the dependencies are installed correctly and we can import them without any issues.</p>
<p>In my case, uv set a very new Python requirement in <code>pyproject.toml</code>, so I changed it:</p>
<pre><code class="language-diff">- requires-python = &quot;&gt;=3.14&quot;
+ requires-python = &quot;&gt;=3.12&quot;
</code></pre>
<p>The <code>&gt;=3.14</code> requirement is surprisingly aggressive. Python 3.14 is not a stable baseline for a normal project yet. Python 3.12 is a much more reasonable minimum version, and it still has all the features we need for this project.</p>
<p>Now run <code>uv sync</code> to update the lock file with this change.</p>
<p>Next, run the project using <code>uv run</code>:</p>
<pre><code class="language-bash">uv run literature-vault
</code></pre>
<p>The <code>literature-vault</code> command is created automatically by uv based on the package name. In <code>pyproject.toml</code>, uv wires that command to a Python function:</p>
<pre><code class="language-toml">[project.scripts]
literature-vault = &quot;literature_vault:main&quot;
</code></pre>
<p>That means the command imports the <code>literature_vault</code> package and calls its <code>main</code> function. For now, that function lives in <code>src/literature_vault/__init__.py</code>, which uv also created automatically:</p>
<pre><code class="language-python">def main() -&gt; None:
    print(&quot;Hello from literature-vault!&quot;)
</code></pre>
<p>So when you run <code>uv run literature-vault</code>, it executes the <code>main</code> function and prints &quot;Hello from literature-vault!&quot; to the terminal.</p>
<h2 id="hello-cli" tabindex="-1"><a href="https://madooei.com/posts/literature-vault/hello-world/#hello-cli" class="header-anchor">Hello CLI</a></h2>
<p>Let's wire up the Typer CLI now. The idea is to keep the application logic separate from the CLI code, so that we can reuse the logic in different contexts (e.g., in the MCP server) without duplicating it.</p>
<p>Create a new file, <code>src/literature_vault/core.py</code>, and put this in it:</p>
<pre><code class="language-python">def hello(name: str = &quot;world&quot;) -&gt; str:
    return f&quot;Hello, {name}!&quot;
</code></pre>
<p>Now create another file, <code>src/literature_vault/cli.py</code>, with the following content:</p>
<pre><code class="language-python">import typer
from literature_vault.core import hello

app = typer.Typer()


@app.callback()
def main() -&gt; None:
    &quot;&quot;&quot;Literature Vault command line interface.&quot;&quot;&quot;


@app.command()
def greet(name: str = typer.Argument(&quot;world&quot;)) -&gt; None:
    typer.echo(hello(name))
</code></pre>
<p>This is the Typer layer. It imports the plain function and decides how to expose it in the terminal. Let's break down the file:</p>
<ul>
<li>We import <code>typer</code> and the <code>hello</code> function from <code>core.py</code>.</li>
<li>We create a <code>Typer</code> app instance.</li>
<li>We define a callback using the <code>@app.callback()</code> decorator. This gives the CLI a top-level entry point and makes Typer treat the app as a group of commands.</li>
<li>We define a command using the <code>@app.command()</code> decorator. The function <code>greet</code> is the command handler, and it takes a <code>name</code> argument that defaults to &quot;world&quot;.</li>
<li>The <code>typer.Argument(&quot;world&quot;)</code> part tells Typer the command will take an argument called <code>name</code>, and if the user doesn't provide it, it will default to &quot;world&quot;. This also allows Typer to generate help text for the command.</li>
<li>Inside the command, we call the <code>hello</code> function and print its result using <code>typer.echo()</code>.</li>
</ul>
<p>The callback may look unnecessary right now, but it gives us the CLI shape we want for this project. Literature Vault will eventually have commands like <code>lv add</code>, <code>lv search</code>, and <code>lv list</code>, so it is better to start with an explicit command group instead of a single top-level command.</p>
<p>Now open <code>pyproject.toml</code> and change this:</p>
<pre><code class="language-diff">  [project.scripts]
- literature-vault = &quot;literature_vault:main&quot;
+ lv = &quot;literature_vault.cli:app&quot;
</code></pre>
<p>I made two changes here:</p>
<ul>
<li>I changed the command name from <code>literature-vault</code> to <code>lv</code>, which is the name I wanted for the CLI.</li>
<li>I changed the target from <code>literature_vault:main</code> to <code>literature_vault.cli:app</code>, which tells uv to import the <code>app</code> object from <code>literature_vault/cli.py</code> and run it when someone runs <code>lv</code>.</li>
</ul>
<p>Now run:</p>
<pre><code class="language-bash">uv run lv greet Ali
</code></pre>
<p>You should see:</p>
<pre><code class="language-plaintext">Hello, Ali!
</code></pre>
<p>Also try:</p>
<pre><code class="language-bash">uv run lv --help
</code></pre>
<p>You should see the top-level help text generated by Typer, including the <code>greet</code> command.</p>
<pre><code class="language-plaintext">
 Usage: lv [OPTIONS] COMMAND [ARGS]...

 Literature Vault command line interface.

╭─ Commands ────────────────────────────────────────────────────────╮
│ greet                                                             │
╰───────────────────────────────────────────────────────────────────╯
</code></pre>
<p>You can also ask for help for the <code>greet</code> command:</p>
<pre><code class="language-bash">uv run lv greet --help
</code></pre>
<p>That help text shows the <code>name</code> argument and its default value.</p>
<pre><code class="language-plaintext"> Usage: lv greet [OPTIONS] [NAME]

╭─ Arguments ───────────────────────────────────────────────────────╮
│   name      [NAME]  [default: world]                              │
╰───────────────────────────────────────────────────────────────────╯
╭─ Options ─────────────────────────────────────────────────────────╮
│ --help          Show this message and exit.                       │
╰───────────────────────────────────────────────────────────────────╯
</code></pre>
<p>That is the first real payoff from Typer: because the function has a typed parameter, Typer can generate command-line help from it.</p>
<h2 id="hello-mcp" tabindex="-1"><a href="https://madooei.com/posts/literature-vault/hello-world/#hello-mcp" class="header-anchor">Hello MCP</a></h2>
<p>Now let's expose the same <code>hello</code> function through MCP. This is the reason we put the application logic in <code>core.py</code> instead of writing it directly inside the Typer command. The CLI and the MCP server should both be thin wrappers around the same underlying Python function.</p>
<p>Create a new file, <code>src/literature_vault/mcp_server.py</code>, with the following content:</p>
<pre><code class="language-python">from fastmcp import FastMCP

from literature_vault.core import hello

mcp = FastMCP(&quot;Literature Vault&quot;)


@mcp.tool
def greet(name: str = &quot;world&quot;) -&gt; str:
    return hello(name)


if __name__ == &quot;__main__&quot;:
    mcp.run()
</code></pre>
<p>This should feel very similar to the Typer file:</p>
<ul>
<li>We import the same <code>hello</code> function from <code>core.py</code>.</li>
<li>We create a FastMCP server named <code>Literature Vault</code>.</li>
<li>We decorate a normal Python function with <code>@mcp.tool</code> to expose it as an MCP tool.</li>
<li>Inside the tool, we call the same core function that the CLI uses.</li>
</ul>
<p>At this point, the structure is exactly what we wanted:</p>
<pre><code class="language-plaintext">src/literature_vault
├── __init__.py
├── cli.py
├── core.py
└── mcp_server.py
</code></pre>
<p>The important part is that <code>core.py</code> does not know anything about Typer or FastMCP. It is just Python code. The interface-specific files import that code and expose it in different ways.</p>
<p>Now let's test the MCP server with the official <a href="https://modelcontextprotocol.io/docs/tools/inspector">MCP Inspector</a>. The Inspector is a local browser UI for testing and debugging MCP servers. It lets us see the tools exposed by the server and call them manually, without wiring the server into Claude Desktop, Cursor, or another MCP host yet.</p>
<p>The Inspector runs through <code>npx</code>, so you need <a href="https://nodejs.org/en">Node.js</a> installed.</p>
<p>Then launch the Inspector from the project directory:</p>
<pre><code class="language-bash">npx -y @modelcontextprotocol/inspector uv run python -m literature_vault.mcp_server
</code></pre>
<p>This opens the Inspector UI in your browser.</p>
<p><img src="https://madooei.com/posts/literature-vault/hello-world/2026-06-15-22-38-57.png" alt=""></p>
<p>The left sidebar should already be filled in with:</p>
<pre><code class="language-plaintext">Transport Type: STDIO
Command: uv
Arguments: run python -m literature_vault.mcp_server
</code></pre>
<p>Click <code>Connect</code>. This starts the MCP server process and connects the Inspector to it.</p>
<p><img src="https://madooei.com/posts/literature-vault/hello-world/2026-06-15-22-39-50.png" alt=""></p>
<p>After it connects, use the Inspector to call the tool:</p>
<ul>
<li>Open the <code>Tools</code> tab.</li>
<li>Click <code>List Tools</code> if the tools are not shown yet.</li>
<li>Select the <code>greet</code> tool.</li>
<li>Enter <code>Ali</code> for the <code>name</code> argument.</li>
<li>Run the tool.</li>
</ul>
<p><img src="https://madooei.com/posts/literature-vault/hello-world/2026-06-15-22-42-09.png" alt=""></p>
<p>You should see the tool return:</p>
<pre><code class="language-plaintext">Hello, Ali!
</code></pre>
<p><img src="https://madooei.com/posts/literature-vault/hello-world/2026-06-15-22-42-28.png" alt=""></p>
<p>Now the same application logic works through two different interfaces:</p>
<pre><code class="language-bash">uv run lv greet Ali
</code></pre>
<p>and:</p>
<pre><code class="language-plaintext">MCP Inspector -&gt; Tools -&gt; greet
</code></pre>
<p>That is the architectural pattern I want for the rest of Literature Vault.</p>
<p>You can stop the MCP server by pressing <code>Ctrl+C</code> in the terminal where you ran the <code>npx</code> command. The Inspector will show that the connection was lost.</p>
<h2 id="hello-tests" tabindex="-1"><a href="https://madooei.com/posts/literature-vault/hello-world/#hello-tests" class="header-anchor">Hello Tests</a></h2>
<p>We also installed <code>pytest</code>, so let's add a small test before wrapping up.</p>
<p>Create a new directory called <code>tests</code>. For this project, I want the tests to follow the same boundaries as the source code:</p>
<ul>
<li><code>core.py</code> contains application logic, so it gets its own tests.</li>
<li><code>cli.py</code> contains the Typer interface, so it gets its own tests.</li>
<li><code>mcp_server.py</code> contains the MCP interface, so it gets its own tests.</li>
</ul>
<p>The test directory should look like this:</p>
<pre><code class="language-plaintext">.
├── src
│   └── literature_vault
│       ├── __init__.py
│       ├── cli.py
│       ├── core.py
│       └── mcp_server.py
└── tests
    ├── test_cli.py
    ├── test_core.py
    └── test_mcp_server.py
</code></pre>
<p>This does not need to mechanically copy the full <code>src/literature_vault</code> directory structure yet. For now, a flat <code>tests</code> directory with one test file per source module is simple and readable. If the project grows much larger, I can always move to a nested structure like <code>tests/literature_vault/test_core.py</code>.</p>
<p>Put this in <code>tests/test_core.py</code>:</p>
<pre><code class="language-python">from literature_vault.core import hello


def test_hello_default() -&gt; None:
    assert hello() == &quot;Hello, world!&quot;


def test_hello_with_name() -&gt; None:
    assert hello(&quot;Ali&quot;) == &quot;Hello, Ali!&quot;
</code></pre>
<p>These tests check the plain Python function directly. They do not know anything about Typer or MCP.</p>
<p>Now put this in <code>tests/test_cli.py</code>:</p>
<pre><code class="language-python">from typer.testing import CliRunner

from literature_vault.cli import app

runner = CliRunner()


def test_greet_command() -&gt; None:
    result = runner.invoke(app, [&quot;greet&quot;, &quot;Ali&quot;])

    assert result.exit_code == 0
    assert result.output == &quot;Hello, Ali!\n&quot;
</code></pre>
<p>This test checks the Typer layer. It does not call <code>hello</code> directly. It calls the CLI the way a user would: through the <code>greet</code> command.</p>
<p>Finally, put this in <code>tests/test_mcp_server.py</code>:</p>
<pre><code class="language-python">import asyncio

from fastmcp import Client

from literature_vault.mcp_server import mcp


def test_greet_tool() -&gt; None:
    async def call_tool() -&gt; str:
        async with Client(mcp) as client:
            result = await client.call_tool(&quot;greet&quot;, {&quot;name&quot;: &quot;Ali&quot;})
            return result.data

    assert asyncio.run(call_tool()) == &quot;Hello, Ali!&quot;
</code></pre>
<p>This test checks the MCP layer. The MCP Inspector is great for manual testing, but for an automated test suite we want something that can run in the terminal. FastMCP's test client lets us call the MCP tool directly without opening a browser.</p>
<p>Now run the tests:</p>
<pre><code class="language-bash">uv run pytest
</code></pre>
<p>You should see all four tests pass:</p>
<pre><code class="language-plaintext">4 passed
</code></pre>
<p>This is still a tiny test suite, but it is enough for this stage. It verifies the main design decision of this post: the same core function can be used directly, through the CLI, and through MCP. Later, when <code>hello</code> turns into real functionality like <code>add</code> and <code>search</code>, we can keep this same testing pattern.</p>
<p>I have not touched SQLite yet. That is intentional. This post was about getting the Python project, CLI, MCP server, and tests in place. In the next post, I will start the storage layer and bring in the SQLite-related pieces when there is actually something to test against.</p>
]]>
      </content:encoded>
      <pubDate>Mon, 15 Jun 2026 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>Project Overview</title>
      <link>https://madooei.com/posts/literature-vault/overview/</link>
      <guid isPermaLink="false">https://madooei.com/posts/literature-vault/overview/</guid>
      <content:encoded>
        <![CDATA[<h1>Literature Vault: Project Overview</h1>
<p>I'm planning to build &quot;Literature Vault&quot; — a local search engine for research papers stored as PDFs on my machine. It is meant to ingest and index the content of these PDFs and allow search with keywords or natural language through a simple CLI and MCP. It would be ideal for agentic flows.</p>
<p>If I were doing my PhD again, I would be building something like this. I recently signed a contract to write a book on AI and STEM education, so I'm building this to help with the research for the book, for my own use. I'll document the process of building it here too, in case it's useful to others, and I'll share the code on GitHub when it's ready.</p>
<p>This is not a &quot;chat-with-your-PDF&quot; tool. Those tools exist! For example, Google's NotebookLM lets you upload your PDFs and then ask questions about them. But NotebookLM is more of a synthesis tool, and that is a layer one can build on top of my literature vault. Besides, I prefer to do that kind of work myself (let the human do some of the work).</p>
<p>I want to be able to run this entirely on-device, without relying on any AI service providers. I know it's possible, but at the moment I'm not sure whether it's feasible on modest hardware. I'll figure it out as I go, and I'll try to build it in a modular way so that I can swap out components as needed.</p>
<p>There are two main components to this system: the <em>ingestion</em> pipeline and the <em>search</em> engine. I'm going to jot down some thoughts on each of these components here, since it helps me organize my ideas. These may change as I go, and that's fine.</p>
<h2 id="search" tabindex="-1"><a href="https://madooei.com/posts/literature-vault/overview/#search" class="header-anchor">Search</a></h2>
<p>I want three modes of search: keyword, semantic, and hybrid.</p>
<p>The <strong>keyword search</strong> is plain full-text search. This is the classic approach, from before embeddings, and it's still the standard today. It is not just the exact string match that you get when you press Ctrl+F in a PDF viewer. It will be more like the search you get in Google Scholar, which includes stemming, stop-word removal, and other NLP techniques to make it more effective.</p>
<p>The <strong>semantic search</strong> is what we got in the era of LLMs. The process is to break the papers into smaller chunks (e.g., paragraphs), turn those into a numerical representation (embedding) using a language model, and then store those embeddings in a vector database. The idea is that the &quot;vector&quot; (a numerical representation of the text) captures the meaning (semantics) of the text, so that similar meanings will have similar vectors, even if they use different words. When I search, I will also turn my query into an embedding and then find the passages whose embeddings are closest to the query embedding in the vector space (vector search). This is the part that lets you search in natural language.</p>
<p>So you might think: now that we can do semantic search, why do we need keyword search? Well, semantic search can miss some things that keyword search would catch. For example, if I search for exact phrases or specific technical terms, keyword search will certainly find those, while semantic search might not if those terms get diluted in the embedding. So the common wisdom is to use <strong>hybrid search</strong>, which combines the keyword and semantic search. It runs both of them and then combines the rankings. For example, it might take the top 100 results from each search and then re-rank them based on some combination of their keyword relevance and their semantic relevance to the query.</p>
<p>I don't want three separate commands for this. They're really the same thing: I type a query, I get back a ranked list of passages. So I'll make it one <code>search</code> command with a <code>--mode</code> flag.</p>
<pre><code class="language-plaintext">lv search &quot;attention in transformers&quot;        # hybrid by default
lv search --mode keyword &quot;transformer architecture&quot;
lv search --mode semantic &quot;how models handle long context&quot;
</code></pre>
<p>The <code>lv</code> is the tentative name for the CLI tool.</p>
<p>A few things I'm deciding early:</p>
<ul>
<li>Hybrid is the default, so a plain <code>lv search &quot;...&quot;</code> just does the sensible thing without me picking a mode.</li>
<li>The results are passages with some ID that we can use to retrieve the paper (its metadata and location on disk) later.</li>
<li>We should have <code>--json</code> and <code>--files</code> output formats that are more machine-readable, for use in agentic flows.</li>
<li>We should have some other flags for controlling the search, like how many results to return, whether to restrict the search based on certain metadata (e.g., only papers from 2020-2022), etc.</li>
</ul>
<h2 id="ingestion" tabindex="-1"><a href="https://madooei.com/posts/literature-vault/overview/#ingestion" class="header-anchor">Ingestion</a></h2>
<p>Before I can search anything, I need to get the papers into the vault. This is the ingestion side.</p>
<p>The first thing is to figure out what a paper <em>is</em>, as far as the system is concerned. I think the right move is to give each paper a fingerprint by hashing its content. That gives me a stable ID, and it also solves a practical problem: if I add the same paper twice, the system can tell it has seen it before and skip it. So <code>lv add</code> becomes idempotent almost for free. The fingerprint is also what <code>lv remove</code> and <code>lv list</code> refer to when they talk about a paper.</p>
<p>The next thing is to get the text out of the PDF. This is harder than it sounds, because PDFs are messy, but it's a solved problem and I don't need to solve it myself. I'll treat text extraction as a component I plug in, so I can start with something simple and swap in a better extractor later without touching the rest of the system. The same goes for pulling out metadata like the title, authors, and year, which I'll need for <code>lv list</code> and for the metadata filters on search.</p>
<p>Once I have the text, the rest of ingestion is a pipeline that turns it into the things search needs. It chunks the paper into passages, builds the keyword index over them, computes the embeddings, and stores everything alongside the paper's fingerprint and the location of each passage. When that pipeline finishes, the paper is searchable. That's really all &quot;ingested&quot; means here: the paper has been fingerprinted, its text extracted, and its passages indexed for both kinds of search.</p>
<h2 id="tech-stack" tabindex="-1"><a href="https://madooei.com/posts/literature-vault/overview/#tech-stack" class="header-anchor">Tech stack</a></h2>
<p>I'm going to build this in Python, since the libraries for embeddings, PDF handling, and everything on the ingestion side mostly live there.</p>
<p>For storage, I'll use a single <a href="https://www.sqlite.org/">SQLite</a> file. SQLite has <a href="https://www.sqlite.org/fts5.html">full-text search</a> built in, and with the <a href="https://github.com/asg017/sqlite-vec"><code>sqlite-vec</code></a> extension it can store and search vectors too. So both the keyword index and the embeddings live in the same file, next to the paper metadata and fingerprints. One file, no server to run, everything on disk. That fits the on-device goal nicely, and it's easy to swap out later if I outgrow it.</p>
<p>For the embeddings, I'll use a small local embedding model that runs on CPU. The exact model is a detail I'll figure out later; the point is that it runs on my machine and nothing leaves it.</p>
<p>For the CLI, I'll use <a href="https://typer.tiangolo.com/">Typer</a>. It lets me write each command as a plain function with type hints, which keeps things small and readable. And for the MCP server, I'll use <a href="https://gofastmcp.com/">FastMCP</a>, which works the same way: a tool is just a typed function with a decorator.</p>
<p>That last bit is the part I'm most happy about. Because both Typer and FastMCP wrap plain typed functions, I can write the core logic once and expose it through both the CLI and the MCP server without duplicating anything. And if I ever want to put a web API in front of it, the same logic is right there to wrap again. So the searching and ingesting live in one place, and the CLI, the MCP server, and a future API are all just thin layers on top.</p>
<p>That's the plan for now.</p>
]]>
      </content:encoded>
      <pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>Garbage Collection in Java</title>
      <link>https://madooei.com/posts/garbage-collection-in-java/</link>
      <guid isPermaLink="false">https://madooei.com/posts/garbage-collection-in-java/</guid>
      <description>
        How C, C++, and Java each answer one question — who reclaims heap memory, and when — and what garbage collection buys you, and costs you, in exchange for safety.
      </description>
      <content:encoded>
        <![CDATA[<p>Java is a garbage-collected language. You create objects with <code>new</code>, and you never manually free their memory; something else reclaims that memory for you. It is worth understanding what that something else does, and what it costs.</p>
<p>Start with the problem it solves. Conceptually, every object your program creates has to live somewhere in memory, in a region called the heap. The heap is not infinite. Every object takes a chunk of it, and once the program can no longer use an object, that chunk has to be handed back, or the heap fills up and the program runs out of memory. The question is who hands it back, and when. C, C++, and Java answer that question in three different ways, and comparing the three is the clearest way to understand what garbage collection is.</p>
<h2 id="c-you-free-memory-by-hand" tabindex="-1"><a href="https://madooei.com/posts/garbage-collection-in-java/#c-you-free-memory-by-hand" class="header-anchor">C: you free memory by hand</a></h2>
<p>In C, you manage the heap yourself. You ask for memory with <code>malloc</code>, and you give it back with <code>free</code>:</p>
<pre><code class="language-c">int *p = malloc(sizeof(int));   // reserve a chunk of heap, get its address
*p = 5;                         // use it
free(p);                        // hand the chunk back
</code></pre>
<p>The rule is simple: every successful <code>malloc</code> must eventually be matched by exactly one <code>free</code>, no more and no less. If you get that wrong, you hit one of three common bugs.</p>
<p>The first is a <strong>memory leak</strong>. You allocate, you forget to free, and that chunk stays reserved until the program ends. One small leak in a short-lived program may not matter much. A leak inside a loop, in a program that runs for a long time, accumulates until the program runs out of memory.</p>
<p>The second is a <strong>dangling pointer</strong>. You free a chunk, but you still hold a pointer to it, and later you use that pointer. The memory may have already been handed out to something else by then, so you are reading or writing data that no longer belongs to you. These bugs are hard to reproduce and are a common cause of crashes and security vulnerabilities.</p>
<p>The third is a <strong>double free</strong>: calling <code>free</code> twice on the same chunk, which corrupts the heap's bookkeeping.</p>
<p>C does not catch any of these for you. You have full control over memory and full responsibility for managing it correctly.</p>
<h2 id="c-cleanup-tied-to-scope" tabindex="-1"><a href="https://madooei.com/posts/garbage-collection-in-java/#c-cleanup-tied-to-scope" class="header-anchor">C++: cleanup tied to scope</a></h2>
<p>C++ keeps everything C has. It has <code>new</code> and <code>delete</code>, which are the C++ equivalents of <code>malloc</code> and <code>free</code>, and the same three bugs are still possible. But C++ also provides a way to avoid freeing memory by hand.</p>
<p>The idea is to tie the lifetime of a heap object to the lifetime of an ordinary stack variable. When a C++ object with automatic storage duration goes out of scope, C++ guarantees that a special method called its <strong>destructor</strong> runs automatically. If that stack object owns heap memory, its destructor can free that heap memory, so cleanup happens automatically when the owner goes out of scope. This pattern is called <strong>RAII</strong> (&quot;resource acquisition is initialization&quot;), but the idea is just to let scope exit do the freeing.</p>
<p>In modern C++ you rarely write <code>delete</code> yourself. You use <strong>smart pointers</strong> that apply this pattern for you:</p>
<pre><code class="language-cpp">std::unique_ptr&lt;int&gt; p = std::make_unique&lt;int&gt;(5);
// use *p ...
// no delete needed: when p goes out of scope, the int is freed
</code></pre>
<p>A <code>unique_ptr</code> owns its object and destroys it when it goes out of scope. A <code>shared_ptr</code> lets several owners share one object and destroys it when the last owner goes away, by keeping a count of how many owners there are.</p>
<p>The important property is that the cleanup is <em>deterministic</em>. You know what event triggers cleanup: a <code>unique_ptr</code> destroys its object when the owner goes out of scope, and a <code>shared_ptr</code> destroys its object when the last owner goes away. There is no background process. You still decide who owns what, and you can still get it wrong — two <code>shared_ptr</code>s that point at each other form a cycle that keeps each other alive and is never freed — but the common case is handled predictably.</p>
<h2 id="java-the-runtime-frees-memory-for-you" tabindex="-1"><a href="https://madooei.com/posts/garbage-collection-in-java/#java-the-runtime-frees-memory-for-you" class="header-anchor">Java: the runtime frees memory for you</a></h2>
<p>Java takes the responsibility away from you. You allocate with <code>new</code>, and there is no second step. There is no <code>free</code> and no <code>delete</code>. You never reclaim memory yourself.</p>
<pre><code class="language-java">Employee e = new Employee(1);
// ... use it ...
// no free, no delete; you simply stop using it
</code></pre>
<p>Instead, the JVM runs a <strong>garbage collector</strong>: a process that, from time to time, determines which objects are still in use and reclaims the rest. The question it has to answer is which objects are still in use, and the answer is based on references — the links a variable holds to an object, and that object holds to another.</p>
<p>An object is <em>live</em> if it is <strong>reachable</strong>: if you can get to it by starting from a set of roots — the local variables currently on the stack, the static fields of your classes, and a few others — and following references from object to object. If no chain of references leads to an object, then nothing in your program can name it or use it again. It is <em>garbage</em>, and the collector can reclaim its memory.</p>
<p>This changes how you free something. You do not free it; you make it <em>unreachable</em> by dropping the references to it:</p>
<pre><code class="language-java">Employee e = new Employee(1);
e = null;   // if no other reachable reference points to that object, it is now eligible for collection
</code></pre>
<p>You are not telling the runtime to delete the object. You are telling it that you no longer hold a reference to the object, and at some later point the collector reclaims it. (Letting a local variable go out of scope does the same thing, without writing <code>null</code>.)</p>
<p>In exchange for giving up control, you avoid all three C bugs. You cannot have a dangling pointer, because you never free anything that a live reference still points to. You cannot double-free. And the &quot;forgot to free&quot; leak is mostly gone, because the collector reclaims objects once they are no longer reachable. This safety is a large part of why Java has no C/C++-style pointers: with no manual <code>free</code>, no raw addresses, and no pointer arithmetic, dangling-pointer and double-free bugs are removed from ordinary Java code.</p>
<p>Tracing collection has another benefit. Because the collector works by tracing what is reachable, it handles cycles automatically. Two Java objects that refer to each other but that nothing else points to are still unreachable from the roots, so they are collected. This is the case that reference-counting smart pointers in C++ do not handle.</p>
<p>Garbage collection also has costs.</p>
<p>The main cost is that collection is <em>non-deterministic</em>. Unlike C++'s scope-based cleanup, you do not know when an object will be collected, or even whether it will be collected before the program ends. The collector runs on its own schedule, and when it runs it may briefly pause your program to do its work — a &quot;stop-the-world&quot; pause. Modern collectors are designed to keep these pauses small, but pause behavior depends on the collector and workload, so for latency-sensitive software they are still a concern. Garbage-collected programs often need extra memory headroom, because memory is usually reclaimed in batches rather than immediately at the moment an object becomes unreachable.</p>
<p>There is also a subtler problem. Java can still leak, not in the C sense, but in a logical one. If you keep a reference to an object you no longer need (a common cause is an object left in a long-lived collection or cache), it stays reachable, so the collector will never reclaim it. The collector reclaims the <em>unreachable</em>; it cannot know that a still-reachable object is one you are done with. Java leaks are leaks of unintended reachability, not of forgotten frees.</p>
<p>One more consequence: because the collector may move objects around in memory to reduce fragmentation, an object's address is not stable over its lifetime. This is one reason Java does not show you raw addresses or let you do pointer arithmetic — the address you saw a moment ago might no longer be correct. And because collection timing is unpredictable, Java does not give you a reliable destructor the way C++ does. (Java historically had finalizers, but they are unreliable and deprecated; they are not a substitute for deterministic cleanup.) That is fine for memory, which the collector handles, but not for other resources like open files or network sockets, which need to be closed promptly. For those, Java provides <code>try</code>-with-resources: a scope-based cleanup mechanism for objects that implement <code>AutoCloseable</code>, where Java calls <code>close()</code> automatically at the end of the block.</p>
<h2 id="the-trade-off" tabindex="-1"><a href="https://madooei.com/posts/garbage-collection-in-java/#the-trade-off" class="header-anchor">The trade-off</a></h2>
<p>The three languages form a spectrum that trades control against safety:</p>
<ul>
<li><strong>C</strong> gives you full manual control. You have precise control over when memory is freed, and full responsibility for getting it right.</li>
<li><strong>C++</strong> keeps the control but automates the work. With RAII and smart pointers, cleanup happens deterministically at scope exit, and you mostly stop writing <code>delete</code> by hand.</li>
<li><strong>Java</strong> gives the job to the runtime. Whole categories of bugs are removed, at the cost of determinism, some memory overhead, and occasional pauses.</li>
</ul>
<p>No point on this spectrum is universally correct. A database engine or an operating-system kernel may need C's control; a large business application is usually better off with Java's safety. Each language makes a different choice.</p>
<h2 id="the-short-version" tabindex="-1"><a href="https://madooei.com/posts/garbage-collection-in-java/#the-short-version" class="header-anchor">The short version</a></h2>
<ul>
<li>In <strong>C</strong>, you free memory by hand with <code>free</code>, and you own every mistake: leaks, dangling pointers, double frees.</li>
<li>In <strong>C++</strong>, you can tie cleanup to scope with destructors and smart pointers, so owned memory is reclaimed automatically and deterministically when the owner is destroyed. You control when, and the language does the work.</li>
<li>In <strong>Java</strong>, a garbage collector reclaims whatever your references no longer reach. You stop managing memory and start managing reachability: safer, but you give up knowing exactly when cleanup happens.</li>
</ul>
<p>You never call <code>free</code> in Java. But you are still responsible for letting go of references you no longer need.</p>
]]>
      </content:encoded>
      <pubDate>Sat, 06 Jun 2026 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>Is a Java Reference a Pointer?</title>
      <link>https://madooei.com/posts/java-reference-vs-pointer/</link>
      <guid isPermaLink="false">https://madooei.com/posts/java-reference-vs-pointer/</guid>
      <description>
        C pointers, C++ references, and Java references are three different things that share one confusing word. Untangling them — and settling whether Java is pass-by-value or pass-by-reference.
      </description>
      <content:encoded>
        <![CDATA[<p>Students who come to Java from C or C++ often ask whether a Java reference is just a pointer. Students who come to Java without that background ask the opposite question: Java has no pointers, so what is a reference?</p>
<p>Part of what makes this confusing is that the word &quot;reference&quot; means different things in different languages. There are three separate ideas that get lumped together: the C pointer, the C++ reference, and the Java reference. Let's look at them one language at a time.</p>
<h2 id="pointers-in-c" tabindex="-1"><a href="https://madooei.com/posts/java-reference-vs-pointer/#pointers-in-c" class="header-anchor">Pointers in C</a></h2>
<p>In C, you work with memory addresses directly.</p>
<p>Start with an ordinary variable:</p>
<pre><code class="language-c">int x = 5;
</code></pre>
<p><code>x</code> is a name for a block of memory that holds the value <code>5</code>. That block has an address — a number that tells you where it is in memory. In C, you can get that address with the <code>&amp;</code> (&quot;address-of&quot;) operator:</p>
<pre><code class="language-c">int *p = &amp;x;
</code></pre>
<p><code>p</code> is a new variable, and its type is <code>int *</code>, which means &quot;pointer to an int.&quot; <code>p</code> does not hold an integer; it holds an <em>address</em>: the location of <code>x</code>. If <code>x</code> lives at address <code>0x1234</code>, then <code>p</code> holds the number <code>0x1234</code>.</p>
<p>A pointer is a variable like any other. It has its own block of memory, its own address, and it holds a value. The only difference is that the value it holds is meant to be used as the location of something else.</p>
<p>To go from the pointer to the thing it points at, you <em>dereference</em> it with the <code>*</code> operator:</p>
<pre><code class="language-c">printf(&quot;%d&quot;, *p);   // prints 5
*p = 10;            // now x is 10
</code></pre>
<p><code>*p</code> means &quot;go to the address stored in <code>p</code> and use whatever is there.&quot; Writing through <code>*p</code> changes <code>x</code>, because <code>p</code> holds <code>x</code>'s address.</p>
<p>Because a pointer is just a variable holding a number, you can do with it what you can do with any variable. You can point it somewhere else:</p>
<pre><code class="language-c">int y = 99;
p = &amp;y;   // p now holds the address of y instead
</code></pre>
<p>You can set it to point at nothing:</p>
<pre><code class="language-c">p = NULL;
</code></pre>
<p>You can also have a pointer to a pointer, since a pointer has its own address. C does not protect you from mistakes: if you dereference a pointer that holds an invalid address, the program has a bug, and C will not catch it for you.</p>
<p>To summarize C: a pointer is a variable that holds an address, you take addresses with <code>&amp;</code>, and you follow them with <code>*</code>. Everything is explicit.</p>
<h2 id="references-in-c" tabindex="-1"><a href="https://madooei.com/posts/java-reference-vs-pointer/#references-in-c" class="header-anchor">References in C++</a></h2>
<p>C++ keeps C's pointers exactly as they are. It also adds a second, separate thing, and it calls that thing a <em>reference</em>.</p>
<p>Here is a C++ reference:</p>
<pre><code class="language-cpp">int x = 5;
int &amp;r = x;
</code></pre>
<p><code>r</code> is declared as <code>int &amp;</code>, which means &quot;reference to an int.&quot; It does not behave like a pointer. <code>r</code> is not a variable that holds an address. <code>r</code> is another name for <code>x</code> — an alias. After this line, <code>r</code> and <code>x</code> refer to the same block of memory.</p>
<p>You do not use <code>&amp;</code> or <code>*</code> to work with it:</p>
<pre><code class="language-cpp">r = 10;   // x is now 10
</code></pre>
<p>You use <code>r</code> as if you had written <code>x</code>, because it is <code>x</code>.</p>
<p>This is the part that confuses people. A reference has two rules that a pointer does not:</p>
<ul>
<li><strong>It must be bound when it is created.</strong> You cannot write <code>int &amp;r;</code> with nothing on the right. A reference has to be an alias for something from the start.</li>
<li><strong>It can never be re-bound.</strong> Once <code>r</code> is an alias for <code>x</code>, it stays an alias for <code>x</code>. If you later write <code>r = y;</code>, that does <em>not</em> make <code>r</code> refer to <code>y</code>. It copies <code>y</code>'s value into <code>x</code>, because <code>r</code> is another name for <code>x</code>. There is no way to make an existing reference refer to a different object.</li>
</ul>
<p>A pointer is different: you can re-seat it as often as you like, and it can be <code>NULL</code>. A reference cannot be re-seated, and in a correct program it cannot refer to nothing.</p>
<p>So C++ has two distinct tools:</p>
<ul>
<li>A <strong>pointer</strong> is a variable that holds an address. It can be re-seated, it can be null, it has its own address, and you work with it through <code>&amp;</code> and <code>*</code>.</li>
<li>A <strong>reference</strong> is an alias — a second name for an object that already exists. It is bound once, cannot be re-seated, is not nullable in correct C++ code, and needs no special syntax.</li>
</ul>
<p>A C++ compiler usually implements a reference using a pointer internally, but the language treats them as different things with different rules.</p>
<h2 id="passing-arguments-the-swap-example" tabindex="-1"><a href="https://madooei.com/posts/java-reference-vs-pointer/#passing-arguments-the-swap-example" class="header-anchor">Passing arguments: the swap example</a></h2>
<p>The difference shows up when you pass something to a function.</p>
<p>Suppose you want a function that swaps two integers. In C, you use pointers, because the function needs the addresses of the caller's variables to change them:</p>
<pre><code class="language-c">void swap(int *a, int *b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

swap(&amp;x, &amp;y);   // pass the addresses
</code></pre>
<p>In C++, you can do the same thing with references. The parameters become aliases for the caller's variables:</p>
<pre><code class="language-cpp">void swap(int &amp;a, int &amp;b) {
    int tmp = a;
    a = b;
    b = tmp;
}

swap(x, y);   // no &amp; needed; a and b are x and y
</code></pre>
<p>Inside this function, <code>a</code> and <code>b</code> are not copies. They are the caller's <code>x</code> and <code>y</code> under different names, so the swap takes effect in the caller.</p>
<p>Java cannot do this, as we will see next.</p>
<h2 id="references-in-java" tabindex="-1"><a href="https://madooei.com/posts/java-reference-vs-pointer/#references-in-java" class="header-anchor">References in Java</a></h2>
<p>Java has no C/C++-style pointers. There is no <code>&amp;</code>, no <code>*</code>, no pointer arithmetic, and no way to get the numeric address of an object. So when Java says &quot;reference,&quot; the natural assumption, especially coming from C++, is that it means the C++ reference: an alias, bound once, never null.</p>
<p>That assumption is wrong, and it is the main source of confusion. A Java reference is not a C++ reference. In its behavior it is closer to a C++ pointer, with some restrictions.</p>
<p>Here is what a Java reference can do:</p>
<pre><code class="language-java">Employee e1 = new Employee(1);
Employee e2 = new Employee(2);
e1 = e2;       // re-seated: e1 now refers to the second object
e1 = null;     // and it can refer to nothing
</code></pre>
<p>A Java reference can be re-seated and can be null. A C++ reference can do neither; those are pointer behaviors. What Java takes from the C++ reference is the syntax: there is no <code>*</code> to dereference. When you write something like <code>e1.getId()</code>, Java follows the reference for you before calling the method. The dereference is implicit, but it still happens.</p>
<p>So a Java reference is pointer-like: you can think of it as pointing to an object, but Java does not expose it as a raw memory address. You cannot do arithmetic on it, cannot read it as a number, and cannot dereference it explicitly. It has the behavior of a pointer, with the unsafe operations removed and the dereference made implicit. The name &quot;reference&quot; can make people think of C++ references, but the behavior is much closer to a restricted pointer.</p>
<p>The swap function shows this clearly. Here it is in Java:</p>
<pre><code class="language-java">static void swap(Employee a, Employee b) {
    Employee tmp = a;
    a = b;
    b = tmp;
}

swap(e1, e2);   // e1 and e2 are unchanged afterward
</code></pre>
<p>This does nothing to the caller's <code>e1</code> and <code>e2</code>. Java passes the reference by value: <code>a</code> and <code>b</code> are copies of the references <code>e1</code> and <code>e2</code>. Swapping the copies inside the function does not affect the originals. This is how a copied pointer behaves, and it is not how a C++ reference behaves; a C++ reference would have made the swap take effect.</p>
<p>There is one more point to be clear about, because it is a common source of confusion. Even though you cannot re-seat the caller's variable, you can change the object it points at:</p>
<pre><code class="language-java">static void giveRaise(Employee a) {
    a.setSalary(a.getSalary() + 1000);   // this does affect the caller's object
}
</code></pre>
<p>Here <code>a</code> is a copy of the reference, but the copy points at the same object as the caller's reference. Changing that object through <code>a</code> is visible outside the function. What you cannot do is make the caller's variable point at a different object.</p>
<p>This settles the common question of whether Java is pass-by-value or pass-by-reference. Java is always pass-by-value. For objects, the value being copied is the reference, not the object. You can follow the reference and change what is at the other end, but you cannot change the caller's reference itself.</p>
<h2 id="the-short-version" tabindex="-1"><a href="https://madooei.com/posts/java-reference-vs-pointer/#the-short-version" class="header-anchor">The short version</a></h2>
<ul>
<li>A <strong>C pointer</strong> is a variable that holds an address. It is explicit, can be re-seated, can be null, and uses <code>&amp;</code> and <code>*</code>.</li>
<li>A <strong>C++ reference</strong> is an alias — a second name for an object that already exists. It is bound once, cannot be re-seated, is not nullable in correct C++ code, and uses no special syntax.</li>
<li>A <strong>Java reference</strong> uses the syntax of a C++ reference (no <code>*</code>, implicit dereference) but has behavior closer to a C pointer (can be re-seated, can be null, passed by value). It is pointer-like, but Java does not expose it as a raw address.</li>
</ul>
<p>The word &quot;reference&quot; can be misleading: a Java reference is not a C++ reference. In the ways that matter for this discussion, it behaves much more like a restricted pointer.</p>
]]>
      </content:encoded>
      <pubDate>Fri, 05 Jun 2026 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>Java's Two Kinds of Types</title>
      <link>https://madooei.com/posts/java-two-kinds-of-types/</link>
      <guid isPermaLink="false">https://madooei.com/posts/java-two-kinds-of-types/</guid>
      <description>
        Why Java splits every type into primitives and references — a story about fixed-size memory blocks, variable-size values, and why an object can't contain a copy of itself.
      </description>
      <content:encoded>
        <![CDATA[<p>Java has two categories of types: primitive types and reference types. Let's briefly review them.</p>
<p>Primitive types include <code>int</code>, <code>double</code>, <code>boolean</code>, etc. They store their values directly. For example, if you have an <code>int x = 5;</code>, the variable <code>x</code> directly holds the value <code>5</code>. When your program runs, it allocates memory for <code>x</code> and stores the value <code>5</code> in that memory location. When you try to print <code>x</code>, the program has a lookup table that tells it where <code>x</code> is stored in memory (let's say at address <code>0x1234</code>), and it goes to that address, reads the raw data stored there (which is in binary), converts it to an integer (because it knows <code>x</code> is an <code>int</code>), and then prints the result (<code>5</code>).</p>
<p>There is a lot of machinery that happens under the hood to make this work, but the key point is that for primitive types, the variable directly holds the value.</p>
<p>Reference types, on the other hand, do not hold the actual data. Instead, they hold a reference (or pointer) to the location in memory where the actual data is stored.<sup><a class="footnote-ref" href="https://madooei.com/posts/java-two-kinds-of-types/#fn-1" id="fnref-1">1</a></sup> Let's walk through an example to illustrate this. Suppose you write <code>Employee e1 = new Employee(1);</code>. This statement is actually doing a few things:</p>
<ul>
<li>First, it creates a new <code>Employee</code> object in memory. Let's say this object is stored at address <code>0x5678</code>.</li>
<li>Then, it initializes the fields of that <code>Employee</code> object (e.g., setting <code>id</code> to <code>1</code>).</li>
<li>Then, it creates a variable <code>e1</code>. This variable also has a memory location (let's say <code>0x1234</code>).</li>
<li>Finally, it stores the reference (the address <code>0x5678</code>) in the variable <code>e1</code>. So <code>e1</code> does not hold the actual <code>Employee</code> object; it holds a reference to where that object is stored in memory.</li>
</ul>
<p>When you access <code>e1.getId()</code> (to print the employee's id as an example), the program does the following:</p>
<ul>
<li>It looks up the variable <code>e1</code> and finds that its memory location is <code>0x1234</code>.</li>
<li>It goes to that memory location and reads the value stored there, which is some binary data.</li>
<li>It interprets that binary data as a reference (because <code>e1</code> is of type <code>Employee</code>). Here, &quot;reference&quot; simply means an address in memory where the actual <code>Employee</code> object is stored. So it reads the reference and finds that it points to <code>0x5678</code>.</li>
<li>It then goes to the memory location <code>0x5678</code> where the actual <code>Employee</code> object is stored.</li>
<li>It then reads the <code>id</code> field from that object, which is <code>1</code>, returns it from <code>getId()</code>, and prints it.</li>
</ul>
<p>I've glossed over some details here, but the key point is that it has to follow the reference from <code>e1</code> to get to the actual object in memory. This is what it means for <code>e1</code> to be a reference type. It does not hold the actual data; it holds a reference to where the data is stored.</p>
<p>But why do we have two types of variables? The answer is more interesting than &quot;because Java says so.&quot; It has to do with how variables are stored in memory. Let's explore that next.</p>
<h2 id="what-is-a-variable-really" tabindex="-1"><a href="https://madooei.com/posts/java-two-kinds-of-types/#what-is-a-variable-really" class="header-anchor">What Is a Variable, Really?</a></h2>
<p>You can think of computer memory as a long row of tiny boxes, each box holding a fixed number of bits (usually 8 bits, which is called a byte). Each box has its own address, which is just a number that tells you where it is in the row. The memory is divided into regions, and the regions are used for different purposes and as such have different characteristics.</p>
<p>One of those regions is where your program's variables live. When you declare a variable in your program, the compiler sets aside a block of those boxes (memory units) for it. The variable's name is just a label for that block, so when you use the variable in your code, the program knows to go to that specific location to read or write its value.</p>
<p>Here is the part that matters. The region where variables live has a strict rule: each variable gets a block of a fixed size, decided before the program runs. When your code is compiled, the compiler has to know exactly how much room to reserve for each variable. Why must it be fixed in advance? Because the blocks are laid out next to each other in one continuous row. If variable <code>x</code> is followed by <code>y</code> in memory, the program needs to know where <code>x</code> ends and <code>y</code> begins. If <code>x</code> could grow or shrink while the program ran, it would crash into <code>y</code>. So the size is settled up front, and it never changes.</p>
<p>How much room? That depends on the type. This is, in fact, <em>what the type tells the compiler</em>. When you write <code>int x;</code>, the <code>int</code> says &quot;reserve 4 bytes.&quot; A <code>double</code> says &quot;reserve 8 bytes.&quot; The type is not just a label for you, the programmer — it is an instruction to the compiler about how big the block must be and how to read the bits inside it.</p>
<p>If the value is something small with a known, fixed size — a whole number, a decimal number, a single character, a true-or-false — then it fits nicely in a fixed-size block. This is exactly what a <strong>primitive</strong> type is.<sup><a class="footnote-ref" href="https://madooei.com/posts/java-two-kinds-of-types/#fn-2" id="fnref-2">2</a></sup></p>
<p>But what if the value cannot be fit into a fixed-size block? What if it is something that can vary in size?</p>
<h2 id="when-the-value-doesn-t-fit" tabindex="-1"><a href="https://madooei.com/posts/java-two-kinds-of-types/#when-the-value-doesn-t-fit" class="header-anchor">When the Value Doesn't Fit</a></h2>
<p>Let's say we define a variable to hold a person's name: <code>String name;</code></p>
<p>How big a block should the compiler set aside for <code>name</code>?</p>
<p>An <code>int</code> was easy — every <code>int</code> is exactly 4 bytes, today and forever, so the compiler reserves 4 bytes and moves on. But a name? It could be a small 3-character string like my name, Ali, or a much longer name. The type <code>String</code> can store the entirety of this blog post (or any other text, however long). Moreover, you can change which string the variable refers to while the program runs: assign it a short name now, then assign it a longer name later. There is no single number of bytes the compiler can pick ahead of time that is right for every possible string.</p>
<p>This runs straight into the rule stated earlier: the block reserved for a variable has a fixed size, decided up front, and it never changes. A <code>String</code> has no fixed size. So a string simply cannot live inside the variable's reserved block the way an <code>int</code> does. The two facts are in direct conflict.</p>
<p>So what do we do? The solution is to stop trying to put the string itself in the block. Instead, we put the string <em>somewhere else</em> in memory — in a different region (often called the <em>heap</em>) where objects can be allocated at runtime with whatever size they need. (The program creates a new object of whatever size is needed, and the variable can later point to a different object.)</p>
<p>So what does go into the block reserved for <code>name</code>? We put the address of that somewhere else. The block does not hold the string. It holds a note that says &quot;the string you want is over there, at address <code>0x5678</code>.&quot;</p>
<p>Look at what this buys us. The string itself can be 2 bytes or 2 million; it lives elsewhere, so its size is no longer our problem. And the block corresponding to <code>name</code> stays small and fixed — it only ever holds an address, and an address is the same size no matter how big the thing it points to is (typically 8 bytes on a 64-bit machine). The fixed-size block and the variable-size value can finally coexist, because we stopped trying to hold the value in the block and started holding <em>directions to</em> the value.</p>
<p>That address-sitting-in-a-block is what we call a <strong>reference</strong>. The block holds a reference to the value; the value lives somewhere else in memory.</p>
<p>You might reasonably push back here. If there is a region of memory that can hold a string of any size, why the detour? Why not let the variable <code>name</code> refer to that region directly, and skip the little fixed block in the middle?</p>
<p>The answer is that the block <em>is</em> the variable, and the variable has to stay put while the thing it refers to does not.</p>
<p>Think about what the name <code>name</code> actually is. When your code is compiled, <code>name</code> becomes one specific block in the variable region — the place the rest of your compiled code reaches every single time it uses <code>name</code>, for the whole life of the variable. That block has to be settled before the program runs, which is the fixed-size rule again.</p>
<p>Now think about the string. It is created <em>while</em> the program runs, not before. At compile time there is no address to point at yet — the string does not exist, and the compiler has no way to know where it will eventually land. And it gets worse: you can point <code>name</code> at a different string later. Write <code>name = &quot;Ali&quot;</code> on one line and <code>name = &lt;something far longer&gt;</code> on the next, and you now have two different strings, of two different sizes, at two unrelated addresses.</p>
<p>So we have a fixed thing — the variable's block, pinned down at compile time — that has to refer to a moving target: a value created at runtime that can be swapped out at any moment. You cannot wire the name directly to the string's address, because when the wiring is decided there is no address yet, and even once there is one, the next line might change it. The block never moves; what changes is the address written inside it. <em>That</em> is what the indirection is for: the block is a stable handle you can always find, and its contents are free to point wherever the variable currently refers.</p>
<p>So here is one important reason Java has two kinds of types. Some values have a small, fixed, known size and can be stored directly in the variable's block — those are the <strong>primitives</strong>. Objects, on the other hand, are stored elsewhere, and the variable's block stores only a fixed-size reference to the object — those are the <strong>reference types</strong>. This keeps the variable's block small and fixed even when the object is created at runtime, replaced by a different object, shared by multiple variables, or connected to other objects.</p>
<h2 id="how-big-is-an-employee" tabindex="-1"><a href="https://madooei.com/posts/java-two-kinds-of-types/#how-big-is-an-employee" class="header-anchor">How Big Is an Employee?</a></h2>
<p>Variable size is the first reason references exist, but it is not the only one. There is a second reason, and it is about a problem that has no solution at all without references.</p>
<p>Go back to the <code>Employee</code> class, and assume it has the following definition:</p>
<pre><code class="language-java">public class Employee {
    private int id;
    private Employee manager;
    // Other fields (like name, title, etc.) are omitted for simplicity
    // Constructor, getters, setters, other methods are omitted for simplicity
}
</code></pre>
<p>Pay attention to the <code>manager</code> field. It is of type <code>Employee</code>. Interesting: one employee has a <em>reference</em> to another employee. This allows us to create a <em>chain</em> of employees, where each employee can have a manager, and that manager can have their own manager, and so on. You can imagine a junior employee who reports to a mid-level manager, who reports to a senior manager, who reports to the CEO. Each of those employees can be represented as an <code>Employee</code> object, and the <code>manager</code> field can point to the next employee in the chain. You might wonder about the CEO, who has no manager. We can represent that by setting the <code>manager</code> field to <code>null</code> for the CEO.</p>
<p>Let's ask a question that sounds almost too simple: how big is an <code>Employee</code> object? How many bytes must the compiler set aside for one?</p>
<p>We can try to add it up. The <code>id</code> field is an <code>int</code>, so that is 4 bytes. Then there is the <code>manager</code> field, which is an... <code>Employee</code>. So to know how big an <code>Employee</code> is, we first need to know how big an <code>Employee</code> is.</p>
<p>Read that again — it is not a slip. Suppose the <code>manager</code> field stored an entire <code>Employee</code> object inside it, the whole thing laid out inline. Then the size of an <code>Employee</code> would be:</p>
<pre><code class="language-plaintext">size(Employee) = 4 bytes (id) + size(Employee)
</code></pre>
<p>And the <code>size(Employee)</code> on the right has its own <code>manager</code>, which is another <code>Employee</code>, which has its own <code>manager</code>, which is another <code>Employee</code>, with no end in sight. The block would need room for an employee, who holds an employee, who holds an employee, forever. No number of bytes satisfies this. The compiler cannot lay out even a single <code>Employee</code> in memory. The object is, quite literally, infinitely large.</p>
<p>So storing an <code>Employee</code> object directly inside another <code>Employee</code> object, by value, is not merely a bad idea — it is impossible. <strong>A type cannot contain a full inline copy of itself.</strong></p>
<p>Now watch what a reference does to this.</p>
<p>If <code>manager</code> holds a <em>reference</em> to an <code>Employee</code> instead of an <code>Employee</code> itself, then <code>manager</code> is just an address. An address has a fixed, known size — the same handful of bytes whether it points to a junior hire, the CEO, or nothing at all. The infinite regress collapses:</p>
<pre><code class="language-plaintext">size(Employee) = 4 bytes (id) + 8 bytes (a reference)
</code></pre>
<p>Around twelve bytes — the JVM adds a little bookkeeping of its own, but the point is that it is a fixed, finite number, known before the program runs. The compiler can lay it out without trouble. And that <code>manager</code> reference can point to another <code>Employee</code> who lives elsewhere in memory, who has their own <code>manager</code> reference pointing to yet another <code>Employee</code> elsewhere, and so on up to the CEO, whose <code>manager</code> reference is simply <code>null</code>.</p>
<p>This is the second reason references have to exist. Without them, no value could ever contain another value of its own type, and an entire family of structures would be impossible to build. This is also why Java never gives you the choice: a field whose type is a class is <em>always</em> a reference, never the object itself laid out inline. The language closes the trap before you can fall into it.</p>
<p>With references, a type can refer to its own kind — and that single capability is the foundation of a whole family of data structures, including linked lists, trees, graphs, and more.</p>
]]>
      </content:encoded>
      <pubDate>Thu, 04 Jun 2026 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>The Stack and the Heap</title>
      <link>https://madooei.com/posts/the-stack-and-the-heap/</link>
      <guid isPermaLink="false">https://madooei.com/posts/the-stack-and-the-heap/</guid>
      <description>
        Where a running Java program keeps its data, why it needs two regions, and how method calls, recursion, and object lifetimes play out across the stack and the heap.
      </description>
      <content:encoded>
        <![CDATA[<p>A running Java program keeps its data in more than one place in memory. Two of those places matter for understanding how a program behaves: the stack and the heap. They differ in what they hold, how long that data lives, and who cleans it up. This post explains both, mostly in terms of Java, with some comparison to C and C++ where it helps.</p>
<h2 id="what-lives-where-in-java" tabindex="-1"><a href="https://madooei.com/posts/the-stack-and-the-heap/#what-lives-where-in-java" class="header-anchor">What lives where in Java</a></h2>
<p>In Java, the standard conceptual rule of thumb is short:</p>
<ul>
<li>A method call's local variables and parameters are stored in its stack frame.</li>
<li>Objects — anything you create with <code>new</code> — conceptually live on the heap.</li>
</ul>
<p>These two facts interact for reference types. Suppose we have a small class:</p>
<pre><code class="language-java">public class Employee {
    private int id;
    // constructor, getter, etc.
}
</code></pre>
<p>Now consider this line:</p>
<pre><code class="language-java">Employee e = new Employee(1);
</code></pre>
<p>This involves two separate pieces of memory. The object — the actual <code>Employee</code>, with its <code>id</code> field — is created on the heap. The variable <code>e</code> is a local variable, so its reference value is stored in the stack frame, and that reference points to the object on the heap.</p>
<p>A primitive local variable is different. With <code>int count = 5;</code>, the local-variable slot for <code>count</code> holds its value, <code>5</code>, directly in the stack frame. There is no separate object anywhere.</p>
<pre><code class="language-plaintext">        Stack                                Heap
   ┌─────────────────┐              ┌──────────────────────┐
   │ e   ■───────────┼────────────▶ │ Employee             │
   │                 │              │   id = 1             │
   │ count = 5       │              │                      │
   └─────────────────┘              └──────────────────────┘
</code></pre>
<h2 id="the-stack" tabindex="-1"><a href="https://madooei.com/posts/the-stack-and-the-heap/#the-stack" class="header-anchor">The stack</a></h2>
<p>The stack holds the data for method calls. Each time a method is called, Java sets aside a block of memory called a <strong>frame</strong> for that call. The frame holds the method's local-variable slots, its parameters, and some bookkeeping.</p>
<p>The frames are arranged as a stack in the data-structure sense: last in, first out. When method A calls method B, a frame for B is pushed on top of A's frame. When B returns, its frame is popped off, and control goes back to A. If B had called C, C's frame would sit on top of B's and would be popped first.</p>
<p>This has one important consequence: the storage for a method call is automatic and tied to that call. The frame comes into existence when the method is called, and it is gone the moment the method returns and its frame is popped. A local variable may be in scope for only part of the method, but in any case you do not free it; its stack storage goes away on its own when the call ends.</p>
<p>The stack is cheap to use. Allocating a frame is essentially moving a pointer, and popping it is moving the pointer back. But the stack has limits: the size of each frame is known in advance, and the total stack space is limited.</p>
<h2 id="recursion-and-the-call-stack" tabindex="-1"><a href="https://madooei.com/posts/the-stack-and-the-heap/#recursion-and-the-call-stack" class="header-anchor">Recursion and the call stack</a></h2>
<p>Recursion is the clearest way to see the call stack at work. A recursive method calls itself, and each call gets its own frame, with its own copy of the parameters and local variables.</p>
<p>Take a method that computes a factorial for positive inputs:</p>
<pre><code class="language-java">static int factorial(int n) {
    if (n == 1) return 1;          // base case
    return n * factorial(n - 1);
}
</code></pre>
<p>When you call <code>factorial(3)</code>, the calls do not all run at once. Each one calls the next and waits for it to return:</p>
<ul>
<li><code>factorial(3)</code> is called. A frame is pushed with <code>n = 3</code>. To finish, it needs the result of <code>factorial(2)</code>.</li>
<li><code>factorial(2)</code> is called. A frame is pushed on top, with <code>n = 2</code>. It needs <code>factorial(1)</code>.</li>
<li><code>factorial(1)</code> is called. A frame is pushed on top, with <code>n = 1</code>. This is the base case: it returns <code>1</code>, and its frame is popped.</li>
<li><code>factorial(2)</code> resumes, computes <code>2 * 1 = 2</code>, returns <code>2</code>, and its frame is popped.</li>
<li><code>factorial(3)</code> resumes, computes <code>3 * 2 = 6</code>, returns <code>6</code>, and its frame is popped.</li>
</ul>
<p>At the deepest point, all three frames are on the stack at the same time:</p>
<pre><code class="language-plaintext">        ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
top ──▶ ┃ factorial(1)  n=1  return 1  (n == 1)       ┃
        ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
        ┌─────────────────────────────────────────────┐
        │ factorial(2)  n=2  waiting for factorial(1) │
        ├─────────────────────────────────────────────┤
        │ factorial(3)  n=3  waiting for factorial(2) │
        └─────────────────────────────────────────────┘
</code></pre>
<p>Each frame has its own <code>n</code>, which is why the calls do not interfere with one another. The frames build up until the base case is reached, then unwind in reverse order as each call returns.</p>
<p>This also explains stack overflow. If a recursive method has no base case, or never reaches it, the frames keep getting pushed and none are ever popped. Eventually the stack space runs out, and the program fails with a <code>StackOverflowError</code>.</p>
<h2 id="the-heap" tabindex="-1"><a href="https://madooei.com/posts/the-stack-and-the-heap/#the-heap" class="header-anchor">The heap</a></h2>
<p>The heap holds objects, and it is not tied to method calls. Conceptually, when you write <code>new</code>, the object is created on the heap, and it stays there until it becomes unreachable and the garbage collector reclaims it, regardless of which method created it.</p>
<p>This is the key difference from the stack. An object created inside a method does not disappear when the method returns. It can outlive the call, as long as it remains reachable:</p>
<pre><code class="language-java">static Employee createEmployee() {
    Employee local = new Employee(1);  // object on the heap; local reference in the stack frame
    return local;                      // return the reference
}

Employee e = createEmployee();         // e refers to the same heap object
</code></pre>
<p>When <code>createEmployee</code> returns, its frame is popped off the stack, and the local variable <code>local</code> is gone. But the <code>Employee</code> object on the heap is still reachable, because the reference was returned and is now held by <code>e</code> in the caller. The object outlived the method that created it.</p>
<p>The heap is more flexible than the stack. Objects can have different sizes, their lifetimes can extend beyond the method call that created them, and they can be referred to from many places at once. The cost of that flexibility is that the heap needs separate management to reclaim objects that are no longer reachable — the cleanup that the stack gets for free by popping frames.</p>
<h2 id="why-two-regions" tabindex="-1"><a href="https://madooei.com/posts/the-stack-and-the-heap/#why-two-regions" class="header-anchor">Why two regions</a></h2>
<p>A reasonable question is why a program needs both. The stack's automatic lifetime is cheap and safe, but it only works for data whose storage can disappear when the call returns. Two situations do not fit that pattern:</p>
<ul>
<li>The data must outlive the method that created it. The <code>createEmployee</code> example returns an object that has to exist after the method returns. A stack frame cannot hold it, because the frame is gone once the method returns.</li>
<li>The data needs to be shared or to vary in size. Objects can be referred to from several reachable places at once and can have sizes chosen at runtime; tying them to a single frame would not work.</li>
</ul>
<p>For data that fits the call pattern — ordinary local-variable values and parameters — the stack is ideal, because cleanup is automatic and free. For object data with independent lifetime, the program uses the heap.</p>
<h2 id="c-and-c" tabindex="-1"><a href="https://madooei.com/posts/the-stack-and-the-heap/#c-and-c" class="header-anchor">C and C++</a></h2>
<p>The stack and the heap are not specific to Java. C and C++ have the same two regions, with the same basic roles: local variables go on the stack, and dynamically allocated memory goes on the heap. There are two differences worth noting.</p>
<p>First, C and C++ let you choose where an object goes. A local struct or object declared in the normal way lives on the stack and is destroyed automatically when it goes out of scope. An object you allocate with <code>malloc</code> (in C) or <code>new</code> (in C++) lives on the heap. In Java you do not make this choice in source code: objects are treated as heap objects in the standard model, and local variables and parameters hold primitive values or references in stack frames.</p>
<p>Second, the heap has to be reclaimed somehow. In C you do it by hand with <code>free</code>. In C++ you usually tie it to scope with destructors and smart pointers. In Java, a garbage collector reclaims heap objects that are no longer reachable. In all three languages, the stack reclaims itself automatically by popping frames.</p>
<h2 id="a-caveat" tabindex="-1"><a href="https://madooei.com/posts/the-stack-and-the-heap/#a-caveat" class="header-anchor">A caveat</a></h2>
<p>&quot;Objects on the heap, local-variable values in stack frames&quot; is the standard model for reasoning about a Java program, and it is the right model for understanding lifetimes and behavior. But it describes the conceptual runtime model, not a word-for-word rule about how every JVM must represent every value internally. The JVM is allowed to optimize. For example, with a technique called escape analysis, it may avoid a heap allocation, or represent an object as separate pieces, if it can prove the object never escapes the method that created it.</p>
<h2 id="the-short-version" tabindex="-1"><a href="https://madooei.com/posts/the-stack-and-the-heap/#the-short-version" class="header-anchor">The short version</a></h2>
<ul>
<li>The <strong>stack</strong> holds method-call frames, including local-variable slots and method parameters. Frames are pushed when a method is called and popped when it returns, so stack storage is cleaned up automatically when the call ends. The stack is fast but limited in size.</li>
<li>The <strong>heap</strong> holds objects created with <code>new</code> in the standard Java model. Objects live independently of method calls and can outlive the method that created them, for as long as they remain reachable. The heap is flexible but needs separate cleanup.</li>
<li>A reference-typed local variable has its reference value stored in the stack frame, and that reference points to an object on the heap.</li>
<li>C and C++ have the same two regions. The main differences are that they let you choose the stack or the heap for an object in source code, and that they reclaim the heap by hand or by scope rather than with a garbage collector.</li>
</ul>
]]>
      </content:encoded>
      <pubDate>Wed, 03 Jun 2026 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>Java's Exceptions</title>
      <link>https://madooei.com/posts/java-exceptions/</link>
      <guid isPermaLink="false">https://madooei.com/posts/java-exceptions/</guid>
      <description>
        A refresher on Java's exception mechanism — not just try/catch, but signaling errors by throwing, how exceptions propagate, checked vs. unchecked, custom exceptions, and robust methods that enforce their own contracts.
      </description>
      <content:encoded>
        <![CDATA[<p>This is a refresher on Java's exception mechanism for my students taking Data Structures with me.</p>
<p>I noticed that when we speak of exceptions, students immediately think of <code>try</code>/<code>catch</code> blocks, which are only one part of the story. In fact, when designing and implementing data structures, we will be more concerned with the other part of the story: how to signal an error condition by throwing an exception. The <code>try</code>/<code>catch</code> mechanism is how a client can handle that exception, but that is not our focus when we are implementing the data structure itself. So I will start with the throwing part of the story, and then cover the catching part at the end.</p>
<h2 id="signaling-an-error-condition" tabindex="-1"><a href="https://madooei.com/posts/java-exceptions/#signaling-an-error-condition" class="header-anchor">Signaling an Error Condition</a></h2>
<p>Suppose we are implementing a list backed by an array. The interface offers a method to get the element at an index:</p>
<pre><code class="language-java">public interface List&lt;T&gt; {
    T get(int index);
    // add, remove, size, ...
}
</code></pre>
<p>The implementation keeps the elements in an array <code>data</code>, with an <code>int size</code> counting how many are in use. Now, what should <code>get</code> do when the index is invalid — negative, or past the end of the list? There are a few options, and most of them are bad.</p>
<p>One option is to assume the caller never passes a bad index. This is the <em>precondition</em> approach: the method documents &quot;the index must be in range&quot; and then trusts the caller.</p>
<pre><code class="language-java">public T get(int index) {
    return data[index]; // assumes index is valid
}
</code></pre>
<p>The problem is that the method now has no way to <em>report</em> a bad index. It can only avoid the question. Every caller has to check the index before calling:</p>
<pre><code class="language-java">if (index &gt;= 0 &amp;&amp; index &lt; list.size()) {
    String value = list.get(index);
} else {
    // now what? return null? a default? crash?
}
</code></pre>
<p>This check gets repeated in every caller, written slightly differently each time, and there is no good answer for the <code>else</code> branch — the interface has not said what should happen when the index is invalid. And if a caller forgets the check, the bad index reaches the backing array. Sometimes that produces a cryptic failure:</p>
<pre><code class="language-plaintext">Exception in thread &quot;main&quot; java.lang.ArrayIndexOutOfBoundsException: 10
	at ArrayList.get(ArrayList.java:42)
</code></pre>
<p>That message names an internal array index, not the problem the caller cares about. Even worse, if the backing array has extra capacity, an index that is past <code>size</code> but still inside <code>data.length</code> might not throw at all; it might return an unused slot instead. The method has failed to enforce the list's abstraction.</p>
<p>Another option, if this were a list of integers, is to return a special value to signal failure — an <em>error code</em>:</p>
<pre><code class="language-java">public int get(int index) {
    if (index &lt; 0 || index &gt;= size) {
        return -1; // error code
    }
    return data[index];
}
</code></pre>
<p>But <code>-1</code> might be a perfectly valid element the list is storing, so the caller cannot tell an error from real data. And, as before, the caller has to remember to check every return value.</p>
<p>What we want is a way for the method itself to check the index and, when it is invalid, signal that clearly — without overloading the return value, and without relying on the caller to remember. That is what an exception is for.</p>
<p>An <strong>exception</strong> is an object that represents an error condition during program execution. It is a regular Java object, with a type and a place in a class hierarchy. When a method detects a condition it cannot proceed with, it can <em>throw</em> an exception: the method stops executing, and Java looks for code elsewhere that knows how to handle the situation.</p>
<h2 id="throwing-or-raising-an-exception" tabindex="-1"><a href="https://madooei.com/posts/java-exceptions/#throwing-or-raising-an-exception" class="header-anchor">Throwing (or Raising) an Exception</a></h2>
<p>A method throws an exception when it detects an error condition it should not handle silently. The syntax is <code>throw</code>, followed by a new exception object:</p>
<pre><code class="language-java">public T get(int index) {
    if (index &lt; 0 || index &gt;= size) {
        throw new IndexOutOfBoundsException(
            &quot;Index &quot; + index + &quot; out of bounds for size &quot; + size);
    }
    return data[index];
}
</code></pre>
<p>Two things to notice. First, the check now lives inside the method, written once, instead of in every caller. Second, the message names the abstraction the caller understands — &quot;size 5&quot;, not an internal array index. A message like &quot;Index 7 out of bounds for size 3&quot; tells the next developer exactly what happened; a bare exception with no message tells them nothing.</p>
<p>Java ships with many built-in exception types, and you should reach for them before inventing your own. A few common ones:</p>
<ul>
<li><code>IndexOutOfBoundsException</code> — an index is outside the valid range.</li>
<li><code>IllegalArgumentException</code> — a method received an argument it cannot accept.</li>
<li><code>IllegalStateException</code> — the object is in a state where the operation does not make sense.</li>
<li><code>NullPointerException</code> — a null reference was used where an object was required.</li>
</ul>
<p>For example, if our list does not allow null elements, <code>add</code> can reject a null argument:</p>
<pre><code class="language-java">public void add(T element) {
    if (element == null) {
        throw new IllegalArgumentException(&quot;Cannot add null element to list&quot;);
    }
    // ... rest of implementation
}
</code></pre>
<p><code>IllegalArgumentException</code> is a conventional choice when the offender is a bad argument. For a null argument specifically, many Java APIs use <code>NullPointerException</code>; the important point is to choose the exception type that says what contract was violated.</p>
<p>Moving the validation into the method changes the contract. Instead of &quot;the index must be in range&quot; (a rule the caller has to remember), the contract becomes &quot;if the index is out of range, you get an <code>IndexOutOfBoundsException</code>.&quot; The method takes on the checking, every caller gets simpler, and the error points back at the call that caused it.</p>
<h2 id="propagating-an-exception" tabindex="-1"><a href="https://madooei.com/posts/java-exceptions/#propagating-an-exception" class="header-anchor">Propagating an Exception</a></h2>
<p>When a method throws an exception and does not catch it, the exception does not disappear and the whole program does not necessarily stop immediately. The current method stops, and the exception travels <em>up the call stack</em>, one method at a time, until something catches it or it reaches the top.</p>
<p>Consider a chain of calls:</p>
<pre><code class="language-java">public void processAll(List&lt;String&gt; names, int index) {
    analyze(names, index);       // (3) exception passes through here
}

public void analyze(List&lt;String&gt; names, int index) {
    processOne(names, index);    // (2) and here
}

public void processOne(List&lt;String&gt; names, int index) {
    String name = names.get(index); // (1) exception thrown here
}
</code></pre>
<p>If <code>get</code> throws an <code>IndexOutOfBoundsException</code>:</p>
<ol>
<li><code>processOne</code> has no <code>try</code>/<code>catch</code>, so the exception leaves it and propagates up.</li>
<li><code>analyze</code> has no handler either, so it keeps going up.</li>
<li><code>processAll</code> does not catch it, so it goes up again.</li>
<li>If <code>main</code> does not catch it, the main thread terminates and prints the stack trace.</li>
</ol>
<p>Each method on the stack gets a chance to handle the exception, and each one here declines. Where to catch is a design decision: catch it in the method that actually knows what to do about it.</p>
<p>The exception object carries the information you need to make that decision. You can ask it for its message, its type, and its stack trace:</p>
<pre><code class="language-java">catch (IndexOutOfBoundsException e) {
    e.getMessage();               // &quot;Index 5 out of bounds for size 3&quot;
    e.getClass().getSimpleName(); // &quot;IndexOutOfBoundsException&quot;
    e.printStackTrace();          // where it was thrown, frame by frame
}
</code></pre>
<h2 id="catching-an-exception" tabindex="-1"><a href="https://madooei.com/posts/java-exceptions/#catching-an-exception" class="header-anchor">Catching an Exception</a></h2>
<p>To handle an exception, wrap the risky code in a <code>try</code> block and handle the failure in a <code>catch</code> block:</p>
<pre><code class="language-java">public void process(List&lt;String&gt; names, int index) {
    try {
        String name = names.get(index);
        System.out.println(&quot;Processing: &quot; + name);
    } catch (IndexOutOfBoundsException e) {
        System.out.println(&quot;Error: &quot; + e.getMessage());
    }
    System.out.println(&quot;This still runs.&quot;);
}
</code></pre>
<p>Once the exception is caught, if the <code>catch</code> block completes normally, the method continues after the <code>try</code>/<code>catch</code>.</p>
<p>A single <code>try</code> block can throw more than one kind of exception, and you can write one <code>catch</code> per type:</p>
<pre><code class="language-java">try {
    names.add(element);
    names.remove(index);
} catch (IndexOutOfBoundsException e) {
    System.out.println(&quot;Index problem: &quot; + e.getMessage());
} catch (IllegalArgumentException e) {
    System.out.println(&quot;Bad argument: &quot; + e.getMessage());
}
</code></pre>
<p>Java runs the first <code>catch</code> whose type matches. This means <strong>order matters</strong>: list specific exceptions before general ones. If a general catch comes first, it would handle everything the specific catch could handle, so Java rejects the specific catch below it as unreachable code.</p>
<pre><code class="language-java">try {
    names.get(index);
} catch (IndexOutOfBoundsException e) { // specific first
    // ...
} catch (RuntimeException e) {           // general last
    // ...
}
</code></pre>
<p>Sometimes there is cleanup that must happen whether or not an exception was thrown — closing a file, releasing a lock. That is what <code>finally</code> is for; in ordinary control flow, it runs before control leaves the <code>try</code>/<code>catch</code>/<code>finally</code> statement:</p>
<pre><code class="language-java">FileReader reader = null;
try {
    reader = new FileReader(filename);
    // read the file
} catch (IOException e) {
    System.out.println(&quot;Error reading file: &quot; + e.getMessage());
} finally {
    if (reader != null) {
        try { reader.close(); } catch (IOException e) { /* report */ }
    }
}
</code></pre>
<p>For resources that implement <code>AutoCloseable</code>, modern Java offers try-with-resources, which calls <code>close()</code> for you at the end of the block and replaces most uses of <code>finally</code>.</p>
<p>Two habits are worth forming. Catch specific types, not the blanket <code>Exception</code>, so you can respond to each failure on its own terms. And do not swallow exceptions: a <code>catch</code> block that does nothing hides the bug and lets the program limp along as if nothing happened. You do not have to solve the problem in the <code>catch</code> block, but you should at least report it.</p>
<h2 id="java-s-checked-vs-unchecked-exceptions" tabindex="-1"><a href="https://madooei.com/posts/java-exceptions/#java-s-checked-vs-unchecked-exceptions" class="header-anchor">Java's Checked vs. Unchecked Exceptions</a></h2>
<p>Every exception in Java is part of a class hierarchy rooted at <code>Throwable</code>:</p>
<pre><code class="language-plaintext">                         Throwable
                             |
              ┌──────────────┴──────────────┐
            Error                        Exception
     (OutOfMemoryError)                       |
     (StackOverflowError)        ┌────────────┼────────────┐
                           RuntimeException  IOException  SQLException
                                 |                 |           |
                   (NullPointerException)        ...         ...
                   (IndexOutOfBoundsException)
                   (IllegalArgumentException)
</code></pre>
<p><code>Error</code> covers system-level problems we usually cannot recover from, such as running out of memory; we do not normally catch these. The exceptions we usually write and handle are under <code>Exception</code>, and <code>Exception</code> splits into two camps.</p>
<p>An <strong>unchecked exception</strong>, in everyday discussion, is any class that extends <code>RuntimeException</code>. More precisely, Java's unchecked throwables are <code>RuntimeException</code>, <code>Error</code>, and their subclasses. The compiler does not force you to catch or declare unchecked throwables; you can let them propagate without writing anything. In data-structure code, unchecked exceptions usually signal a programming error — a null you forgot to check, an index off the end. The compiler cannot detect these for you, so it stays quiet and lets them surface at runtime.</p>
<p>A <strong>checked exception</strong> extends <code>Exception</code> but not <code>RuntimeException</code>. The compiler tracks these: if a method can throw one, you must either catch it or declare it on the method signature with <code>throws</code>. Checked exceptions usually signal a problem from <em>outside</em> the program — a missing file, a dropped network connection, an unreachable database.</p>
<pre><code class="language-java">// will not compile: FileReader's constructor can throw FileNotFoundException,
// which is a kind of IOException
public void read() {
    FileReader file = new FileReader(&quot;data.txt&quot;);
}

// handle it locally
public void read() {
    try (FileReader file = new FileReader(&quot;data.txt&quot;)) {
        // read from file
    } catch (IOException e) {
        System.out.println(&quot;Could not read file: &quot; + e.getMessage());
    }
}

// or declare it and let the caller deal with it
public void read() throws IOException {
    try (FileReader file = new FileReader(&quot;data.txt&quot;)) {
        // read from file
    }
}
</code></pre>
<p>The choice between them usually comes down to the source of the failure. Programming errors — a bad index, a null argument, a precondition violation — point back at the code, and we use unchecked exceptions for those. Failures from the environment — file, network, database — are conditions a correct program should anticipate, and checked exceptions are often used for those. Java forces you to handle or declare checked failures and stays quiet about unchecked bugs.</p>
<p>For the data structures in this course, we use <em>unchecked</em> (runtime) exceptions. An out-of-bounds index, or a <code>remove</code> on an empty list, is a programming error: the client called us incorrectly. That is exactly what unchecked exceptions are for.</p>
<h2 id="custom-exceptions" tabindex="-1"><a href="https://madooei.com/posts/java-exceptions/#custom-exceptions" class="header-anchor">Custom Exceptions</a></h2>
<p>The built-in exceptions work, but they are generic:</p>
<pre><code class="language-java">throw new IllegalArgumentException(&quot;Invalid index&quot;);
throw new IllegalStateException(&quot;List is empty&quot;);
</code></pre>
<p>Sometimes a domain-specific exception reads more clearly, and the name alone tells the story in a stack trace. To write one, extend <code>RuntimeException</code> (since these are programming errors) and, optionally, carry structured data beyond the message. These are shown together for compactness; in a real Java project, each public exception class would usually live in its own file.</p>
<pre><code class="language-java">public class InvalidIndexException extends RuntimeException {
    private final int index;
    private final int size;

    public InvalidIndexException(int index, int size) {
        super(&quot;Index &quot; + index + &quot; out of bounds for size &quot; + size);
        this.index = index;
        this.size = size;
    }

    public int getIndex() { return index; }
    public int getSize() { return size; }
}

public class EmptyListException extends RuntimeException {
    public EmptyListException(String operation) {
        super(&quot;Cannot perform &quot; + operation + &quot; on empty list&quot;);
    }
}

public class NullElementException extends RuntimeException {
    public NullElementException() {
        super(&quot;List does not allow null elements&quot;);
    }
}
</code></pre>
<p>The message is for humans reading a stack trace; the <code>getIndex()</code> and <code>getSize()</code> accessors let a caller inspect what happened in code. Distinct types also let a caller respond to each failure on its own terms:</p>
<pre><code class="language-java">try {
    String name = names.get(index);
} catch (InvalidIndexException e) {
    System.out.println(&quot;Bad index &quot; + e.getIndex() + &quot; for size &quot; + e.getSize());
} catch (EmptyListException e) {
    System.out.println(&quot;List is empty: &quot; + e.getMessage());
}
</code></pre>
<p>The caller branches on the <em>kind</em> of failure, not on the text of a message.</p>
<h2 id="code-contracts" tabindex="-1"><a href="https://madooei.com/posts/java-exceptions/#code-contracts" class="header-anchor">Code Contracts</a></h2>
<p>Consider this simple abstraction:</p>
<pre><code class="language-java">public class CheckingAccount {
  private double balance;

  // Pre: amount &gt;= 0
  // Post: balance is increased by amount
  public void deposit(double amount) {
    // implementation omitted
  }

  // Pre: amount &gt;= 0 &amp;&amp; amount &lt;= balance
  // Post: balance is decreased by amount
  public void withdraw(double amount) {
    // implementation omitted
  }

  // Inv: balance &gt;= 0
  public double getBalance() {
    return balance;
  }
}
</code></pre>
<p>The &quot;Pre&quot; and &quot;Post&quot; comments are called <em>preconditions</em> and <em>postconditions</em>, respectively. They specify what must be true before a method is called (preconditions) and what will be true after the method is called (postconditions). The &quot;Inv&quot; comment is an <em>invariant</em>, which specifies a condition that must always be true for the object. We use this to describe our <em>code contract</em>: the obligations of the client and the guarantees of the implementation.</p>
<p>For example, the preconditions for <code>deposit</code> and <code>withdraw</code> specify what the client must ensure before calling these methods, and the postconditions specify what the implementation guarantees after the method is called. If the client violates the preconditions (e.g., by trying to deposit a negative amount or withdraw more than the balance), then the implementation is not obligated to fulfill the postconditions.</p>
<p>A contract written only as comments still relies on the client to honor it. A <em>robust</em> method goes further: it enforces its own preconditions and signals a violation with an exception, so a broken contract fails loudly instead of silently corrupting state.</p>
<h2 id="robust-methods" tabindex="-1"><a href="https://madooei.com/posts/java-exceptions/#robust-methods" class="header-anchor">Robust Methods</a></h2>
<p>A robust method does not trust the caller to have checked its preconditions; it checks them itself, and it does so <em>before</em> it changes any state. Validate everything first, then do the work:</p>
<pre><code class="language-java">public void add(int index, T element) {
    // validate first
    if (element == null) {
        throw new NullElementException();
    }
    if (index &lt; 0 || index &gt; size) {
        throw new InvalidIndexException(index, size);
    }
    // then perform the operation
    // ... implementation
}
</code></pre>
<p>The order matters. If a check fails, the method throws <em>now</em>, before any write, so the list is never left half-modified. A method that validates partway through its work can leave the object in an inconsistent state.</p>
<p>The other half is the message. When you throw, report both what went wrong and what you saw. Passing the offending <code>index</code> <em>and</em> the <code>size</code> produces &quot;Index 7 out of bounds for size 4,&quot; which is far more useful than &quot;invalid index.&quot;</p>
<p>This is the idea behind <strong>defensive programming</strong>: the data structure protects itself rather than trusting every caller to be careful. Validation lives in one place, inside the structure; the error surfaces immediately, at the call that caused it, instead of three operations later when some other method trips over the corrupted state; and every implementation of the same interface reports the same failure in the same way. The goal is an interface that is easy to use correctly and hard to use incorrectly.</p>
]]>
      </content:encoded>
      <pubDate>Mon, 01 Jun 2026 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>Generics and Type Erasure in Java</title>
      <link>https://madooei.com/posts/generics-and-type-erasure/</link>
      <guid isPermaLink="false">https://madooei.com/posts/generics-and-type-erasure/</guid>
      <description>
        Why new T[capacity] won't compile, and how one 2004 design decision — type erasure — explains a whole cluster of Java generics gotchas.
      </description>
      <content:encoded>
        <![CDATA[<p>If you've ever written a generic data structure in Java, you've probably run into a line that looks completely reasonable and yet refuses to compile:</p>
<pre><code class="language-java">T[] data = new T[capacity];   // does not compile
</code></pre>
<p>It feels like it should work. You can write <code>new String[capacity]</code> and <code>new int[capacity]</code>, so why not <code>new T[capacity]</code>? The answer is a single design decision Java made back in 2004, and once you understand it, a whole cluster of generic &quot;gotchas&quot; stops being mysterious. That decision is called <em>type erasure</em>. Let's work up to it.</p>
<h2 id="the-generic-array-problem" tabindex="-1"><a href="https://madooei.com/posts/generics-and-type-erasure/#the-generic-array-problem" class="header-anchor">The generic array problem</a></h2>
<p>Say we're building a small generic container, the kind of thing you write once and use with any element type:</p>
<pre><code class="language-java">public class Box&lt;T&gt; {
  private T[] data;

  public Box(int capacity) {
    data = new T[capacity];   // we'd love to write this
  }
}
</code></pre>
<p>The compiler stops us cold on that <code>new T[capacity]</code>. The usual fix is to allocate an array of <code>Object</code> and cast it to <code>T[]</code>:</p>
<pre><code class="language-java">@SuppressWarnings(&quot;unchecked&quot;)
public Box(int capacity) {
  data = (T[]) new Object[capacity];
}
</code></pre>
<p>The cast is <em>unchecked</em>, the compiler can't verify it, so it warns us, and we suppress the warning because <code>data</code> is private and we control every value that goes into it. From the outside, the box behaves exactly as if it held a real <code>T[]</code>.</p>
<p>This is the standard idiom. Java's own <code>ArrayList</code> does exactly this: it stores its elements in an <code>Object[]</code> and casts on the way out. But it raises an obvious question. Why can't we just write <code>new T[capacity]</code> and skip the dance?</p>
<h2 id="type-erasure" tabindex="-1"><a href="https://madooei.com/posts/generics-and-type-erasure/#type-erasure" class="header-anchor">Type erasure</a></h2>
<p>Here's the rule that explains it. <strong>Type erasure</strong> means generic type parameters exist only at compile time. The compiler uses them to check your code, and then it throws them away before your program runs.</p>
<p>So when you write this:</p>
<pre><code class="language-java">Box&lt;String&gt; b = new Box&lt;String&gt;(10);
</code></pre>
<p>the compiler checks every use of <code>b</code> against <code>String</code>, and then erases the type argument. At runtime, what's left behaves as if you'd written:</p>
<pre><code class="language-java">Box b = new Box(10);
</code></pre>
<p>The angle brackets are gone. The running program has no idea that <code>b</code> was ever a &quot;box of <code>String</code>.&quot; And that is precisely why <code>new T[capacity]</code> is illegal: building an array requires knowing its component type <em>at runtime</em>, and by the time the program runs, <code>T</code> has been erased. There's no concrete type left for the array creation to use, so the language disallows the syntax outright rather than let you create something unsound.</p>
<h2 id="what-else-erasure-explains" tabindex="-1"><a href="https://madooei.com/posts/generics-and-type-erasure/#what-else-erasure-explains" class="header-anchor">What else erasure explains</a></h2>
<p>The array restriction is the one people hit first, but it's not alone. Several of Java's generic limitations are the same fact wearing different hats:</p>
<ul>
<li><strong>All instantiations share one class.</strong> <code>Box&lt;String&gt;</code> and <code>Box&lt;Integer&gt;</code> compile to the same bytecode. There is only one <code>Box</code> class at runtime, not one per type argument.</li>
<li><strong><code>instanceof</code> can't ask about a type parameter.</strong> You can't write <code>x instanceof T</code>, and you can't write <code>b instanceof Box&lt;String&gt;</code>. The type argument isn't there at runtime to test against, so the check is meaningless and the compiler rejects it.</li>
<li><strong>You can't do <code>new T()</code> either</strong>, for the same reason <code>new T[]</code> fails: there's no concrete type to construct.</li>
</ul>
<p>None of these are arbitrary rules someone added to make your life harder. They all fall out of one decision: the type argument is not around at runtime to act on.</p>
<h2 id="why-java-erases" tabindex="-1"><a href="https://madooei.com/posts/generics-and-type-erasure/#why-java-erases" class="header-anchor">Why Java erases</a></h2>
<p>Other languages made different choices. C# keeps generic type information at runtime; C++ templates generate a separate concrete class for each type you use. So why did Java erase?</p>
<p>Because of history. Generics arrived in Java 5, in 2004, nearly a decade after the language shipped. By then there was already an enormous body of pre-generic code in the wild, code full of raw types like <code>List</code> and <code>ArrayList</code> with no angle brackets at all. The language designers wanted new generic code and old raw code to keep working together, in the same program, without a painful migration. Erasure made that possible: because <code>Box&lt;String&gt;</code> and a raw <code>Box</code> are the same type underneath, the new and the old interoperate seamlessly.</p>
<p>The limitations we walked through, the array problem, the missing runtime type, the broken <code>instanceof</code>, are the price Java paid for that backward compatibility. Whether it was the right call is a fun thing to argue about. But knowing <em>that</em> it was the call, and why, turns a pile of confusing compiler errors into a single idea you can reason about.</p>
<p>So the next time <code>new T[capacity]</code> won't compile, you'll know it isn't the compiler being difficult. It's just type erasure, doing exactly what it was designed to do.</p>
]]>
      </content:encoded>
      <pubDate>Sun, 31 May 2026 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>A Refresher on Logarithms</title>
      <link>https://madooei.com/posts/a-refresher-on-logarithms/</link>
      <guid isPermaLink="false">https://madooei.com/posts/a-refresher-on-logarithms/</guid>
      <description>
        Logarithms run through algorithm analysis — binary search, balanced trees, sorting. A from-scratch refresher built on the one idea they rest on: a logarithm is an exponent read backwards.
      </description>
      <content:encoded>
        <![CDATA[<p>If you are taking Data Structures with me, logarithms are about to show up everywhere: binary search, balanced trees, the cost of sorting. You met them in a math class once, and then you probably never used them again. This page is a refresher — no prior fluency assumed. Let's rebuild logarithms from the one idea they rest on.</p>
<h2 id="what-a-logarithm-actually-is" tabindex="-1"><a href="https://madooei.com/posts/a-refresher-on-logarithms/#what-a-logarithm-actually-is" class="header-anchor">What a logarithm actually is</a></h2>
<p>A logarithm is the inverse of exponentiation. That single sentence is the whole game.</p>
<p>Exponentiation asks: <em>start with a base, raise it to a power — what do you get?</em> A logarithm runs that backwards: <em>you know the base and the result; what was the power?</em></p>
<p>We write it like this:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9088em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span><span class="mspace" style="margin-right:1em;"></span><span class="mord text"><span class="mord">means</span></span><span class="mspace" style="margin-right:1em;"></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7144em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em;">y</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span><span class="mord">.</span></span></span></span></span></p>
<p>Read <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span></span></span></span> as &quot;the power you raise <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">b</span></span></span></span> to in order to get <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span>.&quot; The <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">b</span></span></span></span> is the <strong>base</strong>.</p>
<p>Let's pin this down with one concrete case we'll come back to throughout this page. Take base <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">8</span></span></span></span>:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">8</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8641em;"></span><span class="mord">3</span><span class="mspace" style="margin-right:1em;"></span><span class="mord text"><span class="mord">because</span></span><span class="mspace" style="margin-right:1em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">8.</span></span></span></span></span></p>
<p>That's it. <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">8</span></span></span></span> is just the answer to &quot;two to the <em>what</em> gives eight?&quot; — and the answer is three. Whenever a logarithm looks intimidating, translate it back into that question.</p>
<p>(Two small print conditions, so nothing surprises you later: the base <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">b</span></span></span></span> must be positive and not equal to <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>, and you can only take the log of a positive <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span>. You can't raise a positive base to any power and land on zero or a negative number, so those inputs have no answer.)</p>
<p>Two values fall straight out of the definition:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8641em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:1em;"></span><span class="mord text"><span class="mord">because</span></span><span class="mspace" style="margin-right:1em;"></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8389em;vertical-align:-0.1944em;"></span><span class="mord">1</span><span class="mpunct">,</span></span></span></span></span></p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">b</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8641em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:1em;"></span><span class="mord text"><span class="mord">because</span></span><span class="mspace" style="margin-right:1em;"></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">b</span><span class="mord">.</span></span></span></span></span></p>
<p>Anything to the zero power is one, so the log of one is always zero. And the base raised to the first power is itself, so the log of the base is always one.</p>
<h2 id="the-laws-of-logarithms" tabindex="-1"><a href="https://madooei.com/posts/a-refresher-on-logarithms/#the-laws-of-logarithms" class="header-anchor">The laws of logarithms</a></h2>
<p>There are three laws you'll lean on, plus a fourth for switching bases. Here they are together; we'll derive each one in the next section.</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:7.4607em;vertical-align:-3.4804em;"></span><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:3.9804em;"><span style="top:-6.5118em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span><span class="mclose">)</span></span></span><span style="top:-4.7018em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:-0.1667em;"></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size2">(</span></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.6954em;"><span style="top:-2.655em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em;">y</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.4811em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size2">)</span></span></span></span></span><span style="top:-2.8527em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8991em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span><span style="top:-0.8212em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:3.4804em;"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:3.9804em;"><span style="top:-6.5118em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span></span></span><span style="top:-4.7018em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span></span></span><span style="top:-2.8527em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span></span></span><span style="top:-0.8212em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.0573em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">b</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.0573em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.9301em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:3.4804em;"><span></span></span></span></span></span><span class="arraycolsep" style="width:1em;"></span><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:3.9804em;"><span style="top:-6.5118em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"></span></span><span style="top:-4.7018em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"></span></span><span style="top:-2.8527em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"></span></span><span style="top:-0.8212em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:3.4804em;"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:3.9804em;"><span style="top:-6.5118em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mord"></span><span class="mord text"><span class="mord">(product)</span></span></span></span><span style="top:-4.7018em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mord"></span><span class="mord text"><span class="mord">(quotient)</span></span></span></span><span style="top:-2.8527em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mord"></span><span class="mord text"><span class="mord">(power)</span></span></span></span><span style="top:-0.8212em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mord"></span><span class="mord text"><span class="mord">(change of base)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:3.4804em;"><span></span></span></span></span></span></span></span></span></span></span></span></p>
<p>These laws use the same conditions as before: the bases are positive and not equal to <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>, and every quantity inside a logarithm must be positive.</p>
<p>Notice the shape of the first three: multiplication on the inside turns into addition on the outside, division turns into subtraction, and a power turns into multiplication. A logarithm often knocks an operation down one level. That is exactly what made logarithms useful for hand calculation centuries ago, and it is why they tame the multiply-heavy counting we do when we analyze algorithms.</p>
<p>Before deriving anything, let's just <em>check</em> the product law on numbers we can verify by hand:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord">4</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">8</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">32</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mord">5</span><span class="mpunct">,</span><span class="mspace" style="margin-right:2em;"></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">4</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">8</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">3</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6922em;"></span><span class="mord">5.</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord amsrm">✓</span></span></span></span></span></p>
<p>Same answer both ways. Good. Now let's see <em>why</em>.</p>
<h2 id="where-the-laws-come-from" tabindex="-1"><a href="https://madooei.com/posts/a-refresher-on-logarithms/#where-the-laws-come-from" class="header-anchor">Where the laws come from</a></h2>
<p>Every law here is an exponent law wearing a disguise. The trick is the same each time: name the logs we're working with, rewrite everything as powers of <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">b</span></span></span></span>, and use the exponent rule we already know.</p>
<h3 id="the-product-law" tabindex="-1"><a href="https://madooei.com/posts/a-refresher-on-logarithms/#the-product-law" class="header-anchor">The product law</a></h3>
<p>We want to understand <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span><span class="mclose">)</span></span></span></span>. Start by naming the two logs on the right:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span><span class="mpunct">,</span><span class="mspace" style="margin-right:2em;"></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span><span class="mord">.</span></span></span></span></span></p>
<p>By the definition of a logarithm, that's the same as saying:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7144em;"></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7144em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">m</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9088em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">x</span><span class="mpunct">,</span><span class="mspace" style="margin-right:2em;"></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7144em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span><span class="mord">.</span></span></span></span></span></p>
<p>Now multiply <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span></span></span></span> by multiplying their power-of-<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">b</span></span></span></span> forms:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.7em;vertical-align:-1.1em;"></span><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6em;"><span style="top:-3.76em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span></span></span><span style="top:-2.26em;"><span class="pstrut" style="height:3em;"></span><span class="mord"></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.1em;"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6em;"><span style="top:-3.76em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7144em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">m</span></span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7144em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span></span></span></span></span></span><span style="top:-2.26em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8213em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">m</span><span class="mbin mtight">+</span><span class="mord mathnormal mtight">n</span></span></span></span></span></span></span></span></span><span class="mord">.</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.1em;"><span></span></span></span></span></span></span></span></span></span></span></span></p>
<p>The second line is the one exponent law we need: multiplying same-base powers adds the exponents. Now read that result back through the definition of a logarithm — <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">x</span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span></span></span></span> equals <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">b</span></span></span></span> raised to <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span>, so the log of <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">x</span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span></span></span></span> <em>is</em> <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span>:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span><span class="mord">.</span></span></span></span></span></p>
<p>That's the product law. Multiplication inside became addition outside, because multiplying powers adds their exponents.</p>
<h3 id="the-quotient-law" tabindex="-1"><a href="https://madooei.com/posts/a-refresher-on-logarithms/#the-quotient-law" class="header-anchor">The quotient law</a></h3>
<p>Same setup, division instead of multiplication. With <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.6644em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">m</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span> and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.6644em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span></span></span></span>:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:3.7519em;vertical-align:-1.6259em;"></span><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.1259em;"><span style="top:-4.1259em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.1076em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em;">y</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.8804em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span><span style="top:-2.1055em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.6259em;"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.1259em;"><span style="top:-4.1259em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.5904em;"><span style="top:-2.989em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.6644em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">m</span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span><span style="top:-2.1055em;"><span class="pstrut" style="height:3.3714em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8213em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">m</span><span class="mbin mtight">−</span><span class="mord mathnormal mtight">n</span></span></span></span></span></span></span></span></span><span class="mord">.</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.6259em;"><span></span></span></span></span></span></span></span></span></span></span></span></p>
<p>Dividing same-base powers subtracts the exponents. Reading it back:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.4em;vertical-align:-0.95em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:-0.1667em;"></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size3">(</span></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.1076em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em;">y</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.8804em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size3">)</span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span><span class="mord">.</span></span></span></span></span></p>
<h3 id="the-power-law" tabindex="-1"><a href="https://madooei.com/posts/a-refresher-on-logarithms/#the-power-law" class="header-anchor">The power law</a></h3>
<p>Now <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0991em;vertical-align:-0.25em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8491em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span>. Name the inner log, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">m</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span></span></span></span>, so <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.6644em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">m</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span>. Then:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.8182em;vertical-align:-1.1591em;"></span><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6591em;"><span style="top:-3.76em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8991em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span></span></span></span></span></span></span></span></span></span><span style="top:-2.2009em;"><span class="pstrut" style="height:3em;"></span><span class="mord"></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.1591em;"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6591em;"><span style="top:-3.76em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7144em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">m</span></span></span></span></span></span></span></span><span class="mclose"><span class="mclose">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8991em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span></span></span></span></span></span></span></span></span></span><span style="top:-2.2009em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8991em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em;">mk</span></span></span></span></span></span></span></span></span><span class="mord">.</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.1591em;"><span></span></span></span></span></span></span></span></span></span></span></span></p>
<p>Raising a power to a power multiplies the exponents. So <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8491em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8491em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span></span></span></span></span></span></span></span></span></span></span> is <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">b</span></span></span></span> raised to <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">mk</span></span></span></span>, which means:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.1491em;vertical-align:-0.25em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8991em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0315em;">k</span></span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">mk</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mord mathnormal" style="margin-right:0.0315em;">k</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span><span class="mord">.</span></span></span></span></span></p>
<p>A power inside comes out front as a plain multiplier. This is the law that lets us pull an exponent down — we'll use it in a moment to switch bases.</p>
<h3 id="change-of-base" tabindex="-1"><a href="https://madooei.com/posts/a-refresher-on-logarithms/#change-of-base" class="header-anchor">Change of base</a></h3>
<p>Calculators and the laws above are happy in any base, but the log on your calculator is usually base <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">10</span></span></span></span> or base <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">e</span></span></span></span>, while in algorithms we almost always want base <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span>. So we need a way to compute <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span></span></span></span> using some other base <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">c</span></span></span></span> we <em>can</em> evaluate.</p>
<p>Let <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span></span></span></span>, which means <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.6644em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em;">y</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span>. Both sides are equal, so their logs in base <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">c</span></span></span></span> are equal too:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.7em;vertical-align:-1.1em;"></span><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6em;"><span style="top:-3.76em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.0573em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7144em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em;">y</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span><span style="top:-2.26em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em;">y</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.0573em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.1em;"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6em;"><span style="top:-3.76em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.0573em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span></span></span><span style="top:-2.26em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.0573em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span><span class="mord">.</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.1em;"><span></span></span></span></span></span></span></span></span></span></span></span></p>
<p>The second line is just the power law applied to the left side — it pulled the exponent <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span></span></span></span> out front. Now solve for <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span></span></span></span> by dividing:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.3016em;vertical-align:-0.9301em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.0573em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">b</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.0573em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.9301em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>And <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">y</span></span></span></span> was <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span></span></span></span> all along, so:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.242em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">b</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.3016em;vertical-align:-0.9301em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.0573em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">b</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.0573em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.9301em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span></p>
<p>Let's confirm it on our running example, getting <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">8</span></span></span></span> out of base-<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">10</span></span></span></span> logs:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">8</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.3016em;vertical-align:-0.9301em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">10</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">10</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">8</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.9301em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">0.301</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">0.903</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6922em;"></span><span class="mord">3.</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord amsrm">✓</span></span></span></span></span></p>
<p>There's a quiet payoff hiding here. Changing the base only ever divides by a constant (<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.0573em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">b</span></span></span></span> doesn't depend on <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span>). So <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span></span></span></span>, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">10</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span></span></span></span>, and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span></span></span></span> differ only by a constant factor. When we care about how a cost <em>grows</em> rather than its exact value, the base of the logarithm stops mattering — which is why you'll often see people write just &quot;<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span></span></span></span>&quot; and not fuss over the base.</p>
<h2 id="where-this-shows-up-in-algorithm-analysis" tabindex="-1"><a href="https://madooei.com/posts/a-refresher-on-logarithms/#where-this-shows-up-in-algorithm-analysis" class="header-anchor">Where this shows up in algorithm analysis</a></h2>
<p>Two quick examples, both built on the same observation: <strong>doubling and halving are the operations logarithms count.</strong></p>
<h3 id="binary-search-counting-halvings" tabindex="-1"><a href="https://madooei.com/posts/a-refresher-on-logarithms/#binary-search-counting-halvings" class="header-anchor">Binary search: counting halvings</a></h3>
<p>Binary search looks for a value in a sorted array by checking the middle, then throwing away the half that can't contain the target. Each comparison either finds the target or cuts the remaining range roughly in half. Start with <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span> candidates:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">→</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1.7936em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.1076em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">→</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1.7936em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.1076em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">4</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">→</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.3669em;"></span><span class="minner">⋯</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">→</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1.</span></span></span></span></span></p>
<p>After <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span> halvings the range has size about <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">n</span><span class="mord">/</span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.6644em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">x</span></span></span></span></span></span></span></span></span></span></span>. Ignoring the small off-by-one details for the moment, the search is down to a single candidate when:</p>
<p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:4.7936em;vertical-align:-2.1468em;"></span><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.6468em;"><span style="top:-4.6468em;"><span class="pstrut" style="height:3.1076em;"></span><span class="mord"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.1076em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.5904em;"><span style="top:-2.989em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">x</span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span><span style="top:-2.8208em;"><span class="pstrut" style="height:3.1076em;"></span><span class="mord"><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7144em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">x</span></span></span></span></span></span></span></span></span></span><span style="top:-1.3208em;"><span class="pstrut" style="height:3.1076em;"></span><span class="mord"><span class="mord mathnormal">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:2.1468em;"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.6468em;"><span style="top:-4.6468em;"><span class="pstrut" style="height:3.1076em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord">1</span></span></span><span style="top:-2.8208em;"><span class="pstrut" style="height:3.1076em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord mathnormal">n</span></span></span><span style="top:-1.3208em;"><span class="pstrut" style="height:3.1076em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mord">.</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:2.1468em;"><span></span></span></span></span></span></span></span></span></span></span></span></p>
<p>The middle line just multiplies both sides by <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6644em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.6644em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">x</span></span></span></span></span></span></span></span></span></span></span>; the last line reads <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6644em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.6644em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">x</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span> through the definition of a logarithm — <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">x</span></span></span></span> is the power of <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span> that gives <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span>. So binary search takes on the order of <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span></span></span></span> comparisons. The exact worst-case count has a small rounding/off-by-one term, but the growth is logarithmic.</p>
<p>Check it against our running case. With <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">8</span></span></span></span>: <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">8</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">→</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">4</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">→</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">→</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> is three halvings, and <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">8</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">3</span></span></span></span>. Depending on exactly when the target is found, binary search may use one more comparison than the number of halvings, but the logarithm is the part that controls the growth. That's the whole reason a sorted array is worth the trouble — searching a million elements costs about <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">1</span><span class="mord"><span class="mpunct">,</span></span><span class="mord">000</span><span class="mord"><span class="mpunct">,</span></span><span class="mord">000</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">20</span></span></span></span> comparisons, not a million.</p>
<h3 id="counting-bits-the-inverse-direction" tabindex="-1"><a href="https://madooei.com/posts/a-refresher-on-logarithms/#counting-bits-the-inverse-direction" class="header-anchor">Counting bits: the inverse direction</a></h3>
<p>Here's the same idea running the other way. For a positive integer <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span>, how many binary digits — bits — do you need to write the number <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span>?</p>
<p>Each bit you add <em>doubles</em> how many values you can represent. With <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span></span></span></span> bits you can write <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8491em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8491em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">d</span></span></span></span></span></span></span></span></span></span></span> different numbers, namely <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span> through <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9324em;vertical-align:-0.0833em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8491em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">d</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>. So to have a code for every value from <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span> through <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span>, you need enough bits that <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9851em;vertical-align:-0.136em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8491em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">d</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≥</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>. Solving the rough version, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8491em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8491em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">d</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span>, for <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span></span></span></span> gives <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span></span></span></span> — the same log, because doubling-per-bit is just halving-per-step read backwards.</p>
<p>Pinned to a number: <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">8</span></span></span></span> in binary is <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1000</span></span></span></span>, which is <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">4</span></span></span></span> bits. The exact count is <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">⌊</span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span><span class="mclose">⌋</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> for <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7719em;vertical-align:-0.136em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">≥</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span>, so for <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">8</span></span></span></span> we get <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">⌊</span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">8</span><span class="mclose">⌋</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">3</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">4</span></span></span></span>. (The floor and the <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">+</span><span class="mord">1</span></span></span></span> are bookkeeping for the off-by-one; the <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span></span></span></span> is the part that matters.)</p>
<h2 id="the-take-home-message" tabindex="-1"><a href="https://madooei.com/posts/a-refresher-on-logarithms/#the-take-home-message" class="header-anchor">The take-home message</a></h2>
<p>A logarithm answers one question: <em>what power gives this number?</em> Every law is an exponent law read through that lens — products become sums, powers become multipliers, and changing the base only ever costs a constant factor. In this course, <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9386em;vertical-align:-0.2441em;"></span><span class="mop"><span class="mop">lo<span style="margin-right:0.0139em;">g</span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.207em;"><span style="top:-2.4559em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2441em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">n</span></span></span></span> captures the number of times you can halve <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span> before reaching <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span> (exactly when <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">n</span></span></span></span> is a power of <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span>, and up to rounding otherwise). Keep that picture in mind and the cost of binary search, balanced trees, and good sorting algorithms will all read the same way.</p>
]]>
      </content:encoded>
      <pubDate>Fri, 29 May 2026 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>On Full-Stack Development in the Age of AI</title>
      <link>https://madooei.com/posts/on-fullstack-and-ai/</link>
      <guid isPermaLink="false">https://madooei.com/posts/on-fullstack-and-ai/</guid>
      <description>
        Should you still learn full-stack development when AI can generate applications? An honest assessment of the changing landscape for junior developers.
      </description>
      <content:encoded>
        <![CDATA[<p>A student recently asked me a question I'm sure many others are wondering about:</p>
<blockquote>
<p>How important is full stack development given that AI coding tools can now generate full stack applications fairly reliably? If it's still worth pursuing, which stack would you recommend learning?</p>
</blockquote>
<p>It's a fair question. I teach a course called Full-Stack JavaScript, and I'd be concerned too if I were a student watching AI agents generate complete applications. Let me give you an honest answer, even if it's not entirely reassuring.</p>
<p>The short version: Yes, I still think learning full-stack development is valuable. But the landscape is changing in ways that are uncomfortable to acknowledge.</p>
<h2 id="why-this-course-exists" tabindex="-1"><a href="https://madooei.com/posts/on-fullstack-and-ai/#why-this-course-exists" class="header-anchor">Why This Course Exists</a></h2>
<p>First, let's be clear about something. I didn't create Full-Stack JavaScript out of love for JavaScript or passion for full-stack development. I created it to help students be job ready. That was my sole intention—to give you the skills needed to work as software developers, particularly building applications that businesses actually need.</p>
<p>The question is whether that preparation still makes sense when AI can do much of what we teach in that course.</p>
<h2 id="the-complexity-spectrum" tabindex="-1"><a href="https://madooei.com/posts/on-fullstack-and-ai/#the-complexity-spectrum" class="header-anchor">The Complexity Spectrum</a></h2>
<p>To understand where AI fits, think about software projects along multiple axes of difficulty:</p>
<ul>
<li><strong>Problem familiarity</strong>: conventional → novel</li>
<li><strong>Algorithmic complexity</strong>: low → high</li>
<li><strong>Specification clarity</strong>: precise → ambiguous</li>
<li><strong>Architectural scope</strong>: localized → distributed</li>
<li><strong>External integrations</strong>: none → many</li>
<li><strong>Environment complexity</strong>: simple → complex (setup, build, deployment)</li>
<li><strong>State and data complexity</strong>: stateless → heavy state management</li>
<li><strong>Concurrency requirements</strong>: single-threaded → highly concurrent</li>
<li><strong>Non-functional constraints</strong>: minimal → strict (performance, security, compliance)</li>
<li><strong>Robustness requirements</strong>: basic → mission-critical</li>
<li><strong>Tool/API volatility</strong>: stable → rapidly changing</li>
<li><strong>UI/UX complexity</strong>: simple forms → complex flows</li>
<li><strong>Backward compatibility</strong>: greenfield → legacy integration</li>
<li>And more...</li>
</ul>
<p>The simpler a project is on each axis, the better AI coding agents do. As complexity rises along any of these dimensions, they struggle more, the same way a human developer would.</p>
<h2 id="where-ai-stands-today" tabindex="-1"><a href="https://madooei.com/posts/on-fullstack-and-ai/#where-ai-stands-today" class="header-anchor">Where AI Stands Today</a></h2>
<p>The hard part to admit is this: AI coding agents are excellent at the simpler-to-moderate levels of this spectrum. They can do very well what a junior software developer can do. Everything I teach in Full-Stack JavaScript—setting up servers, creating REST APIs, building React frontends, connecting to databases, deploying applications—AI can do with flying colors, much better than students just learning these skills. (And these tools keep getting better, with no sign of slowing down.)</p>
<p>But it hasn't bridged the gap to become completely autonomous. It's not yet at the &quot;build me X and it shall be&quot; stage. You still need a human co-pilot to guide it, validate its decisions, catch its mistakes, and handle the ambiguous parts.</p>
<p>Current evidence suggests that AI copilots work best with senior developers. Senior + AI is more productive than Senior + Junior. This creates an obvious incentive: replace junior developers with AI.</p>
<h2 id="the-market-reality" tabindex="-1"><a href="https://madooei.com/posts/on-fullstack-and-ai/#the-market-reality" class="header-anchor">The Market Reality</a></h2>
<p>This isn't speculation. The data (see [1] and [2]) is already showing the shift:</p>
<p>Junior roles are shrinking. Studies across 250,000 firms show that headcount for early-career software developers (ages 22-25) has been dropping steadily, right as AI coding tools spread.</p>
<p>Senior roles are growing. Headcount for developers aged 31 and up keeps expanding, and companies struggle to find enough senior engineers, poaching talent or buying whole companies just to secure capable developers.</p>
<p>And firms are cutting junior hiring on purpose. They're reducing the roles they expect to automate, because they see it as cheaper than future layoffs: cut the hiring now rather than lay people off later.</p>
<h2 id="the-paradox" tabindex="-1"><a href="https://madooei.com/posts/on-fullstack-and-ai/#the-paradox" class="header-anchor">The Paradox</a></h2>
<p>Here's the problem: you can't create a course that directly turns someone into a senior developer. Senior developers are made through years of experience, starting as juniors and growing through mistakes, projects, and mentorship.</p>
<p>This creates two possible futures:</p>
<p><strong>Scenario 1</strong>: You start learning now, but before you develop senior-level skills, AI closes the gap. It becomes fully autonomous, handles complex projects, and junior-to-mid-level developers are no longer needed. You're out of luck.</p>
<p><strong>Scenario 2</strong>: You start learning now, but AI fails to close the gap. The industry suffers from its reduction in junior roles. As current seniors retire, there aren't enough people to replace them because we stopped training juniors. You become extremely valuable.</p>
<p>I hope the second scenario happens. Unfortunately, major companies seem to be betting on the first.</p>
<h2 id="so-should-you-take-the-course" tabindex="-1"><a href="https://madooei.com/posts/on-fullstack-and-ai/#so-should-you-take-the-course" class="header-anchor">So Should You Take the Course?</a></h2>
<p>Despite all this, my answer is still yes—but with clear eyes about what you're getting into.</p>
<p>You need to understand the fundamentals. Even if AI is writing the code, someone has to know whether that code makes sense, whether the architecture is sound, whether the security implications have been considered. You can't guide an AI copilot well if you don't understand what you're asking it to build.</p>
<p>The complexity spectrum matters here. The full-stack development we teach sits at the simpler end on purpose, but you need those fundamentals before you can tackle the complex problems AI still can't handle on its own. You have to crawl before you walk.</p>
<p>Speed matters. If you're going to beat the AI gap, you can't take the leisurely four-year path. Learn intensively, build real projects, contribute to meaningful work, and move from junior to mid-level as fast as you can. The clock is ticking.</p>
<p>Depth still beats breadth. Don't try to learn every framework and stack. Pick one, learn it deeply, understand the principles, and get good at solving real problems. The ability to think through hard technical challenges is what will set you apart from AI. (Think about that the next time you're signing up for another humanities course!)</p>
<h2 id="what-about-which-stack" tabindex="-1"><a href="https://madooei.com/posts/on-fullstack-and-ai/#what-about-which-stack" class="header-anchor">What About Which Stack?</a></h2>
<p>You might be tempted by another angle: since AI coding agents are better at popular stacks (trained on more data, better documentation, more Stack Overflow answers), maybe you should learn something esoteric to gain an edge. This is a mistake. You're trying to compete with AI, and you can't win that game. AI will eventually cover the esoteric stacks too, and you'll have spent your time learning technologies with smaller job markets and fewer resources. You'll have optimized for being different from AI rather than being good at building software.</p>
<p>Put AI aside. Don't make your technology choices based on what AI can or can't do. Make them based on what you need to learn to build real applications and get real jobs. If you want to build web applications, learn JavaScript and its popular frameworks and libraries—that's where the jobs are. If you want to work on machine learning or data science, learn Python and its ecosystem. Pick something practical with real market demand, go deep, and build things that matter.</p>
<p>Whatever stack or domain you choose, learn to use AI well within it. The future isn't about competing with AI; it's about working alongside it. Learn the fundamentals deeply enough that you can guide AI tools, validate their output, and catch their mistakes. Use AI to accelerate your development, not to replace your understanding. The developers who thrive won't be the ones who avoid AI or try to outrun it; they'll be the ones who understand their craft well enough to make AI a force multiplier.</p>
<p>There's a catch, though: using AI while you're still learning can get in the way of that learning if you're not careful. There's a real tension between learning to use AI and using AI to learn. I'll write more about how to navigate this in a future post, but for now, be mindful of the difference between using AI as a tutor and using it as a ghost writer.</p>
<h2 id="the-honest-bottom-line" tabindex="-1"><a href="https://madooei.com/posts/on-fullstack-and-ai/#the-honest-bottom-line" class="header-anchor">The Honest Bottom Line</a></h2>
<p>I can't promise that learning full-stack development will help you get a job in five years. The industry is changing too rapidly, and the AI capabilities are advancing too quickly for anyone to make that promise honestly.</p>
<p>What I can say is this: understanding how to build software systems, even if AI is doing the typing, remains valuable. The question is whether that value translates to employment opportunities at the junior level, or whether you'll need to accelerate past that tier before the market for junior developers disappears entirely.</p>
<p>It's a gamble. But it's a more informed gamble than going in blind.</p>
<p>If you're going to make this bet, make it count. Don't just complete the assignments. Build real things. Contribute to open source. Work on projects that challenge you. Aim to be mid-level capable by the time you graduate, not entry-level.</p>
<p>The industry is changing. How you adapt to that change will matter more than which stack you choose to learn.</p>
<hr>
<p><strong>References:</strong></p>
<ul>
<li>[1] Hosseini Maasoum, Seyed Mahdi and Hosseini Maasoum, Seyed Mahdi and Lichtinger, Guy, Generative AI as Seniority-Biased Technological Change: Evidence from U.S. Résumé and Job Posting Data (August 31, 2025). Available at SSRN: https://ssrn.com/abstract=5425555 or http://dx.doi.org/10.2139/ssrn.5425555</li>
<li>[2] Brynjolfsson, Erik, Bharat Chandar, and Ruyu Chen. &quot;Canaries in the coal mine? six facts about the recent employment effects of artificial intelligence.&quot; Stanford Digital Economy Lab. Published August (2025). Available at: https://digitaleconomy.stanford.edu/wp-content/uploads/2025/08/Canaries_BrynjolfssonChandarChen.pdf</li>
</ul>
]]>
      </content:encoded>
      <pubDate>Thu, 13 Nov 2025 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>On Course Load and Learning: Why Less is More</title>
      <link>https://madooei.com/posts/on-course-load-and-learning/</link>
      <guid isPermaLink="false">https://madooei.com/posts/on-course-load-and-learning/</guid>
      <description>
        An argument for taking fewer courses, pursuing depth over breadth, and choosing challenge over convenience in undergraduate education.
      </description>
      <content:encoded>
        <![CDATA[<p>If you're like many smart, motivated students, you stack a heavy course load, add extracurriculars, and end up overwhelmed—still feeling you haven't done enough. Your semester can feel like chasing a train that never stops long enough to board. The intent is to make the most of your undergraduate years; the result is burnout, superficial learning, and missed opportunities for genuine intellectual growth.</p>
<p>My advice is simple: take fewer courses. Focus on depth over breadth. Choose challenge over convenience. For most undergraduates, fewer courses done thoroughly is the wiser default.</p>
<p>Graduating early: Taking more courses can let you finish in three years and save on tuition and housing. If you face serious financial constraints, consider this path. For most students who can afford the standard four years, the depth and time for advanced work outweigh the cost savings; graduating early often means sacrificing depth of learning—the real value of your undergraduate education.</p>
<p>If you can afford the full four years (for example, because you're on a full scholarship), you may still feel pressure to overload on courses and extracurriculars. There is a pervasive belief that more is better—that piling on courses, majors, and activities will lead to a richer experience and more opportunities after graduation. After all, whether you take 12 credits or 21+ credits, you still pay the same tuition. Why not get the most out of it? Course registration can start to resemble an all‑you‑can‑eat buffet. That's where the logic falters. Here's the case for less being more.</p>
<h2 id="the-math-doesn-t-work" tabindex="-1"><a href="https://madooei.com/posts/on-course-load-and-learning/#the-math-doesn-t-work" class="header-anchor">The Math Doesn't Work</a></h2>
<p>Let's start with basic arithmetic. The federal definition of a credit hour is this: one hour of classroom instruction plus a <em>minimum</em> of two hours of out-of-class work per week equals one credit hour. That's three hours total per credit, per week (in a typical semester), as a minimum. So, for example, if you're taking a 3-credit course, you should expect to spend at least 9 hours per week on that course (3 hours in class + 6 hours studying at home). There are exceptions, of course! For example, a lab course may require much less outside work, while a project-based course may require much more. But as a general rule of thumb, this is the standard.</p>
<p>A full-time student is one whose primary occupation is studying. Full-time employment is typically considered to be around 40 hours per week. Therefore, a full-time student should be dedicating approximately 40 hours per week to their studies. At 12 credits (the minimum for full-time status at Hopkins), that's 36 hours per week. At 15 credits (a typical course load of 3–4 courses), you're at 45 hours—already above the 40-hour mark.</p>
<p>If you take 18–21 credits, that's 54–63 hours per week just for coursework. Now add in extracurriculars (research projects, student clubs, applying for internships, etc.), personal responsibilities, and perhaps a part-time job. It becomes unsustainable. Something has to give, and what gives is depth of learning.</p>
<p>While it's true that some courses require less work, that's usually at the expense of rigor and depth. An easy or superficial course can help you check a box, satisfy a requirement, or boost your GPA, but it won't grow you intellectually the way a hard one will. And that growth is the point of an undergraduate education, especially in engineering. Paying tuition for an easy A that amounts to busywork, while skipping the advanced courses that demand real effort (the ones you're unlikely to study on your own, outside the scaffolding of a class), is a poor trade when time is zero-sum. I'd take the B+ in a rigorous course over the easy A.</p>
<p>The credit-hour math is a minimum. In practice, most technical courses routinely exceed it, so you'll likely spend more time than that. And even if you push well past 50–60 hours a week, there's a ceiling on how much a person can absorb: the brain has finite attention and processing capacity, and piling on more courses past that point just lowers the quality of what you learn.</p>
<h2 id="the-multiple-major-trap" tabindex="-1"><a href="https://madooei.com/posts/on-course-load-and-learning/#the-multiple-major-trap" class="header-anchor">The Multiple Major Trap</a></h2>
<p>It's common to see students major in two or more fields, often adding a minor or two for good measure. In principle, in fields with shared cores (e.g., CS + Applied Math), a second major or minor can formalize complementary depth and perhaps open doors for interdisciplinary work. In practice, however, when you commit to multiple majors within a fixed timeframe (typically four years and within a fixed credit cap), each additional major forces you to optimize for breadth over depth. Your learning becomes a series of requirements to satisfy rather than a coherent intellectual journey. You take the courses you <em>must</em> take, not necessarily the ones you <em>should</em> take.</p>
<p>What's worse is that many programs have adjusted their requirements to make double majors feasible. As multiple majors become common, the marginal signaling value of an additional major declines. What stands out beyond credential inflation is actual evidence of mastery: a thesis, research paper, open-source contributions, or performance in advanced electives—outcomes that require slack in the schedule.</p>
<h2 id="the-extracurricular-paradox" tabindex="-1"><a href="https://madooei.com/posts/on-course-load-and-learning/#the-extracurricular-paradox" class="header-anchor">The Extracurricular Paradox</a></h2>
<p>On top of an overloaded course schedule or multiple majors, you may try to maintain research positions in labs, participate in independent studies, lead clubs, and engage in various other activities—all simultaneously. The intent is admirable. The execution is often superficial.</p>
<p>When you spread yourself this thin, you can't give any single activity the attention it deserves. You do the bare minimum to put a checkmark next to each item on your resume. You're present, but you're not really engaged. You're participating, but you're not making meaningful contributions. Concentrated effort on fewer, harder things yields artifacts, references, and real competence.</p>
<h2 id="a-better-path" tabindex="-1"><a href="https://madooei.com/posts/on-course-load-and-learning/#a-better-path" class="header-anchor">A Better Path</a></h2>
<p>Here's what I recommend instead.</p>
<p>Take three or four courses a semester, and make them count. This fits both the federal credit-hour definition and the reality of deep learning. It gives you time to actually understand the material, to struggle with hard concepts, to go past the minimum.</p>
<p>Commit to a single major. Take the advanced courses. Take the ones that scare you a little. Build real expertise in your field. You can always take electives outside your major to explore other interests, without the pressure of satisfying a second major's requirements. No one ever got hired because they had two majors; they got hired because they were good at what they did.</p>
<p>Use summers for extracurriculars. If you want to do research, an independent study, or anything else, do it over the summer when you're not taking courses. Give each one the attention it deserves instead of spreading yourself thin. Take on one or two meaningful things across your whole degree, and stick with them rather than dabbling in many.</p>
<p>Choose challenge over convenience. Take the courses you wouldn't study on your own, where you'll learn from the professor's expertise and your classmates' perspectives. Take the ones that matter for the field you care about and genuinely challenge you. Avoid the &quot;easy A&quot; that doesn't stretch you. The goal is to grow, not to collect a good grade.</p>
<p>Plan for four years. Unless you have serious financial constraints, there's no prize for finishing early, especially if finishing early means you learned less. Many students who rush through in three years end up adding a master's year anyway. Slow down, take your time, and make it count.</p>
<h2 id="the-real-value" tabindex="-1"><a href="https://madooei.com/posts/on-course-load-and-learning/#the-real-value" class="header-anchor">The Real Value</a></h2>
<p>The value of higher education isn't in the number of degrees you collect, the majors and minors you accumulate, the courses you cram into each semester, or the activities you juggle. It's in the transformation that happens when you engage deeply with challenging material—when you have time to think, question, and connect ideas across domains. That transformation, not the transcript, is what will serve you for the next forty years of your career.</p>
<p>That's what I want for my students. Not more courses, more majors, more activities—but deeper learning, genuine challenge, and the time and space to become truly competent in your field.</p>
<p>Sometimes less really is more.</p>
]]>
      </content:encoded>
      <pubDate>Sun, 09 Nov 2025 00:00:00 GMT</pubDate>
    </item>
    <item>
      <title>Welcome</title>
      <link>https://madooei.com/posts/welcome/</link>
      <guid isPermaLink="false">https://madooei.com/posts/welcome/</guid>
      <description>A short note about why this site exists.</description>
      <content:encoded>
        <![CDATA[<p>This is the first post on the new site. The unit of content here is just a
<strong>post</strong> — sometimes that's a course page, sometimes a project log, sometimes
an opinion. Posts can be grouped together when they belong in a sequence (a
multi-part tutorial, a course's lectures), but the default is flat.</p>
<p>If you want a feed, <a href="https://madooei.com/feed.xml">here it is</a>.</p>
]]>
      </content:encoded>
      <pubDate>Wed, 30 Apr 2025 00:00:00 GMT</pubDate>
    </item>
  </channel>
</rss>