#
# Decimal class. This class is used to perform and analyze the long division
# for generating the decimal expansions for fractions having a specified
# denominator. The number base can also be specified, though it defaults
# to base 10. The resulting data include:
#
# fraction: e.g., "1/7"
# decimal: the decimal expansion; e.g., "142857"
# decimal_parts: a three-element array, containing the various parts of
# the decimal expansion. These parts are described below.
# length: the length of the decimal expansion; e.g., 6
# halfway: if applicable, the position in the repeating portion of the
# decimal expansion after which the complementary portion begins.
# E.g., 3
# resolves: True / False, depending on whether the decimal expansion
# eventually terminates. E.g., True for 1/2; False for 1/3.
# non_repeating: if applicable, the length of the non-repeating portion
# of the decimal expansion. E.g., for 1/2, the length is 1; for 1/3,
# the length is 0-; for 1/12, the length is 2.
#
class Decimal:
primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97)
def __init__(self, denom, base=10):
denom = int(denom)
self.base = int(base)
data = []
for i in range(1, denom):
data.append(self._get_decimal_data(i, denom))
self.denominator = denom
self.data = data
def _get_decimal_data(self, num, denom):
decimal_parts = []
remainder = num
halfway = 0
resolves = False
non_repeating = 0
places = []
remainders = [remainder]
period_complete = False
while not period_complete:
# Perform the steps of long division until period is complete.
if remainder < denom:
remainder *= self.base
place = remainder / denom
places.append(place)
remainder -= place * denom
# Check for period completion.
# Period is complete if long division resolves without remainder.
if remainder == 0:
period_complete = True
resolves = True
decimal_parts = [''.join(map(str,places)), '', '']
# Period is complete if a remainder is repeated.
elif remainder in remainders:
period_complete = True
resolves = False
non_repeating = remainders.index(remainder)
if (len(places) - non_repeating) % 2 == 0:
halfway = non_repeating + len(places) / 2
else:
halfway = len(places)
decimal_parts = [
''.join(map(str,places[0:non_repeating])),
''.join(map(str,places[non_repeating:halfway])),
''.join(map(str,places[halfway:]))
]
# Store the remainder if resolution not detected.
else:
remainders.append(remainder)
# Once the decimal expansion is complete, compile the data.
decimal_data = {
'fraction' : str(num) + '/' + str(denom),
'decimal' : ''.join(map(str,places)),
'decimal_parts' : decimal_parts,
'length' : len(places),
'halfway' : halfway,
'resolves' : resolves,
'non_repeating' : non_repeating
}
return decimal_data