<?xml version="1.0"?>
<rss version="2.0.">
  <channel>
    <title>Advogato blog for fejj</title>
    <link>http://www.advogato.org/person/fejj/</link>
    <description>Advogato blog for fejj</description>
    <language>en-us</language>
    <generator>mod_virgule</generator>
    <pubDate>Sat, 17 May 2008 15:21:55 GMT</pubDate>
    <item>
      <pubDate>Mon, 5 Mar 2007 19:56:18 GMT</pubDate>
      <title>5 Mar 2007</title>
      <link>http://www.advogato.org/person/fejj/diary.html?start=177</link>
      <guid>http://www.advogato.org/person/fejj/diary.html?start=177</guid>
      <description>&lt;a href="http://www.advogato.org/person/fzort/" &gt;fzort&lt;/a&gt;: I think you mean Binary&#xD;
Insertion&#xD;
Sort and not Bubble Sort. The idea would be to use another&#xD;
in-place sorting algorithm that doesn't get hit hard when&#xD;
attempting to sort a segment that &lt;i&gt;may&lt;/i&gt; already be&#xD;
pre-sorted. No reason to use anything slower than you have&#xD;
to, and so Binary Insertion Sort fits nicely.&#xD;
&lt;p&gt; For historical reasons, a Binary Insertion Sort was&#xD;
probably also used to eliminate recursive function call&#xD;
overhead as well as stack overflows.&#xD;
&lt;p&gt; Note that while the binary search portion of the Binary&#xD;
Insertion Sort algorithm is recursive, since it is tail&#xD;
recursive, it can be implemented in such a way as to even&#xD;
avoid having to use an internal stack.&#xD;
&lt;p&gt; See the last implementation discussed &lt;a&#xD;
href="http://jeffreystedfast.blogspot.com/2007/02/binary-insertion-sort.html"&gt;here&lt;/a&gt;&#xD;
for an example on how to do that.&#xD;
&lt;p&gt; Thanks for the link too, btw, I will be sure to check&#xD;
that out later when I get home from work!</description>
    </item>
    <item>
      <pubDate>Sun, 4 Mar 2007 17:12:20 GMT</pubDate>
      <title>4 Mar 2007</title>
      <link>http://www.advogato.org/person/fejj/diary.html?start=176</link>
      <guid>http://www.advogato.org/person/fejj/diary.html?start=176</guid>
      <description>&lt;p&gt;&lt;a href="http://www.advogato.org/person/haruspex/" &gt;haruspex&lt;/a&gt;: Hence my&#xD;
comment above that line,&#xD;
&lt;blockquote&gt;&lt;cite&gt;If your program makes heavy use of a&#xD;
sorting routine, you may want to consider implementing a&#xD;
tailored sort function rather than just using&#xD;
qsort().&lt;/cite&gt;&lt;/blockquote&gt;&#xD;
&lt;p&gt;By no means do I suggest writing your own low-level&#xD;
routines for no reason... but if your program is spending a&#xD;
lot of time sorting, then you might consider writing a&#xD;
tailored sort routine. Obviously this wouldn't make sense if&#xD;
sorting is barely even on the radar as far as time spent in&#xD;
your program.&#xD;
&lt;p&gt;Hopefully this clarifies my position and the intent of my&#xD;
wording (which I admit may have been unclear).&#xD;
&lt;p&gt;Note, also, that all of my entries in my blog series on&#xD;
sorting start off with an unoptimized version of the sort&#xD;
routine, implementing them as closely to the description of&#xD;
the algorithm as I can. From there, in each entry, I went on&#xD;
to describe my mode of thinking on how to achieve better&#xD;
performance (largely as an educational challenge to myself)&#xD;
- e.g. I never suggest pre-optimizing.&#xD;
&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; more on sorting &lt;a&#xD;
href="http://jeffreystedfast.blogspot.com/search/label/sorting"&gt;here&lt;/a&gt;.</description>
    </item>
    <item>
      <pubDate>Sun, 4 Mar 2007 14:58:52 GMT</pubDate>
      <title>4 Mar 2007</title>
      <link>http://www.advogato.org/person/fejj/diary.html?start=175</link>
      <guid>http://www.advogato.org/person/fejj/diary.html?start=175</guid>
      <description>&lt;p&gt;Like &lt;i&gt;Merge Sort&lt;/i&gt;, &lt;i&gt;Quick Sort&lt;/i&gt; promises O(n lg&#xD;
n) time in the average case, and, like &lt;i&gt;Merge Sort&lt;/i&gt;, is&#xD;
also a recursive algorithm. However, it is important to be&#xD;
aware that &lt;i&gt;Quick Sort&lt;/i&gt; is O(n * n) worst case,&#xD;
where, ironically, the input is already mostly sorted in&#xD;
either direction.&#xD;
&lt;p&gt;The way &lt;i&gt;Quick Sort&lt;/i&gt; works is that it first chooses&#xD;
a pivot value with which to partition the working sequence&#xD;
into two segments. Next, it puts all items with values&#xD;
smaller than the pivot value into the first segment and all&#xD;
items with values greater than the pivot value into the&#xD;
second segment. Recursively repeat the process on each segment.&#xD;
&lt;p&gt;Lets put this into code (keeping our same call signature&#xD;
from previous sorting posts):&#xD;
&lt;pre style="font-family: courier new; font-size: 85%"&gt;&#xD;
static int&#xD;
QuickSortPartiton (int a[], int low, int high)&#xD;
{&#xD;
    int pivot, lo, hi;&#xD;
    int tmp;&#xD;
&lt;p&gt;    hi = high - 1;&#xD;
    lo = low;&#xD;
&lt;p&gt;    pivot = a[lo];&#xD;
&lt;p&gt;    while (1) {&#xD;
        while (lo &amp;lt; high &amp;amp;&amp;amp; a[lo] &amp;lt; pivot)&#xD;
            lo++;&#xD;
&lt;p&gt;        while (hi &amp;gt; low &amp;amp;&amp;amp; a[hi] &amp;gt;= pivot)&#xD;
            hi--;&#xD;
&lt;p&gt;        if (lo &amp;lt; hi) {&#xD;
            /* swap */&#xD;
            tmp = a[lo];&#xD;
            a[lo] = a[hi];&#xD;
            a[hi] = tmp;&#xD;
            hi--;&#xD;
        } else {&#xD;
            return hi + 1;&#xD;
        }&#xD;
    }&#xD;
}&#xD;
&lt;p&gt;static void&#xD;
QuickSortRecurse (int a[], int low, int high)&#xD;
{&#xD;
    int mid;&#xD;
&lt;p&gt;    mid = QuickSortPartition (a, low, high);&#xD;
    if (mid &amp;lt; high) {&#xD;
        QuickSortRecurse (a, low, mid);&#xD;
        QuickSortRecurse (a, mid, high);&#xD;
    }&#xD;
}&#xD;
&lt;p&gt;void&#xD;
QuickSort (int a[], int n)&#xD;
{&#xD;
    if (n &amp;lt; 2)&#xD;
        return;&#xD;
&lt;p&gt;    QuickSortRecurse (a, 0, n);&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;Before we go any further, lets see how this compares to&#xD;
our &lt;i&gt;Merge Sort&lt;/i&gt; implementation from earlier.&#xD;
&lt;p&gt;Since I no longer have the same machine that I timed&#xD;
&lt;i&gt;Merge Sort&lt;/i&gt; with, I had to re-time it on my laptop&#xD;
(which is where I've been doing this since I can hack while&#xD;
laying back on my comfortable couch). My laptop is an IBM&#xD;
T40 ThinkPad which sports an Intel Pentium M Processor rated&#xD;
at 1600 MHz.&#xD;
&lt;p&gt;Since I left off sorting 10,000,000 items in the Merge&#xD;
Sort post, I figured I'd use the same array size here.&#xD;
&lt;p&gt;For &lt;i&gt;Merge Sort&lt;/i&gt;, I'm consistently getting around&#xD;
6.96s. For our &lt;i&gt;Quick Sort&lt;/i&gt; implementation, I'm getting&#xD;
about 5.40s.&#xD;
&lt;p&gt;Not bad... but lets see if we can speed it up a bit more.&#xD;
The easiest change to make is to combine &lt;i&#xD;
style="font-family: courier new; font-size:&#xD;
85%"&gt;QuickSortPartition()&lt;/i&gt; into &lt;i style="font-family:&#xD;
courier new; font-size: 85%"&gt;QuickSortRecurse()&lt;/i&gt; in order&#xD;
to try and reduce extra function-call overhead. The&#xD;
resulting code is as follows:&#xD;
&lt;pre style="font-family: courier new; font-size: 85%"&gt;&#xD;
static void&#xD;
QuickSortRecurse (int a[], int low, int high)&#xD;
{&#xD;
    int pivot, lo, hi;&#xD;
    int tmp;&#xD;
&lt;p&gt;    hi = high - 1;&#xD;
    lo = low;&#xD;
&lt;p&gt;    pivot = a[lo];&#xD;
&lt;p&gt;    while (1) {&#xD;
        while (lo &amp;lt; high &amp;amp;&amp;amp; a[lo] &amp;lt; pivot)&#xD;
            lo++;&#xD;
&lt;p&gt;        while (hi &amp;gt; low &amp;amp;&amp;amp; a[hi] &amp;gt;= pivot)&#xD;
            hi--;&#xD;
&lt;p&gt;        if (lo &amp;lt; hi) {&#xD;
            /* swap */&#xD;
            tmp = a[lo];&#xD;
            a[lo] = a[hi];&#xD;
            a[hi] = tmp;&#xD;
            hi--;&#xD;
        } else {&#xD;
            hi++;&#xD;
            break;&#xD;
        }&#xD;
    }&#xD;
&lt;p&gt;    if (hi &amp;lt; high) {&#xD;
        QuickSortRecurse (a, low, hi);&#xD;
        QuickSortRecurse (a, hi, high);&#xD;
    }&#xD;
}&#xD;
&lt;p&gt;void&#xD;
QuickSort (int a[], int n)&#xD;
{&#xD;
    if (n &amp;lt; 2)&#xD;
        return;&#xD;
&lt;p&gt;    QuickSortRecurse (a, 0, n);&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;This new version gets times closer to 5.20s on average.&#xD;
&lt;p&gt;It would be nice if we could get rid of the function call&#xD;
overhead of recursion like we did with &lt;i&gt;Binary&#xD;
Insertion Sort&lt;/i&gt;, as we've seen that getting rid of&#xD;
the need to call out to &lt;i style="font-family: courier new;&#xD;
font-size: 85%"&gt;QuickSortPartition()&lt;/i&gt; improved the&#xD;
performance a bit (not much, but every little bit counts,&#xD;
right?).&#xD;
&lt;p&gt;We're going to have to get crafty in order to work around&#xD;
the need to make our function recursive. What we can do is&#xD;
keep our own stack, but growing it dynamically could&#xD;
potentially kill any performance gains we could hope for...&#xD;
so, lets see what Donald Knuth has to say about the&#xD;
mathematical properties of this sort algorithm.&#xD;
&lt;blockquote&gt;An auxiliary stack with at most [lg N] entries&#xD;
is needed for temporary storage.&lt;/blockquote&gt;&#xD;
&lt;p&gt;As it happens, log base 2 of the max unsigned value&#xD;
of any integer type is the number of bits in said integer&#xD;
type. This means that on my system, where integers are&#xD;
32bit, I'll need a stack size of 32.&#xD;
&lt;p&gt;What do we store on our stack? Well, what variables do we&#xD;
need for &lt;i style="font-family: courier new; font-size:&#xD;
85%"&gt;QuickSortRecurse()&lt;/i&gt;? We need &lt;i style="font-family:&#xD;
courier new; font-size: 85%"&gt;a[]&lt;/i&gt;, &lt;i style="font-family:&#xD;
courier new; font-size: 85%"&gt;high&lt;/i&gt;, and &lt;i&#xD;
style="font-family: courier new; font-size: 85%"&gt;low&lt;/i&gt;. If&#xD;
we're going to make &lt;i style="font-family: courier new;&#xD;
font-size: 85%"&gt;QuickSort()&lt;/i&gt; non-recursive, then that&#xD;
means we'll always have access to &lt;i style="font-family:&#xD;
courier new; font-size: 85%"&gt;a[]&lt;/i&gt; which means the only&#xD;
variables we need to hold on our stack are &lt;i&#xD;
style="font-family: courier new; font-size: 85%"&gt;high&lt;/i&gt;&#xD;
and &lt;i style="font-family: courier new; font-size: 85%"&gt;low&lt;/i&gt;.&#xD;
&lt;p&gt;So here it is, your &lt;i&gt;Moment of Zen&lt;/i&gt;:&#xD;
&lt;pre style="font-family: courier new; font-size: 85%"&gt;&#xD;
typedef struct qstack {&#xD;
    size_t lo;&#xD;
    size_t hi;&#xD;
} qstack_t;&#xD;
&lt;p&gt;void&#xD;
QuickSort (int a[], size_t n)&#xD;
{&#xD;
    qstack_t stack[32], *sp;&#xD;
    register size_t lo, hi;&#xD;
    size_t low, high;&#xD;
    int pivot, tmp;&#xD;
&lt;p&gt;    if (n &amp;lt; 2)&#xD;
        return;&#xD;
&lt;p&gt;    /* push our initial values onto the stack */&#xD;
    sp = stack;&#xD;
    sp-&amp;gt;lo = 0;&#xD;
    sp-&amp;gt;hi = n;&#xD;
    sp++;&#xD;
&lt;p&gt;    while (sp &amp;gt; stack) {&#xD;
        /* pop lo and hi off the stack */&#xD;
        sp--;&#xD;
        high = sp-&amp;gt;hi;&#xD;
        low = sp-&amp;gt;lo;&#xD;
&lt;p&gt;        hi = high - 1;&#xD;
        lo = low;&#xD;
&lt;p&gt;        pivot = a[lo];&#xD;
&lt;p&gt;        while (1) {&#xD;
            while (lo &amp;lt; high &amp;amp;&amp;amp; a[lo] &amp;lt; pivot)&#xD;
                lo++;&#xD;
&lt;p&gt;            while (hi &amp;gt; low &amp;amp;&amp;amp; a[hi] &amp;gt;= pivot)&#xD;
                hi--;&#xD;
&lt;p&gt;            if (lo &amp;lt; hi) {&#xD;
                /* swap */&#xD;
                tmp = a[lo];&#xD;
                a[lo] = a[hi];&#xD;
                a[hi] = tmp;&#xD;
                hi--;&#xD;
            } else {&#xD;
                hi++;&#xD;
&lt;p&gt;                if (hi == high) {&#xD;
                    /* done with this segment */&#xD;
                    break;&#xD;
                }&#xD;
&lt;p&gt;                /* push the larger segment onto the&#xD;
                 * stack and continue sorting the&#xD;
                 * smaller segment. */&#xD;
                if ((hi - low) &amp;gt; (high - hi)) {&#xD;
                    sp-&amp;gt;lo = low;&#xD;
                    sp-&amp;gt;hi = hi;&#xD;
                    sp++;&#xD;
&lt;p&gt;                    hi = high;&#xD;
                    low = lo;&#xD;
                } else {&#xD;
                    sp-&amp;gt;hi = high;&#xD;
                    sp-&amp;gt;lo = hi;&#xD;
                    sp++;&#xD;
&lt;p&gt;                    high = hi;&#xD;
                    lo = low;&#xD;
                }&#xD;
&lt;p&gt;                pivot = a[lo];&#xD;
                hi--;&#xD;
            }&#xD;
        }&#xD;
    }&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;Once again, we see a slight improvement in execution&#xD;
time: 4.59s, just a hair under 5.00s, down from ~5.20s.&#xD;
&lt;p&gt;Just a &lt;i&gt;bit&lt;/i&gt; faster, eh?&#xD;
&lt;p&gt;Out of my own interest, I've been reimplementing all of&#xD;
these sorting algorithms to target glibc's &lt;i&#xD;
style="font-family: courier new; font-size: 85%"&gt;qsort()&lt;/i&gt;&#xD;
API, so as to make any one of them a drop-in replacement&#xD;
(not that it's likely I'd do that, since until now, it's&#xD;
unlikely any of them could have even approached the speed of&#xD;
&lt;i style="font-family: courier new; font-size:&#xD;
85%"&gt;qsort()&lt;/i&gt;... ).&#xD;
&lt;p&gt;Without further ado, here it is, another &lt;i&gt;Moment of&#xD;
Zen&lt;/i&gt;:&#xD;
&lt;pre style="font-family: courier new; font-size: 85%"&gt;&#xD;
static void&#xD;
memswap (void *a, void *b, size_t n)&#xD;
{&#xD;
    register unsigned int *ai, *bi;&#xD;
    unsigned char *ac, *bc, *an;&#xD;
    register unsigned int i;&#xD;
    unsigned char c;&#xD;
&lt;p&gt;    an = (unsigned char *) a + n;&#xD;
    ai = (unsigned int *) a;&#xD;
    bi = (unsigned int *) b;&#xD;
&lt;p&gt;    while (((unsigned char *) (ai + 1)) &amp;lt;= an) {&#xD;
        i = *ai;&#xD;
        *ai++ = *bi;&#xD;
        *bi++ = i;&#xD;
    }&#xD;
&lt;p&gt;    ac = (unsigned char *) ai;&#xD;
    bc = (unsigned char *) bi;&#xD;
&lt;p&gt;    while (ac &amp;lt; an) {&#xD;
        c = *ac;&#xD;
        *ac++ = *bc;&#xD;
        *bc++ = c;&#xD;
    }&#xD;
}&#xD;
&lt;p&gt;typedef struct qstack {&#xD;
    unsigned char *lo;&#xD;
    unsigned char *hi;&#xD;
} qstack_t;&#xD;
&lt;p&gt;void&#xD;
QuickSort (void *base, size_t nmemb, size_t size,&#xD;
           int (* compare) (const void *, const void *))&#xD;
{&#xD;
    register unsigned char *lo, *hi, *pivot;&#xD;
    qstack_t stack[32], *sp = stack;&#xD;
    unsigned char *high, *low;&#xD;
&lt;p&gt;    if (nmemb &amp;lt; 2)&#xD;
        return;&#xD;
&lt;p&gt;    /* push our initial values onto the stack */&#xD;
    sp-&amp;gt;lo = (unsigned char *) base;&#xD;
    sp-&amp;gt;hi = sp-&amp;gt;lo + (nmemb * size);&#xD;
    sp++;&#xD;
&lt;p&gt;    while (sp &amp;gt; stack) {&#xD;
        /* pop lo and hi off the stack */&#xD;
        sp--;&#xD;
        high = sp-&amp;gt;hi;&#xD;
        low = sp-&amp;gt;lo;&#xD;
&lt;p&gt;        hi = high - size;&#xD;
        lo = low;&#xD;
&lt;p&gt;        pivot = lo;&#xD;
&lt;p&gt;        while (1) {&#xD;
            while (lo &amp;lt; high &amp;amp;&amp;amp; compare (lo,&#xD;
pivot) &amp;lt; 0)&#xD;
                lo += size;&#xD;
&lt;p&gt;            while (hi &amp;gt; low &amp;amp;&amp;amp; compare (hi,&#xD;
pivot) &amp;gt;= 0)&#xD;
                hi -= size;&#xD;
&lt;p&gt;            if (lo &amp;lt; hi) {&#xD;
                /* swap */&#xD;
                memswap (lo, hi, size);&#xD;
&lt;p&gt;                if (lo == pivot)&#xD;
                    pivot = hi;&#xD;
                else if (hi == pivot)&#xD;
                    pivot = lo;&#xD;
&lt;p&gt;                hi -= size;&#xD;
            } else {&#xD;
                hi += size;&#xD;
&lt;p&gt;                if (hi == high) {&#xD;
                    /* done with this segment */&#xD;
                    break;&#xD;
                }&#xD;
&lt;p&gt;                /* push the larger segment onto the&#xD;
                 * stack and continue sorting the&#xD;
                 * smaller segment. */&#xD;
                if ((hi - low) &amp;gt; (high - hi)) {&#xD;
                    sp-&amp;gt;lo = low;&#xD;
                    sp-&amp;gt;hi = hi;&#xD;
                    sp++;&#xD;
&lt;p&gt;                    hi = high;&#xD;
                    low = lo;&#xD;
                } else {&#xD;
                    sp-&amp;gt;hi = high;&#xD;
                    sp-&amp;gt;lo = hi;&#xD;
                    sp++;&#xD;
&lt;p&gt;                    high = hi;&#xD;
                    lo = low;&#xD;
                }&#xD;
&lt;p&gt;                pivot = lo;&#xD;
                hi -= size;&#xD;
            }&#xD;
        }&#xD;
    }&#xD;
}&#xD;
&lt;/pre&gt;&#xD;
&lt;p&gt;It turns out that my implementation is neck-and-neck with&#xD;
glibc's &lt;i style="font-family: courier new; font-size:&#xD;
85%"&gt;qsort()&lt;/i&gt; compiled at &lt;i style="font-family: courier&#xD;
new; font-size: 85%"&gt;-O0&lt;/i&gt;, but if I compile with &lt;i&#xD;
style="font-family: courier new; font-size: 85%"&gt;-Os&lt;/i&gt;, my&#xD;
implementation consistently takes the lead:&#xD;
&lt;p&gt;&lt;i style="font-family: courier new; font-size:&#xD;
85%"&gt;QuickSort()&lt;/i&gt; takes on average 12.82s while &lt;i&#xD;
style="font-family: courier new; font-size: 85%"&gt;qsort()&lt;/i&gt;&#xD;
takes about 12.98s. However, the integer tailored version of&#xD;
our &lt;i style="font-family: courier new; font-size:&#xD;
85%"&gt;QuickSort()&lt;/i&gt; only takes 6.46s on average.&#xD;
&lt;p&gt;If your program makes heavy use of a sorting routine, you&#xD;
may want to consider implementing a tailored sort function&#xD;
rather than just using &lt;i style="font-family: courier new;&#xD;
font-size: 85%"&gt;qsort()&lt;/i&gt;.&#xD;
&lt;p&gt;To prove the point further, if we restrict the input&#xD;
array to be made up of pointers (rather than arbitrarily&#xD;
sized elements), we can replace the &lt;i style="font-family:&#xD;
courier new; font-size: 85%"&gt;memswap()&lt;/i&gt; routine with a&#xD;
simple pointer swap. This simple change shaves a whole&#xD;
second off the execution time!&#xD;
&lt;p&gt;Not only can you tailor your sort implementation to be&#xD;
able to do faster swaps/comparisons, but you can also tailor&#xD;
it to be a "stable sort" (as I have done in these&#xD;
implementations), which is something that the libc &lt;i&#xD;
style="font-family: courier new; font-size: 85%"&gt;qsort()&lt;/i&gt;&#xD;
does not guarantee.&#xD;
&lt;p&gt;As Michael Abrash mentions in one of his books, there are&#xD;
a number of fallacies that programmers use to justify not&#xD;
hand-writing some of their low-level routines, one of which&#xD;
is the assumption that the C library is written in optimized&#xD;
assembly and therefore it's unlikely that you could possibly&#xD;
write a replacement routine faster yourself.&#xD;
&lt;p&gt;As I've just proven, this is &lt;i&gt;not&lt;/i&gt; the case. And I&#xD;
haven't even bothered to re-implement my &lt;i&gt;Quick Sort&lt;/i&gt;&#xD;
routine in highly optimized assembly yet!</description>
    </item>
    <item>
      <pubDate>Sun, 4 Mar 2007 14:43:43 GMT</pubDate>
      <title>4 Mar 2007</title>
      <link>http://www.advogato.org/person/fejj/diary.html?start=174</link>
      <guid>http://www.advogato.org/person/fejj/diary.html?start=174</guid>
      <description>I came across something cool the other day that I thought&#xD;
I'd share: a 25-byte long integer sort routine (that is to&#xD;
say, the routine itself is only 25 bytes long).&#xD;
&#xD;
&lt;p&gt; &lt;p&gt; &lt;p&gt; &lt;p&gt; Here it is:&#xD;
&lt;pre style="font-family: courier new; font-size: 85%"&gt;&#xD;
;---------------------------------------------------------------&#xD;
; Sorts an array of ints. C-callable (small model). 25 bytes.&#xD;
; void sort (int n, int a[]);&#xD;
;&#xD;
; Courtesy of David Stafford.&#xD;
;---------------------------------------------------------------&#xD;
&lt;p&gt;      .model small&#xD;
      .code&#xD;
        public _sort&#xD;
&lt;p&gt;top:    mov     dx,[bx]   ; swap two adjacent ints&#xD;
        xchg    dx,[bx+2]&#xD;
        xchg    dx,[bx]&#xD;
&lt;p&gt;        cmp     dx,[bx]   ; in the right order?&#xD;
        jl      top       ; no, swap them back&#xD;
&lt;p&gt;        inc     bx        ; go to the next integer&#xD;
        inc     bx&#xD;
        loop    top&#xD;
&lt;p&gt;_sort:  pop     dx        ; get return address (entry point)&#xD;
        pop     cx        ; get count&#xD;
        pop     bx        ; get pointer&#xD;
        push    bx        ; restore pointer&#xD;
        dec     cx        ; decrement count&#xD;
        push    cx        ; save count&#xD;
        push    dx        ; save return address&#xD;
        jg      top       ; if cx &amp;gt; 0&#xD;
&lt;p&gt;        ret&#xD;
&lt;p&gt;       end&#xD;
&lt;/pre&gt;&#xD;
</description>
    </item>
    <item>
      <pubDate>Thu, 1 Feb 2007 17:22:35 GMT</pubDate>
      <title>1 Feb 2007</title>
      <link>http://www.advogato.org/person/fejj/diary.html?start=173</link>
      <guid>http://www.advogato.org/person/fejj/diary.html?start=173</guid>
      <description>&lt;p&gt;&lt;a&#xD;
href="http://www.advogato.org/person/fzort/diary.html?start=56"&gt;fzort&lt;/a&gt;:&#xD;
Ah, thank you for the explanation :)&#xD;
&lt;p&gt;I was just about to note that expanding on my previous&#xD;
estimation, a slightly better one would be:&#xD;
&lt;p&gt;&lt;b&gt;&lt;i&gt;r = (x &amp;gt;&amp;gt; 1) - (x &amp;gt;&amp;gt; 2) - (x &amp;gt;&amp;gt; 3) + (x &amp;gt;&amp;gt; 6)&lt;/i&gt;&lt;/b&gt;&#xD;
&lt;p&gt;And then of course I could perhaps expand on the (x &amp;gt;&amp;gt; 6)&#xD;
in a similar fashion to get an even more accurate result.&#xD;
&lt;p&gt;Anyways... kind of an interesting problem.</description>
    </item>
    <item>
      <pubDate>Thu, 1 Feb 2007 06:13:09 GMT</pubDate>
      <title>1 Feb 2007</title>
      <link>http://www.advogato.org/person/fejj/diary.html?start=172</link>
      <guid>http://www.advogato.org/person/fejj/diary.html?start=172</guid>
      <description>&lt;p&gt;Interesting interview questions:&#xD;
&lt;p&gt;&lt;b&gt;Q&lt;/b&gt;: What's a fast way to divide an integer by 7&#xD;
using the bit shift operator? (apparently asked by an &lt;a&#xD;
href="http://www.easports.com"&gt;EA Sports&lt;/a&gt; interviewer)&lt;br&gt;&#xD;
&lt;b&gt;A&lt;/b&gt;: I thought about this for a bit and came up&#xD;
with the following estimation:&#xD;
&lt;p&gt;&lt;b&gt;&lt;i&gt;r = (x &amp;gt;&amp;gt; 2) - (x &amp;gt;&amp;gt; 3) + (x &amp;gt;&amp;gt; 6);&lt;/i&gt;&lt;/b&gt;&#xD;
&lt;p&gt;I mostly mention this because I had my own interview&#xD;
today where I felt... well, less than adequate. Suffice it&#xD;
to say, my ability to figure out the Big-O notation for&#xD;
algorithms was less than stellar. I was also unable to come&#xD;
up with a solution for his webcrawler scenario, which was&#xD;
along the lines of "if you've got some huge number of pages&#xD;
to crawl, how could you prevent the crawler from scanning&#xD;
the same page multiple times?" to which I had to admit to&#xD;
him, I hadn't the slightest idea how to go about it (the&#xD;
prelude to this question had been "the simplest way to do&#xD;
such a thing if memory was not an issue" to which I replied&#xD;
I'd use a hash table, using the page urls as the key).</description>
    </item>
    <item>
      <pubDate>Fri, 26 Jan 2007 21:37:07 GMT</pubDate>
      <title>26 Jan 2007</title>
      <link>http://www.advogato.org/person/fejj/diary.html?start=171</link>
      <guid>http://www.advogato.org/person/fejj/diary.html?start=171</guid>
      <description>&lt;p&gt;Been listening to &lt;a&#xD;
href="http://www.modarchive.org/download.php/_/_too_fast.mod"&gt;Drivin'&#xD;
Too Fast&lt;/a&gt; lately, really has a nice groove to it.</description>
    </item>
    <item>
      <pubDate>Thu, 25 Jan 2007 16:54:51 GMT</pubDate>
      <title>25 Jan 2007</title>
      <link>http://www.advogato.org/person/fejj/diary.html?start=170</link>
      <guid>http://www.advogato.org/person/fejj/diary.html?start=170</guid>
      <description>&lt;p&gt;Amazing what a break from looking at code can do to help&#xD;
you fix a bug.&#xD;
&lt;p&gt;Back in 2004, I had been writing articles explaining&#xD;
different sorting algorithms, how they worked, and how to&#xD;
implement them in C (and in most cases, how to implement&#xD;
them more efficiently than the "standard textbook way").&#xD;
Well, I had gotten distracted around the time I had been&#xD;
working on an article for Quick Sort and never got around to&#xD;
finishing it. I remember having a bug in my QuickSort&#xD;
routine somewhere that I wasn't able to find after a few&#xD;
nights of looking at it and having had more pressing things&#xD;
to attend to, set it aside for later (but not before&#xD;
documenting a few test cases that failed and how they failed).&#xD;
&lt;p&gt;Well, yesterday, after coming across that code, I opened&#xD;
it up in my trusty Emacs editor and in just a few minutes&#xD;
had a solution... it was basically a simple one-off bug.&#xD;
&lt;p&gt;Not long after, I got a call from someone at Google who&#xD;
had seen my resume and repeatedly told me they found it&#xD;
"interesting". I have no idea what that means, exactly, but&#xD;
I take it that it's a Good Thing(tm) :)</description>
    </item>
    <item>
      <pubDate>Tue, 23 Jan 2007 18:54:55 GMT</pubDate>
      <title>23 Jan 2007</title>
      <link>http://www.advogato.org/person/fejj/diary.html?start=169</link>
      <guid>http://www.advogato.org/person/fejj/diary.html?start=169</guid>
      <description>&lt;p&gt;Thanks to &lt;a&#xD;
href="http://www.burtonini.com/blog/computers/lemonade-2007-01-23-13-10"&gt;Ross&lt;/a&gt;'s&#xD;
blog for informing me about &lt;a&#xD;
href="http://blog.dave.cridland.net/"&gt;Dave Cridland&lt;/a&gt;'s&#xD;
Push-IMAP projects (Polymer, Telomer) and the Lemonaide&#xD;
specs. This was quite an interesting read... I've been&#xD;
wanting something like this for years, it's really exciting&#xD;
stuff.&#xD;
&lt;p&gt;Despite what &lt;a&#xD;
href="http://pvanhoof.be/blog/index.php/2007/01/23/nokia-n880-fwd-misinformation"&gt;pvanhoof&lt;/a&gt;&#xD;
claims in his own response to this news, offline&#xD;
functionality is &lt;i&gt;not&lt;/i&gt; the hardest part of implementing&#xD;
an IMAP client.</description>
    </item>
    <item>
      <pubDate>Wed, 20 Dec 2006 22:12:30 GMT</pubDate>
      <title>20 Dec 2006</title>
      <link>http://www.advogato.org/person/fejj/diary.html?start=168</link>
      <guid>http://www.advogato.org/person/fejj/diary.html?start=168</guid>
      <description>&lt;p&gt;I find it hillarious that the only argument against &#xD;
what I've posted comes down to:&#xD;
&lt;p&gt;"No really, Bush is a Bad Man because I say so."&#xD;
&lt;p&gt;Very convincing argument, I must say.&#xD;
</description>
    </item>
  </channel>
</rss>
