def bisection(func, a, b, args=(), xtol=1e-10, maxiter=400):
    """Bisection root-finding method.  Given a function and an interval with
    func(a) * func(b) < 0, find the root between a and b.
    """
    if b < a:
        a, b = b, a
    i = 1
    eva = func(a, *args)
    evb = func(b, *args)
    assert eva * evb < 0, 'Must start with interval with func(a) * func(b) <0'
    while i <= maxiter:
        dist = (b - a) / 2.0
        p = a + dist
        if dist / max(1.0, abs(p)) < xtol:
            return p
        ev = func(p, *args)
        if ev == 0:
            return p
        i += 1
        if ev * eva > 0:
            a = p
        else:
            b = p
    raise RuntimeError('bisection failed after %d iterations.' % maxiter)
