def rational_seq(lo,hi,step):
    """Sequence of rational numbers"""
    lo   = cast_to_rational(lo)
    hi   = cast_to_rational(hi)
    step = cast_to_rational(step)
    out = [lo]
    while out[-1]+step <= hi:
        out.append(out[-1]+step)
    return out
def harmonic_progression(a=1, d=1):

    a = cast_to_rational(a)
    d = cast_to_rational(d)

    den = a
    one = Rational(1)
    while True:
        yield one / den
        den += d
def rational_round(Q,dlim):
    """Best approximation of Q with denominator of d or less, by semi-convergents"""

    Q = cast_to_rational(Q)
    if type(dlim) != int:
        raise TypeError("dlim must be integer")
    if dlim < 1:
        raise ZeroDivisionError

    # https://shreevatsa.wordpress.com/2011/01/10/not-all-best-rational-approximations-are-the-convergents-of-the-continued-fraction/
    a = CFrac(Q).terms

    prev = Rational(a[0])
    for pos,val in enumerate(a):
        # Try appending the floor of half the next convergent
        semi = a[:pos]+[(val-1)//2+1]
        semi = CFrac(semi)
        
        # If it is worse than the last semiconvergent add 1
        if abs(semi.as_rational() - Q)  >  abs(prev - Q):
            semi[pos] += 1
            
        while semi.terms[pos] <= val:
            if semi.as_rational().d > dlim:
                semi[pos] -= 1
                return prev
            prev = semi.as_rational()
            semi[pos] += 1
    return Q
def sign(Q):
    """Sign of a rational number"""
    Q = cast_to_rational(Q)
    if Q.n > 0:
        return 1
    elif Q.n < 0:
        return -1
    else:
        return 0
def engel_expansion(Q):
    Q = cast_to_rational(Q)
    
    u = Q
    
    out = []
    
    while u != 0:
        a = (1/u).__ceil__()
        out.append(a)
        u = u*a-1
    return out
def mediant(a,b):

    a = cast_to_rational(a)
    b = cast_to_rational(b)
    
    return Rational(a.n+b.n,a.d+b.d)