mirror of
https://github.com/correl/euler.git
synced 2024-11-23 19:19:53 +00:00
Problem 026
This commit is contained in:
parent
2079aa4199
commit
4cf65ca7a0
1 changed files with 52 additions and 28 deletions
80
e026.py
80
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()
|
||||
|
|
Loading…
Reference in a new issue