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)