Beispiel #1
0
def ladder(num: WholeNumber) -> Set[WholeNumber]:
    prime_factors: List[WholeNumber] = []

    log(f'Testing primes (using ladder method) to see which is factor of {num}...'
        )

    log_indent()
    while not is_prime(num):
        prime_to_test = WholeNumber.from_int(2)

        while True:
            log(f'Testing if {prime_to_test} is divisible by {num}...')
            (new_num, remainder) = num / prime_to_test
            if remainder == WholeNumber.from_int(0):
                break
            prime_to_test = calculate_next_prime(prime_to_test)

        log(f'Found! {prime_to_test} is a prime factor -- {new_num} * {prime_to_test} = {num}'
            )
        prime_factors.append(prime_to_test)
        num = new_num

        log(f'Testing primes to see which is factor of {num}...')

    log(f'{num} itself is a prime!')
    prime_factors.append(num)

    log_unindent()
    log(f'Prime factors: {prime_factors}')

    return prime_factors
Beispiel #2
0
def lcm_walk(num1: WholeNumber,
             num2: WholeNumber) -> Tuple[List[WholeNumber], List[WholeNumber]]:
    num1_multiples: List[WholeNumber] = []
    num2_multiples: List[WholeNumber] = []

    num1_counter = WholeNumber.from_int(1)
    num2_counter = WholeNumber.from_int(1)

    while True:
        log(f'Calculating {num1_counter} multiple of {num1}...')
        num1_multiple = num1 * num1_counter
        num1_multiples.append(num1_multiple)

        log(f'Calculating {num2_counter} multiple of {num2}...')
        num2_multiple = num2 * num2_counter
        num2_multiples.append(num2_multiple)

        log(f'Testing {num1_multiple} vs {num2_multiple}')
        if num1_multiple == num2_multiple:
            log(f'Matches! LCM is {num1_multiple}')
            break
        elif num1_multiple < num2_multiple:
            log(f'Increasing first multiple (multiple for {num1})')
            num1_counter += WholeNumber.from_int(1)
        elif num1_multiple > num2_multiple:
            log(f'Increasing second multiple (multiple for {num2})')
            num2_counter += WholeNumber.from_int(1)

    return num1_multiple
Beispiel #3
0
def calculate_next_prime(last_prime: WholeNumber) -> WholeNumber:
    next_possible_prime = last_prime + WholeNumber.from_int(1)
    while True:
        if is_prime(next_possible_prime):
            return next_possible_prime
        else:
            next_possible_prime += WholeNumber.from_int(1)
Beispiel #4
0
    def __mul__(lhs: IntegerNumber, rhs: IntegerNumber) -> IntegerNumber:
        log(f'Multiplying {lhs} and {rhs}')
        log_indent()

        def determine_sign(magnitude: WholeNumber, default_sign: Sign) -> Sign:
            if magnitude == WholeNumber.from_int(0):
                return None
            else:
                return default_sign

        if lhs.sign is None:  # when sign isn't set, magnitude is always 0 -- 0 * a = 0
            sign = None
            magnitude = WholeNumber.from_int(0)
        elif rhs.sign is None:  # when sign isn't set, magnitude is always 0 -- a * 0 = 0
            sign = None
            magnitude = WholeNumber.from_int(0)
        elif (lhs.sign == Sign.POSITIVE and rhs.sign == Sign.POSITIVE) \
                or (lhs.sign == Sign.NEGATIVE and rhs.sign == Sign.NEGATIVE):
            magnitude = lhs.magnitude * rhs.magnitude
            sign = determine_sign(magnitude, Sign.POSITIVE)
        elif (lhs.sign == Sign.POSITIVE and rhs.sign == Sign.NEGATIVE) \
                or (lhs.sign == Sign.NEGATIVE and rhs.sign == Sign.POSITIVE):
            magnitude = lhs.magnitude * rhs.magnitude
            sign = determine_sign(magnitude, Sign.NEGATIVE)

        log_unindent()
        log(f'sign: {sign}, magnitude: {magnitude}')

        return IntegerNumber(sign, magnitude)
Beispiel #5
0
    def from_str(val: str) -> DecimalNumber:
        values = val.split('.')
        if len(values) == 1 and len(values[0]) > 0:
            return DecimalNumber.from_integer(IntegerNumber.from_str(
                values[0]))
        elif len(values) == 2:
            if values[0][0] == '-':
                sign = Sign.NEGATIVE
                values[0] = values[0][1:]
            elif values[0][0] == '+':
                sign = Sign.POSITIVE
                values[0] = values[0][1:]
            elif values[0] == '0':
                sign = None
            else:
                sign = Sign.POSITIVE

            whole = FractionNumber(
                IntegerNumber.from_whole(WholeNumber.from_str(values[0])),
                IntegerNumber.from_str('1'))
            fractional = FractionNumber(
                IntegerNumber.from_whole(WholeNumber.from_str(values[1])),
                IntegerNumber.from_whole(
                    WholeNumber.from_str('1' + ('0' * len(values[1])))))

            final_frac = whole + fractional
            if sign == Sign.NEGATIVE:
                final_frac = final_frac * FractionNumber.from_str("-1/1")

            return DecimalNumber.from_fraction(final_frac)
        else:
            raise Exception(f'Bad format: {val}')
Beispiel #6
0
    def __init__(self, sign: Union[Sign, None], whole: WholeNumber,
                 fractional: FractionalNumber):
        self.sign = sign
        self.whole = whole.copy()
        self.fractional = fractional.copy()

        if whole == WholeNumber.from_str(
                '0') and fractional == FractionalNumber.from_str(
                    '0') and sign is not None:
            raise Exception('Magnitude of 0 cannot have a sign')
Beispiel #7
0
def main():
    log_whitelist([(inspect.getfile(GreatestCommonDivisor), 'gcd_naive')])

    print("<div style=\"border:1px solid black;\">", end="\n\n")
    print("`{bm-disable-all}`", end="\n\n")
    try:
        args = input().split()  # read from stdin
        input1 = WholeNumber.from_str(args[0])
        input2 = WholeNumber.from_str(args[1])
        res = gcd_naive(input1, input2)  # this will output markdown to stdout
    finally:
        print("</div>", end="\n\n")
        print("`{bm-enable-all}`", end="\n\n")
def main():
    log_whitelist([(inspect.getfile(WholeNumber), '__truediv__')])

    print("<div style=\"border:1px solid black;\">", end="\n\n")
    print("`{bm-disable-all}`", end="\n\n")
    try:
        args = input().split()  # read from stdin
        input1 = WholeNumber.from_str(args[0])
        input2 = WholeNumber.from_str(args[1])
        res = input1 / input2  # this will output markdown to stdout
    finally:
        print("</div>", end="\n\n")
        print("`{bm-enable-all}`", end="\n\n")
Beispiel #9
0
def main():
    log_whitelist([(inspect.getfile(LeastCommonMultiple),
                    'lcm_prime_factorize')])

    print("<div style=\"border:1px solid black;\">", end="\n\n")
    print("`{bm-disable-all}`", end="\n\n")
    try:
        args = input().split()  # read from stdin
        input1 = WholeNumber.from_str(args[0])
        input2 = WholeNumber.from_str(args[1])
        res = lcm_prime_factorize(
            input1, input2)  # this will output markdown to stdout
    finally:
        print("</div>", end="\n\n")
        print("`{bm-enable-all}`", end="\n\n")
Beispiel #10
0
    def from_str(val: str) -> IntegerNumber:
        if len(val) == 0:
            raise Exception('Must contain at least 1 char')

        if val.startswith('-'):
            sign = Sign.NEGATIVE
            digits = val[1:]  # remove negative sign
        else:
            sign = Sign.POSITIVE
            digits = val

        magnitude = WholeNumber.from_str(digits)

        if magnitude == WholeNumber.from_int(0):
            sign = None

        return IntegerNumber(sign, magnitude)
Beispiel #11
0
def lcm_prime_factorize(num1: WholeNumber, num2: WholeNumber) -> WholeNumber:
    log(f'Calculating prime factors for {num1}...')
    num1_primes = sorted(factor_tree(num1).get_prime_factors())
    log(f'{num1_primes}')

    log(f'Calculating prime factors for {num2}...')
    num2_primes = sorted(factor_tree(num2).get_prime_factors())
    log(f'{num2_primes}')

    distinct_primes: Set[WholeNumber] = set()
    [distinct_primes.add(p) for p in num1_primes]
    [distinct_primes.add(p) for p in num2_primes]

    log(f'Combining prime factors to get LCM...')
    least_common_multiple = WholeNumber.from_int(1)
    least_common_multiple_primes = Counter()
    for prime in sorted(list(distinct_primes)):
        num1_count = num1_primes.count(prime)
        num2_count = num2_primes.count(prime)
        if num1_count >= num2_count:
            for i in WholeNumber.range(WholeNumber.from_int(0),
                                       WholeNumber.from_int(num1_count)):
                least_common_multiple = least_common_multiple * prime
            least_common_multiple_primes[prime] += num1_count
        else:
            for i in WholeNumber.range(WholeNumber.from_int(0),
                                       WholeNumber.from_int(num2_count)):
                least_common_multiple = least_common_multiple * prime
            least_common_multiple_primes[prime] += num2_count
    log(f'LCM is {least_common_multiple}')

    return least_common_multiple
Beispiel #12
0
    def __mul__(lhs: DecimalNumber, rhs: DecimalNumber) -> DecimalNumber:
        log(f'Multiplying {lhs} and {rhs}...')
        log_indent()

        adjust_len_self = len(lhs.fractional.digits)
        adjust_len_other = len(rhs.fractional.digits)

        log(f'Generating mock integer number for {lhs}...')
        lhs_extra_0s = adjust_len_self - len(lhs.fractional.digits)
        lhs_combined_digits = lhs.fractional.digits + lhs.whole.digits
        lhs_combined_digits[0:0] = [Digit(0)] * lhs_extra_0s
        mock_self = IntegerNumber(lhs.sign, WholeNumber(lhs_combined_digits))
        log(f'{mock_self}')

        log(f'Generating mock integer number for {rhs}...')
        rhs_extra_0s = adjust_len_other - len(rhs.fractional.digits)
        rhs_combined_digits = rhs.fractional.digits + rhs.whole.digits
        rhs_combined_digits[0:0] = [Digit(0)] * rhs_extra_0s
        mock_other = IntegerNumber(rhs.sign, WholeNumber(rhs_combined_digits))
        log(f'{mock_other}')

        log(f'Performing {mock_self} * {mock_other}...')
        mock_ret = mock_self * mock_other
        log(f'{mock_ret}')

        log(f'Unmocking {mock_ret} back to decimal...')
        unadjust_len = adjust_len_self + adjust_len_other
        ret_sign = mock_ret.sign
        ret_fractional_digits = [
            mock_ret.magnitude[i] for i in range(0, unadjust_len)
        ]
        ret_whole_digits = [
            mock_ret.magnitude[i]
            for i in range(unadjust_len, len(mock_ret.magnitude.digits))
        ]
        ret = DecimalNumber(ret_sign, WholeNumber(ret_whole_digits),
                            FractionalNumber(ret_fractional_digits))
        log(f'{ret}')

        log_unindent()
        log(f'{ret}')

        return ret
Beispiel #13
0
def factor_fast(num: WholeNumber) -> Set[WholeNumber]:
    log(f'Factoring {num}...')
    log_indent()

    factors: Set[WholeNumber] = set()
    for factor1 in WholeNumber.range(WholeNumber.from_int(1),
                                     num,
                                     end_inclusive=True):
        log(f'Test if {factor1} is a factor...')
        factor2, remainder = num / factor1
        if remainder == WholeNumber.from_int(0):
            factors.add(factor1)
            factors.add(factor2)
            log(f'Yes: ({factor1} and {factor2} are factors)')
        else:
            log(f'No')

    log_unindent()
    log(f'{factors}')

    return factors
def main():
    log_whitelist([(inspect.getfile(CommonDivisibilityTest),
                    'common_divisibility_test')])

    print("<div style=\"border:1px solid black;\">", end="\n\n")
    print("`{bm-disable-all}`", end="\n\n")
    try:
        args = input().split()  # read from stdin
        input1 = WholeNumber.from_str(args[0])
        res = common_divisibility_test(input1)
    finally:
        print("</div>", end="\n\n")
        print("`{bm-enable-all}`", end="\n\n")
Beispiel #15
0
def gcd_naive(num1: WholeNumber, num2: WholeNumber) -> WholeNumber:
    log(f'Calculating gcd for {num1} and {num2}...')
    log_indent()

    log(f'Sorting to determine smaller input...')
    min_num = min(num1, num2)

    log(f'Testing up to smaller input ({min_num})...')
    log_indent()
    for i in WholeNumber.range(WholeNumber.from_str('1'), min_num, True):
        log(f'Testing {i}...')
        quotient1, remainder1 = num1 / i
        quotient2, remainder2 = num2 / i
        if remainder1 == 0 and remainder2 == 0:
            log(f'{num1} and {num2} are both divisible by {i}...')
            found = i
        else:
            log(f'{num1} and {num2} are NOT both divisible by {i}...')
    log_unindent()

    log_unindent()
    log(f'GCD is {found}')
    return found
Beispiel #16
0
def factor_naive(num: WholeNumber) -> Set[WholeNumber]:
    log(f'Factoring {num}...')
    log_indent()

    factors: Set[WholeNumber] = set()
    for factor1 in WholeNumber.range(WholeNumber.from_int(1),
                                     num,
                                     end_inclusive=True):
        for factor2 in WholeNumber.range(WholeNumber.from_int(1),
                                         num,
                                         end_inclusive=True):
            log(f'Testing if {factor1} and {factor2} are factors...')
            if factor1 * factor2 == num:
                factors.add(factor1)
                factors.add(factor2)
                log(f'Yes')
            else:
                log(f'No')

    log_unindent()
    log(f'{factors}')

    return factors
Beispiel #17
0
    def get_prime_factors(self,
                          output_list: List[WholeNumber] = None
                          ) -> List[WholeNumber]:
        if output_list is None:
            output_list = []

        if self.left is None and self.right is None:
            if self.value != WholeNumber.from_str(
                    '1'):  # REMEMBER: 1 is not a prime number
                output_list.append(self.value)

        if self.left is not None:
            self.left.get_prime_factors(output_list)
        if self.right is not None:
            self.right.get_prime_factors(output_list)

        return output_list
Beispiel #18
0
    def will_division_terminate(lhs: DecimalNumber,
                                rhs: DecimalNumber) -> bool:
        log(f'Checking if {lhs} / {rhs} results in a non-terminating decimal...'
            )
        log_indent()

        adjust_len_self = len(lhs.fractional.digits)
        adjust_len_other = len(rhs.fractional.digits)

        log(f'Generating mock integer number for {lhs}...')
        lhs_extra_0s = adjust_len_self - len(lhs.fractional.digits)
        lhs_combined_digits = lhs.fractional.digits + lhs.whole.digits
        lhs_combined_digits[0:0] = [Digit(0)] * lhs_extra_0s
        mock_self = IntegerNumber(lhs.sign, WholeNumber(lhs_combined_digits))
        log(f'{mock_self}')

        log(f'Generating mock integer number for {rhs}...')
        rhs_extra_0s = adjust_len_other - len(rhs.fractional.digits)
        rhs_combined_digits = rhs.fractional.digits + rhs.whole.digits
        rhs_combined_digits[0:0] = [Digit(0)] * rhs_extra_0s
        mock_other = IntegerNumber(rhs.sign, WholeNumber(rhs_combined_digits))
        log(f'{mock_other}')

        log(f'Generating mock fraction for {lhs} / {rhs}...')
        mock_fraction = FractionNumber(mock_self, mock_other)
        log(f'{mock_fraction}')

        log(f'Simplifying mock fraction...')
        mock_fraction = mock_fraction.simplify()
        log(f'{mock_fraction}')

        log(f'Checking if prime factors of denom ({mock_fraction.denominator}) is {{}}, {{2}}, {{5}}, or {{2,5}}...'
            )
        mock_fraction_denom_prime_factors = set(
            factor_tree(mock_fraction.denominator).get_prime_factors())
        if not (
            {WholeNumber.from_str('2'),
             WholeNumber.from_str('5')} == mock_fraction_denom_prime_factors or
            {WholeNumber.from_str('2')} == mock_fraction_denom_prime_factors or
            {WholeNumber.from_str('5')} == mock_fraction_denom_prime_factors
                or 0 == len(mock_fraction_denom_prime_factors)):
            ret = False
            log(f'{ret} -- Won\'t terminate.')
        else:
            ret = True
            log(f'{ret} -- Will terminate.')

        log_unindent()
        log(f'{ret}')
        return ret
Beispiel #19
0
def factor_tree(num: WholeNumber) -> FactorTreeNode:
    log(f'Creating factor tree for {num}...')

    factors = factor_fastest(num)

    # remove factor pairs that can't used in factor true: (1, num) or (num, 1)
    factors = set(
        [f for f in factors if f != WholeNumber.from_int(1) and f != num])

    ret = FactorTreeNode()
    if len(factors) == 0:
        ret.value = num
        log(f'Cannot factor {num} is prime -- resulting tree: {ret}')
    else:
        factor1 = next(iter(factors))
        factor2, _ = num / factor1
        ret.value = num
        ret.left = factor_tree(factor1)
        ret.right = factor_tree(factor2)
        log(f'Factored {num} to {factor1} and {factor2} -- resulting tree: {ret}'
            )
    return ret
Beispiel #20
0
def gcd_euclid(num1: WholeNumber, num2: WholeNumber) -> WholeNumber:
    log(f'Calculating gcd for {num1} and {num2}...')
    log_indent()

    next_nums = [num1, num2]

    while True:
        log(f'Sorting {next_nums}...')
        next_nums.sort()  # sort smallest to largest
        next_nums.reverse()  # reverse it so that it's largest to largest
        log(f'Checking if finished ({next_nums[1]} == 0?)...')
        if next_nums[1] == WholeNumber.from_int(0):
            found = next_nums[0]
            break

        log(f'Dividing {next_nums} and grabbing the remainder for the next test...'
            )
        _, remainder = next_nums[0] / next_nums[1]
        next_nums = [next_nums[1], remainder]

    log_unindent()
    log(f'GCD is {found}')
    return found
Beispiel #21
0
    log(f'{num} itself is a prime!')
    prime_factors.append(num)

    log_unindent()
    log(f'Prime factors: {prime_factors}')

    return prime_factors


#MARKDOWN_LADDER


def calculate_next_prime(last_prime: WholeNumber) -> WholeNumber:
    next_possible_prime = last_prime + WholeNumber.from_int(1)
    while True:
        if is_prime(next_possible_prime):
            return next_possible_prime
        else:
            next_possible_prime += WholeNumber.from_int(1)


if __name__ == '__main__':
    # factors = factor_naive(WholeNumber(24))
    # factors = factor_fast(WholeNumber(24))
    # factors = factor_fastest(WholeNumber(24))
    # print(f'{factors}')
    # print(f'{prime_test(WholeNumber(49))}')
    tree = factor_tree(WholeNumber.from_int(24))
    print(f'{tree}')
    # print(f'{ladder(WholeNumber(24))}')
Beispiel #22
0
    def to_suitable_fraction(value: FractionNumber) -> FractionNumber:
        log(f'Converting {value} to an equivalent fraction with denominator that is power of 10...'
            )
        log_indent()

        denom = value.denominator

        if str(denom)[0] == '1' and (set(str(denom)[1:]) == set()
                                     or set(str(denom)[1:]) == set('0')):
            log(f'Already power of 10')
        else:
            log(f'No')
            log(f'Simplifying fraction {value}...')
            value = value.simplify()
            denom = value.denominator
            log(f'{value}')

            log(f'Calculating unique prime factors of {denom}...')
            denom_prime_factors = factor_tree(denom).get_prime_factors()
            denom_prime_factors_set = set(denom_prime_factors)
            log(f'{denom_prime_factors_set}')
            if not ({WholeNumber.from_int(2),
                     WholeNumber.from_int(5)} == denom_prime_factors_set
                    or {WholeNumber.from_int(2)} == denom_prime_factors_set
                    or {WholeNumber.from_int(5)} == denom_prime_factors_set
                    or 0 == len(denom_prime_factors_set)):
                raise Exception(
                    'Simplified denominator contains prime factors other than 2 and 5'
                )

            log(f'Calculating value to scale by so {denom} becomes next largest power of 10...'
                )
            num_of_2s = len(
                list(
                    filter(lambda pf: pf == WholeNumber.from_str('2'),
                           denom_prime_factors)))
            num_of_5s = len(
                list(
                    filter(lambda pf: pf == WholeNumber.from_str('5'),
                           denom_prime_factors)))
            extra_2s = 0
            extra_5s = 0
            if num_of_2s == 0 and num_of_5s == 0:
                extra_2s = 1
                extra_5s = 1
            elif num_of_2s < num_of_5s:
                extra_2s = num_of_5s - num_of_2s
            elif num_of_2s > num_of_5s:
                extra_5s = num_of_2s - num_of_5s
            log(f'Require {extra_2s} 2s and {extra_5s} 5s')

            log(f'Multiplying {extra_2s} 2s and {extra_5s} 5s to get scale...')
            scale_by = WholeNumber.from_str('1')
            for i in range(extra_2s):
                scale_by *= WholeNumber.from_str('2')
            for i in range(extra_5s):
                scale_by *= WholeNumber.from_str('5')
            log(f'{scale_by}')

            log(f'Multiplying {value}\'s numerator and denominator by {scale_by}...'
                )
            value = value * FractionNumber(IntegerNumber.from_whole(scale_by),
                                           IntegerNumber.from_whole(scale_by))
            log(f'{value}')

        log_unindent()
        log(f'{value}')

        return value
Beispiel #23
0
 def from_whole(val: WholeNumber) -> IntegerNumber:
     return IntegerNumber(None if val == WholeNumber.from_int(0) else Sign.POSITIVE, val)
Beispiel #24
0
 def determine_sign(magnitude: WholeNumber, default_sign: Sign) -> Sign:
     if magnitude == WholeNumber.from_int(0):
         return None
     else:
         return default_sign
Beispiel #25
0
    def __init__(self, sign: Union[Sign, None], magnitude: WholeNumber):
        self.sign = sign
        self.magnitude = magnitude.copy()

        if magnitude == WholeNumber.from_int(0) and sign is not None:
            raise Exception('Magnitude of 0 cannot have a sign')
Beispiel #26
0
    def to_words(self: DecimalNumber) -> str:
        fractional_len_to_suffixes = {
            1: 'tenth',
            2: 'hundredth',
            3: 'thousandth',
            4: 'ten-thousandth',
            5: 'hundred-thousandth',
            6: 'millionth',
            7: 'ten-millionth',
            8: 'hundred-millionth',
            9: 'billionth',
            10: 'ten-billionth',
            11: 'hundred-billionth',
            12: 'trillionth',
            13: 'ten-trillionth',
            14: 'hundred-trillionth',
            15: 'quadrillionth',
            16: 'ten-quadrillionth',
            17: 'hundred-quadillionth',
            18: 'quintillionth',
            19: 'ten-quintillionth',
            20: 'hundred-quintillionth',
        }

        log(f'Converting {self}...')
        log_indent()

        log(f'Converting whole portion to words...')
        whole_words = self.whole.to_words()
        log(f'Whole as words: {whole_words}')

        log(f'Converting fractional portion to words...')
        fractional_words = WholeNumber.from_str(str(
            self.fractional)).to_words()
        log(f'fractional as words: {fractional_words}')

        output = ''
        if self.whole == WholeNumber.from_str(
                '0') and self.fractional == FractionalNumber.from_str('0'):
            output += 'zero'
        else:
            if self.sign == Sign.NEGATIVE:
                output += 'negative '

            if self.whole != WholeNumber.from_str('0'):
                output += whole_words

            if self.whole != WholeNumber.from_str(
                    '0') and self.fractional != FractionalNumber.from_str('0'):
                output += ' and '

            if self.fractional != FractionalNumber.from_str('0'):
                output += fractional_words
                suffix = fractional_len_to_suffixes[len(
                    self.fractional.digits)]
                if suffix is None:
                    raise Exception('Fractional too large')
                log(f'Fractional suffix: {suffix}')
                if self.fractional != FractionalNumber.from_str(
                        '0'):  # pluralize suffix if more than 1
                    suffix += 's'
                output += ' ' + suffix

        log_unindent()
        log(f'{output}')

        return output.strip()
Beispiel #27
0
 def from_integer(numerator: IntegerNumber) -> FractionNumber:
     return FractionNumber(
         numerator, IntegerNumber.from_whole(WholeNumber.from_str('1')))
Beispiel #28
0
    def round(self: DecimalNumber, position: str) -> DecimalNumber:
        log(f'Rounding {self} at {position} position...')
        log_indent()

        position = position.strip()
        if position.endswith('s'):
            position = position[:-1]
        position_word_to_index = {
            'hundred-quintillion': 20,
            'ten-quintillion': 19,
            'quintillion': 18,
            'hundred-quadillion': 17,
            'ten-quadrillion': 16,
            'quadrillion': 15,
            'hundred-trillion': 14,
            'ten-trillion': 13,
            'trillion': 12,
            'hundred-billion': 11,
            'ten-billion': 10,
            'billion': 9,
            'hundred-million': 8,
            'ten-million': 7,
            'million': 6,
            'hundred-thousand': 5,
            'ten-thousand': 4,
            'thousand': 3,
            'hundred': 2,
            'ten': 1,
            'one': 0,
            'tenth': -1,
            'hundredth': -2,
            'thousandth': -3,
            'ten-thousandth': -4,
            'hundred-thousandth': -5,
            'millionth': -6,
            'ten-millionth': -7,
            'hundred-millionth': -8,
            'billionth': -9,
            'ten-billionth': -10,
            'hundred-billionth': -11,
            'trillionth': -12,
            'ten-trillionth': -13,
            'hundred-trillionth': -14,
            'quadrillionth': -15,
            'ten-quadrillionth': -16,
            'hundred-quadillionth': -17,
            'quintillionth': -18,
            'ten-quintillionth': -19,
            'hundred-quintillionth': -20,
        }
        position_idx = position_word_to_index[position]
        if position_idx is None:
            raise Exception('Position unknown')

        next_position_idx = position_idx - 1

        log(f'Determining adder based on following position...')
        log_indent()
        log(f'Checking if digit at following position is >= 5...')
        following_digit = WholeNumber.from_digit(self[next_position_idx])
        if following_digit >= WholeNumber.from_str("5"):
            log(f'True ({following_digit} >= 5), deriving adder based on position...'
                )
            if position_idx >= 0:
                adder = DecimalNumber(
                    self.sign, WholeNumber.from_str('1' + '0' * position_idx),
                    FractionalNumber.from_str('0'))
            else:
                adder = DecimalNumber(
                    self.sign, WholeNumber.from_str('0'),
                    FractionalNumber.from_str('0' * -(position_idx + 1) + '1'))
        else:
            log(f'False ({following_digit} < 5), setting adder to 0...')
            adder = DecimalNumber.from_str('0')
        log_unindent()
        log(f'{adder}')

        log(f'Adding {adder} to {self}...')
        ret = self.copy() + adder
        log(f'{ret}')

        log(f'Truncating all following positions...')
        log_indent()
        if position_idx >= 0:
            for i in range(0, position_idx):
                ret[i] = Digit(0)
                log(f'{ret}')
            for i in range(0, len(self.fractional.digits)):
                ret[-i - 1] = Digit(0)
                log(f'{ret}')
        else:
            for i in range(-position_idx, len(self.fractional.digits)):
                ret[-i - 1] = Digit(0)
                log(f'{ret}')
        log_unindent()
        log(f'{ret}')

        log_unindent()
        log(f'{ret}')

        return ret
Beispiel #29
0
def common_divisibility_test(num: WholeNumber) -> Set[WholeNumber]:
    log_indent()
    try:
        ret: Set[WholeNumber] = set()
    
        last_digit: WholeNumber = WholeNumber.from_digit(num.digits[0])  # last digit is always at 0 idx
    
        log(f'Testing if {num} divisible by 2...')
        if last_digit == WholeNumber.from_int(0) \
                or last_digit == WholeNumber.from_int(2) \
                or last_digit == WholeNumber.from_int(4) \
                or last_digit == WholeNumber.from_int(6) \
                or last_digit == WholeNumber.from_int(8):
            log(f'Yes')
            ret.add(WholeNumber.from_int(2))
        else:
            log(f'No')
    
        log(f'Testing if {num}  divisible by 5...')
        if last_digit == WholeNumber.from_int(0) \
                or last_digit == WholeNumber.from_int(5):
            log(f'Yes');
            ret.add(WholeNumber.from_int(5))
        else:
            log(f'No');
    
        log(f'Testing if {num}  divisible by 10...')
        if last_digit == WholeNumber.from_int(0):
            log(f'Yes');
            ret.add(WholeNumber.from_int(10))
        else:
            log(f'No');
    
        log(f'Testing if {num} divisible by 3...')
        reduced_num: WholeNumber = num.copy()
        while True:
            digits = reduced_num.digits
            if len(digits) == 1:
                break
            reduced_num = sum([WholeNumber.from_int(d) for d in digits], WholeNumber.from_int(0))
    
        if reduced_num == WholeNumber.from_int(3) \
                or reduced_num == WholeNumber.from_int(6) \
                or reduced_num == WholeNumber.from_int(9):
            log(f'Yes')
            ret.add(WholeNumber.from_int(3))
        else:
            log(f'No')
    
        log(f'Testing if {num}  divisible by 6...')
        if WholeNumber.from_int(2) in ret and WholeNumber.from_int(3) in ret:
            log(f'Yes')
            ret.add(WholeNumber.from_int(6))
        else:
            log(f'NO')
    
        return ret
    finally:
        log_unindent()