There are multiple ways to handle the case when the key(the searched value) is not found by a binary search. Or any search on elements accessible by indices.
What you see is the Java approach, the approach that has been written by
the foremost writer of Java built-in Libraries (also the author of the article in the question) and, henceforth, used by millions of Java developers around the world for about 20 years.
Here is Java official documentation for the method java.util.Arrays#binarysearch(int a, int key).
Returns: index of the search key, if it is contained in the array; otherwise, (-(insertion point) - 1). The insertion point is defined as the point at which the
key would be inserted into the array: the index of the first element greater than the key, or
a.length if all elements in the array are less than the specified key. Note that this guarantees that the return value will be >= 0 if and only if the key is found.
That is, the method guarantees that the return value will not be a valid index if and only if the key is not found. This guarantee makes sure the return value is not usable when the key is not found, preventing wrong usage or failing faster.
key is not found and
low is 0 right before the method returns, the method should not return
-low, since it is
0, which is a valid index. So, it returns
-(low + 1), which is
-1, an invalid index.
By the way, to find the insertion point when the key is not found, i.e., when
returned_value < 0, we can use
-returned_value - 1.
key, there is no guarantee which one will be found. This uncertainty renders it, basically, useless for most problems in competitive programming. $\endgroup$
-(low+1)can equivalently be written as
~low, perhaps making it clearer that it is a "safe" transformation (no ambiguous results) $\endgroup$