From 4cf65ca7a004b3af77e4f1d455567370cc97d761 Mon Sep 17 00:00:00 2001 From: Correl Roush Date: Fri, 8 Apr 2011 13:31:57 -0400 Subject: [PATCH] Problem 026 --- e026.py | 80 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/e026.py b/e026.py index 4d4ae74..b69c726 100644 --- a/e026.py +++ b/e026.py @@ -27,47 +27,71 @@ def coprime(a, b): primes = [p for p in primes_a if p in primes_b] return bool(primes) -def period_length(numerator, denominator): +def long_division(dividend, divisor): + dividend = str(dividend).replace('.', '') + i = -1 + remainder = 0 + while True: + while remainder < divisor: + i += 1 + remainder *= 10 + try: + remainder += int(dividend[i]) + except: + pass + if remainder == 0: + return + digit = str(remainder // divisor) + remainder = remainder % divisor + yield digit, remainder + +def get_cycle_length(numerator, denominator): """Determine the period length of a non-terminating decimal""" - + length = None numerator = Decimal(numerator) denominator = Decimal(denominator) - if numerator == 1: - if denominator == 1: - return 1 - primes = pfactor(int(denominator)) - - """ - From Wikipedia: - Terminating decimals represent rational numbers of the form - k/2^n5^m - However, a terminating decimal also has a representation as a - repeating decimal, obtained by decreasing the final (nonzero) - digit by one and appending an infinitely repeating sequence of - nines. 1 = 0.999999... and 1.585 = 1.584999999... are two - examples of this. - """ - if len([p for p in primes if p not in [2, 5]]) == 0: - return 1 + if denominator == 1: + return 1 + + """ + From Wikipedia: + Terminating decimals represent rational numbers of the form + k/2^n5^m + + However, a terminating decimal also has a representation as a + repeating decimal, obtained by decreasing the final (nonzero) + digit by one and appending an infinitely repeating sequence of + nines. 1 = 0.999999... and 1.585 = 1.584999999... are two + examples of this. + """ + if coprime(denominator, 10): + return 1 + + digits = [] + for digit in long_division(numerator, denominator): + if digit in digits: + cycle = digits[digits.index(digit):] + return len(cycle) + digits.append(digit) - if coprime(denominator, 10): - pass else: raise Exception('Non-reciprocal period detection not yet implemented') return length def main(): - MAX = 10 - longest_cycle = 0 + MAX = 1000 + longest_cycle = (0, 0) for i in xrange((MAX), 1, -1): - # The period of 1/k for integer k is always ² k ? 1. - if longest_cycle >= i: + # The period of 1/k for integer k is always <= k - 1 + if longest_cycle[1] >= i: break - cycle = period_length(1, i) - fraction = Decimal(1) / Decimal(i) - print '1/{0} = {1} ({2})'.format(i, fraction, cycle), fraction.is_subnormal() + cycle = get_cycle_length(1, i) + if longest_cycle[1] < cycle: + longest_cycle = (i, cycle) + (i, cycle) = longest_cycle + print 'Longest cycle length is', cycle, 'for i =', i if __name__ == '__main__': main()