# L-15 MCS 275 Mon 13 Feb 2017 : bisectsearch.py
"""
We search a sorted array of doubles with bisection.
"""

def linear_search(arr, nbr):
    """
    Returns the index k in the array arr
    such that arr[k] <= nbr <= arr[k+1].
    A must be sorted in increasing order.
    """
    for i in range(len(arr)):
        if nbr <= arr[i]:
            return i-1
    return len(arr)

def bisect_search(arr, nbr):
    """
    Returns the index k in the array arr
    such that arr[k] <= nbr <= arr[k+1]
    applying binary search.
    """
    if len(arr) == 0:
        return -1
    elif len(arr) == 1:
        if arr[0] <= nbr:
            return 0
        else:
            return -1
    else:
        middle = len(arr)//2
        if nbr < arr[middle]:
            return bisect_search(arr[:middle], nbr)
        else:
            k = bisect_search(arr[middle+1:], nbr)
            return k + middle +1

def main():
    """
    Illustration of linear and binary search in an array.
    Prompts the user for the lower, upper bound of the
    interval of random numbers, for the number of random
    numbers, and then for some number to search for.
    """
    from random import uniform as u
    from array import array
    low = float(input('Give lower bound : '))
    upp = float(input('Give upper bound : '))
    size = int(input('How many numbers ? '))
    nbrs = [u(low, upp) for _ in range(size)]
    nbrs.sort()
    data = array('d', nbrs)
    print(data)
    while True:
        nsb = float(input('Give number to search : '))
        idxlin = linear_search(data, nsb)
        idxbis = bisect_search(data, nsb)
        print('lin = %d, bis = %d' % (idxlin, idxbis))
        if idxbis < 0:
            print('outside interval: %f < %f' % (nsb, low))
        elif idxbis > size-1:
            print('outside interval: %f > %f' % (nsb, upp))
        else:
            print('data[%d] = %f <= %f' % (idxbis, data[idxbis], nsb))
            print('%f <= data[%d] = %f' % (nsb, idxbis+1, data[idxbis+1]))
        ans = input('search for more ? (y/n) ')
        if ans != 'y':
            break

main()
