
Textbook errors in binary searching (1988) - segfaultbuserr
https://dl.acm.org/ft_gateway.cfm?id=53012&ftid=13287&dwn=1&CFID=52849712&CFTOKEN=4241eec5c2cd01db-6D15F577-E584-D3B2-8F7278DE2FC3C2B1
======
eesmith
"These errors are logical: they are not related to machine-specific problems
such as arithmetic rounding or overflow."

Famously, Jon Bentley's book "Programming Pearls" binary search contained an
overflow error. See "Extra, Extra - Read All About It: Nearly All Binary
Searches and Mergesorts are Broken" at
[https://ai.googleblog.com/2006/06/extra-extra-read-all-
about...](https://ai.googleblog.com/2006/06/extra-extra-read-all-about-it-
nearly.html) which includes:

> Fast forward to 2006. I was shocked to learn that the binary search program
> that Bentley proved correct and subsequently tested in Chapter 5 of
> Programming Pearls contains a bug. Once I tell you what it is, you will
> understand why it escaped detection for two decades. Lest you think I'm
> picking on Bentley, let me tell you how I discovered the bug: The version of
> binary search that I wrote for the JDK contained the same bug. It was
> reported to Sun recently when it broke someone's program, after lying in
> wait for nine years or so.

~~~
userbinator
One has to ponder philosophically whether that "bug" is actually a bug or not,
given the extremely pathological situation it involves:

 _This bug can manifest itself for arrays whose length (in elements) is 2^30
or greater (roughly a billion elements). This was inconceivable back in the
'80s, when Programming Pearls was written, but it is common these days at
Google and other places._

If you're using a 32-bit system, which has only 2^32 bytes in its address
space, of which half is typically taken up by the OS kernel, leaving 2^31
bytes for your process, you can see just how strange this is; you would only
be able to have an element size of 1 byte, for 2 would fill up the whole 2^31
bytes of address space and leave no room at all for code, and the memory
manager would need to let you allocate a whole 1GB block --- and that's not
even considering _why_ you would ever want to binary search an array that
large at once.

Of course, to use a 32-bit element count on a 64-bit system is itself a more
valid bug, but otherwise the "bug" would appear at 2^63 elements --- clearly
well beyond the capacities of computers today (x86-64 has only 48 bits virtual
address space), or for that matter the size of anything which would be
practically binary searchable.

Thus IMHO this is really more of a curiosity along the lines of "you'll run
out of memory if you try to ask for too much", and you're probably doing
something either exotic or just plain wrong if you need to fill up the
machine's address space with a single data structure.

~~~
civility
> you would only be able to have an element size of 1 byte

Yes, when people point out this bug, it seems crazy. Who does a binary search
of 1GB of sorted data which only contains values from 0...255 (or -128...127).
I mean it _is_ a bug, but it's also the wrong data structure for that data...

> to use a 32-bit element count on a 64-bit system is itself a more valid bug

Yes, this one is real. Even ignoring the binary search algorithm, I cringe
whenever I see people use "int" as a loop index. 2 gig arrays were very common
in the work I used to do.

I also cringe when I see people used unsigned (size_t) loop indices, but
that's a deeper topic.

~~~
asalahli
I'm curious, what's wrong with size_t loop indices? I always thought that was
the most correct type for the job

~~~
civility
It's fine until you do almost any arithmetic using the index. Unsigned
arithmetic is rarely what you want, and it quietly converts all of your signed
types to unsigned giving you large positive values instead of small negative
ones. Maybe this isn't a common use case for most people, but it came up all
the time when I was doing signal processing algorithms.

Using ssize_t is pretty reasonable, and you're not going to overflow ssize_t
for loop indices except in some very pathological cases on a 32 bit
architecture.

If the arithmetic argument doesn't convince you, here's another one: write a
correct loop (using size_t) which traverses your array in reverse order. Here
is a broken example which would be fine with ssize_t:

    
    
        for (size_t ii = len - 1; ii >= 0; --ii) {
    
        }

~~~
drobi
Can you not do: for (size_t i = len-1; i < len; i--)? Isn't -1 defined to be
the largest integer that the unsigned type can handle?

Edit: I guess that wasn't the point of your example (that it may not be easily
recognisable as a bug?)

~~~
civility
Yeah, that works, but it's going to confuse more than half the people who ever
look at it.

