diff --git a/e026.py b/e026.py new file mode 100644 index 0000000..b69c726 --- /dev/null +++ b/e026.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +"""Find the value of d < 1000 for which 1/d contains the longest recurring cycle.A unit fraction contains 1 in the numerator. + +The decimal representation of the unit fractions with denominators 2 to 10 are given: + 1/2 = 0.5 + 1/3 = 0.(3) + 1/4 = 0.25 + 1/5 = 0.2 + 1/6 = 0.1(6) + 1/7 = 0.(142857) + 1/8 = 0.125 + 1/9 = 0.(1) + 1/10 = 0.1 +Where 0.1(6) means 0.166666..., and has a 1-digit recurring cycle. It can be seen that 1/7 has a 6-digit recurring cycle. + +Find the value of d < 1000 for which 1/d contains the longest recurring cycle in its decimal fraction part. +""" + +from decimal import Decimal +from e003 import pfactor + +def coprime(a, b): + """Are integers a and b coprime?""" + + primes_a = pfactor(a) + primes_b = pfactor(b) + primes = [p for p in primes_a if p in primes_b] + return bool(primes) + +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 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) + + else: + raise Exception('Non-reciprocal period detection not yet implemented') + return length + +def main(): + 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[1] >= i: + break + + 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() diff --git a/e027.py b/e027.py deleted file mode 100644 index 4d4ae74..0000000 --- a/e027.py +++ /dev/null @@ -1,73 +0,0 @@ -# -*- coding: utf-8 -*- -"""Find the value of d < 1000 for which 1/d contains the longest recurring cycle.A unit fraction contains 1 in the numerator. - -The decimal representation of the unit fractions with denominators 2 to 10 are given: - 1/2 = 0.5 - 1/3 = 0.(3) - 1/4 = 0.25 - 1/5 = 0.2 - 1/6 = 0.1(6) - 1/7 = 0.(142857) - 1/8 = 0.125 - 1/9 = 0.(1) - 1/10 = 0.1 -Where 0.1(6) means 0.166666..., and has a 1-digit recurring cycle. It can be seen that 1/7 has a 6-digit recurring cycle. - -Find the value of d < 1000 for which 1/d contains the longest recurring cycle in its decimal fraction part. -""" - -from decimal import Decimal -from e003 import pfactor - -def coprime(a, b): - """Are integers a and b coprime?""" - - primes_a = pfactor(a) - primes_b = pfactor(b) - primes = [p for p in primes_a if p in primes_b] - return bool(primes) - -def period_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 coprime(denominator, 10): - pass - else: - raise Exception('Non-reciprocal period detection not yet implemented') - return length - -def main(): - MAX = 10 - longest_cycle = 0 - for i in xrange((MAX), 1, -1): - # The period of 1/k for integer k is always ² k ? 1. - if longest_cycle >= i: - break - - cycle = period_length(1, i) - fraction = Decimal(1) / Decimal(i) - print '1/{0} = {1} ({2})'.format(i, fraction, cycle), fraction.is_subnormal() -if __name__ == '__main__': - main()