Problem 026

This commit is contained in:
Correl Roush 2011-04-08 13:31:57 -04:00
parent 2079aa4199
commit 4cf65ca7a0

80
e026.py
View file

@ -27,47 +27,71 @@ def coprime(a, b):
primes = [p for p in primes_a if p in primes_b] primes = [p for p in primes_a if p in primes_b]
return bool(primes) 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""" """Determine the period length of a non-terminating decimal"""
length = None length = None
numerator = Decimal(numerator) numerator = Decimal(numerator)
denominator = Decimal(denominator) 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 if denominator == 1:
repeating decimal, obtained by decreasing the final (nonzero) return 1
digit by one and appending an infinitely repeating sequence of
nines. 1 = 0.999999... and 1.585 = 1.584999999... are two """
examples of this. From Wikipedia:
""" Terminating decimals represent rational numbers of the form
if len([p for p in primes if p not in [2, 5]]) == 0: k/2^n5^m
return 1
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: else:
raise Exception('Non-reciprocal period detection not yet implemented') raise Exception('Non-reciprocal period detection not yet implemented')
return length return length
def main(): def main():
MAX = 10 MAX = 1000
longest_cycle = 0 longest_cycle = (0, 0)
for i in xrange((MAX), 1, -1): for i in xrange((MAX), 1, -1):
# The period of 1/k for integer k is always ² k ? 1. # The period of 1/k for integer k is always <= k - 1
if longest_cycle >= i: if longest_cycle[1] >= i:
break break
cycle = period_length(1, i) cycle = get_cycle_length(1, i)
fraction = Decimal(1) / Decimal(i) if longest_cycle[1] < cycle:
print '1/{0} = {1} ({2})'.format(i, fraction, cycle), fraction.is_subnormal() longest_cycle = (i, cycle)
(i, cycle) = longest_cycle
print 'Longest cycle length is', cycle, 'for i =', i
if __name__ == '__main__': if __name__ == '__main__':
main() main()