def search_sorted(array, value):
    """
    Searches the given sorted array for the given value using a binary search
    which should execute in O(log N).
    
    Parameters
    ----------
    array : `numpy.ndarray`
        a 1D sorted numerical array
    value : float
        the numerical value to search for
    
    Returns
    -------
    index : int
        - if `value` is between `array[0]` and `array[-1]`, then `index` is the
        integer index of `array` closest to `value`
        - if `value<array[0]` or `value > array[-1]`, then `index` is None
    """
    def index_to_check(rmin, rmax):
        return (rmin + rmax) // 2
    range_min = 0
    range_max_0 = len(array)
    range_max = range_max_0
    numloops = 0
    while numloops < 100:
        numloops += 1
        if (range_max - range_min) == 1:
            if (range_max == range_max_0) or (range_min == 0):
                raise LookupError(("For some reason, range_max-" +\
                    "range_min reached 1 before the element was found. The " +\
                    "element being searched for was {0!s}. (min,max)=" +\
                    "({1!s},{2!s})").format(value, range_min, range_max))
            else:
                high_index = range_max
        else:
            high_index = index_to_check(range_min, range_max)
        high_val = array[high_index]
        low_val = array[high_index - 1]
        if value < low_val:
            range_max = high_index
        elif value > high_val:
            range_min = high_index
        else: # low_val <= value <= high_val
            if (2 * (high_val - value)) < (high_val - low_val):
                return high_index
            else:
                return high_index - 1
    raise NotImplementedError("Something went wrong! I got " +\
        "caught a pseudo-infinite loop!")