Пример #1
0
    def common_denominator_lcm(
            lhs: FractionNumber,
            rhs: FractionNumber) -> (FractionNumber, FractionNumber):
        # Sign is only kept on the numerator, not the denominator
        log(f'Getting {lhs} and {rhs} to common denominator equivalent fractions'
            )
        if lhs._denominator != rhs._denominator:
            log_indent()

            log(f'Calculating common denominator...')
            common_denominator = lcm_prime_factorize(
                rhs._denominator.magnitude, lhs._denominator.magnitude)
            common_denominator = IntegerNumber(Sign.POSITIVE,
                                               common_denominator)
            log(f'{common_denominator}')

            log(f'Calculating numerator for LHS ({lhs})...')
            multiple, _ = common_denominator / lhs._denominator
            lhs_numerator = lhs._numerator * multiple
            log(f'{lhs_numerator}')

            log(f'Calculating numerator for RHS ({rhs})...')
            multiple, _ = common_denominator / rhs._denominator
            rhs_numerator = rhs._numerator * multiple
            log(f'{rhs_numerator}')

            log_unindent()

            lhs_equiv = FractionNumber(lhs_numerator, common_denominator)
            rhs_equiv = FractionNumber(rhs_numerator, common_denominator)
            log(f'Result: {lhs} -> {lhs_equiv}, {rhs} -> {rhs_equiv}')
            return lhs_equiv, rhs_equiv
        else:
            log(f'Fractions already have a common denominator')
            return lhs, rhs
Пример #2
0
    def common_denominator_naive(
            lhs: FractionNumber,
            rhs: FractionNumber) -> (FractionNumber, FractionNumber):
        # Sign is only kept on the numerator, not the denominator
        log(f'Getting {lhs} and {rhs} to common denominator equivalent fractions'
            )
        if lhs._denominator != rhs._denominator:
            log_indent()

            log(f'Calculating common denominator...')
            common_denominator = rhs._denominator * lhs._denominator
            log(f'{common_denominator}')

            log(f'Calculating numerator for LHS ({lhs})...')
            lhs_numerator = lhs._numerator * rhs._denominator
            log(f'{lhs_numerator}')

            log(f'Calculating numerator for RHS ({rhs})...')
            rhs_numerator = rhs._numerator * lhs._denominator
            log(f'{rhs_numerator}')

            log_unindent()

            lhs_equiv = FractionNumber(lhs_numerator, common_denominator)
            rhs_equiv = FractionNumber(rhs_numerator, common_denominator)
            log(f'Result: {lhs} -> {lhs_equiv}, {rhs} -> {rhs_equiv}')
            return lhs_equiv, rhs_equiv
        else:
            log(f'Fractions already have a common denominator')
            return lhs, rhs
Пример #3
0
    def __eq__(lhs: DecimalNumber, rhs: DecimalNumber) -> bool:
        class FailedTestException(Exception):
            pass

        log(f'Equality testing {lhs} and {rhs}...')
        log_indent()

        try:
            log(f'Testing sign...')
            sign_eq = lhs.sign == rhs.sign
            if not sign_eq:
                raise FailedTestException()
            log(f'Equal')

            log(f'Testing whole...')
            whole_eq = lhs.whole == rhs.whole
            if not whole_eq:
                raise FailedTestException()
            log(f'Equal')

            log(f'Testing fractional...')
            fractional_eq = lhs.fractional == rhs.fractional
            if not fractional_eq:
                raise FailedTestException()
            log(f'Equal')

            ret = True
        except FailedTestException:
            log(f'Not equal')
            ret = False

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

        return ret
Пример #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)
Пример #5
0
    def __add__(lhs: IntegerNumber, rhs: IntegerNumber) -> IntegerNumber:
        log(f'Adding {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:  # sign of None is only when magnitude is 0,  0 + a = a
            sign = rhs.sign
            magnitude = rhs.magnitude
        elif rhs.sign is None:  # sign of None is only when magnitude is 0,  a + 0 = a
            sign = lhs.sign
            magnitude = lhs.magnitude
        elif lhs.sign == rhs.sign:
            magnitude = lhs.magnitude + rhs.magnitude
            sign = determine_sign(magnitude, lhs.sign)
        elif lhs.sign != rhs.sign:
            if rhs.magnitude >= lhs.magnitude:
                magnitude = rhs.magnitude - lhs.magnitude
                sign = determine_sign(magnitude, rhs.sign)
            else:
                magnitude = lhs.magnitude - rhs.magnitude
                sign = determine_sign(magnitude, lhs.sign)

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

        return IntegerNumber(sign, magnitude)
Пример #6
0
    def choose_start_test_num_for_divte(
            input1: DecimalNumber,
            expected_product: DecimalNumber) -> DecimalNumber:
        log(f'Choosing a starting number to find {input1} \\* ? = {expected_product}...'
            )
        log_indent()

        log(f'Checking which case should apply...')
        if input1 < DecimalNumber.from_str(
                '1.0') and expected_product >= DecimalNumber.from_str('1.0'):
            log(f'{input1} has {len(input1.fractional.digits)} fractional digits'
                )
            log(f'{expected_product}\'s has {len(expected_product.whole.digits)} whole digits'
                )
            num_of_zeros = len(expected_product.whole.digits) + len(
                input1.fractional.digits) - 1
            start_test_num = DecimalNumber.from_str('1' + '0' * num_of_zeros)
        else:
            log(f'{input1} has {len(input1.whole.digits)} whole digits')
            log(f'{expected_product}\'s has {len(expected_product.whole.digits)} whole digits'
                )
            num_of_zeros = len(expected_product.whole.digits) - len(
                input1.whole.digits)
            start_test_num = DecimalNumber.from_str('1' + '0' * num_of_zeros)

        log(f'Starting number: {start_test_num}')

        log_unindent()
        log(f'{start_test_num}')
        return start_test_num
Пример #7
0
    def __gt__(self: IntegerNumber, other: IntegerNumber) -> bool:
        log(f'Greater than testing {self} and {other}...')
        log_indent()

        self_sign = self.sign
        if self_sign is None:  # assume 0 is a positive -- it simplifies logic below
            self_sign = Sign.POSITIVE

        other_sign = other.sign
        if other_sign is None:  # assume 0 is a positive -- it simplifies logic below
            other_sign = Sign.POSITIVE

        if self_sign == Sign.POSITIVE and other_sign == Sign.POSITIVE:
            log(f'{self.sign} > {other.sign}: Applying whole number less than...')
            ret = self.magnitude > other.magnitude
        elif self_sign == Sign.NEGATIVE and other_sign == Sign.NEGATIVE:
            log(f'{self.sign} > {other.sign}: Turning positive and applying whole number greater than...')
            ret = self.magnitude < other.magnitude
        elif self_sign == Sign.POSITIVE and other_sign == Sign.NEGATIVE:
            log(f'{self.sign} > {other.sign}:: Different signs -- number being tested is positive...')
            ret = True
        elif self_sign == Sign.NEGATIVE and other_sign == Sign.POSITIVE:
            log(f'{self.sign} > {other.sign}: Different signs -- number being tested is negative...')
            ret = False
        log(f'{ret}')

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

        return ret
Пример #8
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
Пример #9
0
    def __truediv__(lhs: IntegerNumber, rhs: IntegerNumber) -> (IntegerNumber, IntegerNumber):
        log(f'Dividing {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
            (quotient_magnitude, remainder_magnitude) = lhs.magnitude / rhs.magnitude
            quotient_sign = None
            remainder_sign = None
        elif rhs.sign is None:  # when sign isn't set, magnitude is always 0 -- a / 0 = err
            raise Exception('Cannot divide by 0')
        elif (lhs.sign == Sign.POSITIVE and rhs.sign == Sign.POSITIVE) \
                or (lhs.sign == Sign.NEGATIVE and rhs.sign == Sign.NEGATIVE):
            (quotient_magnitude, remainder_magnitude) = lhs.magnitude / rhs.magnitude
            quotient_sign = determine_sign(quotient_magnitude, Sign.POSITIVE)
            remainder_sign = determine_sign(remainder_magnitude, Sign.POSITIVE)
        elif (lhs.sign == Sign.POSITIVE and rhs.sign == Sign.NEGATIVE) \
                or (lhs.sign == Sign.NEGATIVE and rhs.sign == Sign.POSITIVE):
            (quotient_magnitude, remainder_magnitude) = lhs.magnitude / rhs.magnitude
            quotient_sign = determine_sign(quotient_magnitude, Sign.NEGATIVE)
            remainder_sign = determine_sign(remainder_magnitude, Sign.NEGATIVE)

        log_unindent()
        log(f'QUOTIENT: sign: {quotient_sign}, magnitude: {quotient_magnitude}')
        log(f'REMAINDER: sign: {remainder_sign}, magnitude: {remainder_magnitude}')

        return IntegerNumber(quotient_sign, quotient_magnitude), IntegerNumber(remainder_sign, remainder_magnitude)
Пример #10
0
    def simplify(self: FractionNumber) -> FractionNumber:
        # Sign is on the numerator
        log(f'Simplifying {self}...')
        log_indent()

        log(f'Calculating GCD for ({self._numerator.magnitude}) and ({self._denominator.magnitude})...'
            )
        gcd = gcd_euclid(self._numerator.magnitude,
                         self._denominator.magnitude)
        log(f'GCD is {gcd}')

        log(f'Dividing numerator ({self._numerator.magnitude}) by {gcd}...')
        new_num, _ = self._numerator.magnitude / gcd
        log(f'New numerator is {new_num}...')

        log(f'Dividing denominator ({self._denominator.magnitude}) by {gcd}...'
            )
        new_den, _ = self._denominator.magnitude / gcd
        log(f'New numerator is {new_den}...')

        # Sign of fraction is on the numerator
        if self.sign == Sign.NEGATIVE:  # if original was negative, so will the simplified
            res = FractionNumber(IntegerNumber(Sign.NEGATIVE, new_num),
                                 IntegerNumber(Sign.POSITIVE, new_den))
        elif self.sign == Sign.POSITIVE:  # if original was positive, so will the simplified
            res = FractionNumber(IntegerNumber(Sign.POSITIVE, new_num),
                                 IntegerNumber(Sign.POSITIVE, new_den))
        else:  # if original was 0 (no sign), so will the simplified
            res = FractionNumber(IntegerNumber(None, new_num),
                                 IntegerNumber(Sign.POSITIVE, new_den))

        log_unindent()
        log(f'{self} simplified to: {res}')

        return res
Пример #11
0
    def as_fraction(self: DecimalNumber) -> FractionNumber:
        log(f'Converting {self} to fraction number...')
        log_indent()

        log(f'Determining denominator based on length of fractional portion ({self.fractional})...'
            )
        denom = IntegerNumber.from_str('1' + '0' * len(self.fractional.digits))
        log(f'{denom}')

        log(f'Converting fractional portion ({self.fractional} to fraction...')
        fractional_fraction = FractionNumber(
            IntegerNumber.from_str(str(self.fractional)), denom)
        log(f'{fractional_fraction}')

        log(f'Converting whole portion ({self.whole}) to fraction...')
        whole_fraction = FractionNumber.from_whole(self.whole)
        log(f'{whole_fraction}')

        log(f'Adding ({whole_fraction}) to ({fractional_fraction})...')
        fraction = whole_fraction + fractional_fraction
        log(f'{fraction}')

        log(f'Applying sign of ({self.sign}) to {fraction}...')
        if self.sign == Sign.NEGATIVE:
            fraction = fraction * FractionNumber.from_str(
                "-1/1")  # make sign negative
        log(f'{fraction}')

        log_unindent()

        return fraction
Пример #12
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()
Пример #13
0
    def __gt__(lhs: DecimalNumber, rhs: DecimalNumber) -> bool:
        class PassedTestException(Exception):
            pass

        class FailedTestException(Exception):
            pass

        log(f'Greater than testing {lhs} and {rhs}...')
        log_indent()

        try:
            log(f'Testing sign...')
            sign_gt = lhs.sign == Sign.POSITIVE and (rhs.sign == Sign.NEGATIVE
                                                     or rhs.sign is None)
            if sign_gt:
                raise PassedTestException()
            sign_eq = lhs.sign == rhs.sign
            if not sign_eq:
                raise FailedTestException()
            log(f'Equal')

            log(f'Testing whole...')
            if lhs.sign != Sign.NEGATIVE:
                whole_gt = lhs.whole > rhs.whole
            else:
                whole_gt = lhs.whole < rhs.whole
            if whole_gt:
                raise PassedTestException()
            whole_eq = lhs.whole == rhs.whole
            if not whole_eq:
                raise FailedTestException()
            log(f'Equal')

            log(f'Testing fractional...')
            if lhs.sign != Sign.NEGATIVE:
                fractional_gt = lhs.fractional > rhs.fractional
            else:
                fractional_gt = lhs.fractional < rhs.fractional
            if fractional_gt:
                raise PassedTestException()
            fractional_eq = lhs.fractional == rhs.fractional
            if not fractional_eq:
                raise FailedTestException()
            log(f'Equal')

            ret = False
        except PassedTestException:
            log(f'Greater')
            ret = True
        except FailedTestException:
            log(f'Not greater or equal')
            ret = False

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

        return ret
Пример #14
0
    def __eq__(lhs: FractionalNumber, rhs: FractionalNumber) -> bool:
        if not isinstance(rhs, FractionalNumber):
            raise Exception()

        log(f'Equality testing {lhs} and {rhs}...')
        log_indent()

        ret = lhs.digits == rhs.digits

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

        return ret
Пример #15
0
    def choose_start_modifier_for_divte(
            start_test_num: DecimalNumber) -> DecimalNumber:
        log(f'Choosing a starting modifier for {start_test_num}...')
        log_indent()

        log(f'{start_test_num} has {len(start_test_num.whole.digits)} digits')
        num_of_zeros = len(start_test_num.whole.digits) - 1
        start_modifier_num = DecimalNumber.from_str('1' + '0' * num_of_zeros)

        log(f'Starting modifier: {start_modifier_num}')

        log_unindent()
        log(f'{start_modifier_num}')
        return start_modifier_num
Пример #16
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
Пример #17
0
    def __add__(lhs: FractionNumber, rhs: FractionNumber) -> FractionNumber:
        # Sign is only kept on the numerator, not the denominator
        log(f'Adding {lhs} and {rhs}...')
        log_indent()

        log(f'Converting {lhs} and {rhs} to equivalent fractions with least common denominator...'
            )
        lhs, rhs = FractionNumber.common_denominator_lcm(lhs, rhs)
        log(f'Equivalent fractions: {lhs} and {rhs}')
        log(f'Adding numerators of {lhs} and {rhs}...')
        res = FractionNumber(lhs._numerator + rhs._numerator, lhs._denominator)

        log_unindent()
        log(f'Result: {res}')

        return res
Пример #18
0
def is_prime(num: WholeNumber) -> bool:
    log(f'Test if {num} is prime...')
    log_indent()

    num_factors = factor_fastest(num)

    # At a minimum, all counting numbers have the factors 1 and the number itself (2 factors). If
    # there are more factore than that, it's a composite. Otherwise, it's a primse.

    log_unindent()
    if len(num_factors) == 2:
        log(f'{num}\'s factors are {num_factors} -- it is a prime')
        return True
    else:
        log(f'{num}\'s factors are {num_factors} -- it is a composite')
        return False
Пример #19
0
    def __eq__(self: IntegerNumber, other: IntegerNumber) -> bool:
        log(f'Equality testing {self} and {other}...')
        log_indent()

        log(f'Testing sign equality ({self.sign} vs {other.sign})...')
        sign_eq = self.sign == other.sign
        log(f'{sign_eq}')

        log(f'Testing magnitude equality ({self.magnitude} vs {other.magnitude})...')
        mag_eq = self.magnitude == other.magnitude
        log(f'{mag_eq}')

        log_unindent()
        ret = sign_eq and mag_eq
        log(f'{ret}')

        return ret
Пример #20
0
    def __mul__(lhs: FractionNumber, rhs: FractionNumber) -> FractionNumber:
        # Sign is only kept on the numerator, not the denominator
        log(f'Multiplying {lhs} and {rhs}')
        log_indent()

        log(f'Multiplying numerators {lhs._numerator} and {rhs._numerator}...')
        numerator = lhs._numerator * rhs._numerator

        log(f'Multiplying denominators {lhs._denominator} and {rhs._denominator}...'
            )
        denominator = lhs._denominator * rhs._denominator

        res = FractionNumber(numerator, denominator)

        log_unindent()
        log(f'Result: {res}')

        return res
Пример #21
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
Пример #22
0
    def from_fraction(value: FractionNumber) -> DecimalNumber:
        log(f'Converting {value} to a decimal number...')
        log_indent()

        log(f'Converting {value} to suitable fraction...')
        value = DecimalNumber.to_suitable_fraction(value)
        log(f'{value}')

        num = value.numerator
        denom = value.denominator
        if not str(denom).startswith('1'):
            raise Exception('Denominator must be power of 10')
        elif not set(str(denom)[1:]) == set('0') and not set(
                str(denom)[1:]) == set():
            raise Exception('Denominator must be power of 10')

        log(f'Resolving fraction {value}...')
        whole, remaining = num / denom
        log(f'{whole} wholes and {remaining} remaining')

        log(f'Converting {remaining} of {denom} to fractional value...')
        num_digits_in_rem = len(remaining.digits)
        num_0s_in_den = len(
            denom.digits
        ) - 1  # starts with 1 followed by 0s, so - 1 to ignore the starting 1
        num_0s_to_prepend_to_rem = num_0s_in_den - num_digits_in_rem
        fractional_digits = remaining.digits[:]  # copy digits
        fractional_digits = fractional_digits + [Digit(
            0)] * num_0s_to_prepend_to_rem  # this prepending 0s...
        # you might be confused because the
        # 0s are being addeed to the end, but
        # that's how FractionalNumber expects
        # digits -- in reversed order
        fractional = FractionalNumber(fractional_digits)
        log(f'{fractional}')

        sign = value.sign

        log_unindent()

        ret = DecimalNumber(sign, whole, fractional)
        log(f'Decimal number: {ret}')
        return ret
Пример #23
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
Пример #24
0
def gcd_factor(num1: WholeNumber, num2: WholeNumber) -> WholeNumber:
    log(f'Calculating gcd for {num1} and {num2}...')
    log_indent()

    log(f'Calculating factors for {num1}...')
    factors1 = factor_fastest(num1)
    log(f'Factors for {num1}: {factors1}')

    log(f'Calculating factors for {num2}...')
    factors2 = factor_fastest(num2)
    log(f'Factors for {num2}: {factors2}')

    log(f'Finding common factors...')
    common_factors = factors1 & factors2  # set intersection
    log(f'Common factors for {num1} and {num2}: {common_factors}')

    found = max(common_factors)

    log_unindent()
    log(f'GCD is {found}')
    return found
Пример #25
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
Пример #26
0
    def __gt__(lhs: FractionalNumber, rhs: FractionalNumber) -> bool:
        if not isinstance(rhs, FractionalNumber):
            raise Exception()

        log(f'Greater than testing {lhs} and {rhs}...')
        log_indent()

        count = max(len(lhs.digits), len(rhs.digits))
        for pos in range(0, count):  # from smallest to largest component
            log(f'Test digits {lhs[pos]} and {rhs[pos]}...')
            if lhs[pos] > rhs[pos]:
                log(f'{lhs[pos]} > {rhs[pos]} -- {lhs} is greater than {rhs}')
                return True
            elif lhs[pos] < rhs[pos]:
                log(f'{lhs[pos]} < {rhs[pos]} -- {lhs} is NOT greater than {rhs}, it is less than'
                    )
                return False
            else:
                log(f'{lhs[pos]} == {rhs[pos]} -- continuing testing')

        log(f'No more digits to test -- {lhs} is NOT greater than {rhs}, it is equal'
            )
        return False
Пример #27
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
Пример #28
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
Пример #29
0
    def __sub__(lhs: IntegerNumber, rhs: IntegerNumber) -> IntegerNumber:
        log(f'Subtracting {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

        def flip_sign(sign: Sign) -> Sign:
            if sign == Sign.POSITIVE:
                return Sign.NEGATIVE
            elif sign == Sign.NEGATIVE:
                return Sign.POSITIVE

        if lhs.sign is None:  # sign of None is only when magnitude is 0,  0 - a = -a
            sign = flip_sign(rhs.sign)
            magnitude = rhs.magnitude
        elif rhs.sign is None:  # sign of None is only when magnitude is 0,  a - 0 = a
            sign = lhs.sign
            magnitude = lhs.magnitude
        elif lhs.sign == rhs.sign:
            if rhs.magnitude >= lhs.magnitude:
                magnitude = rhs.magnitude - lhs.magnitude
                sign = determine_sign(magnitude, flip_sign(lhs.sign))
            else:
                magnitude = lhs.magnitude - rhs.magnitude
                sign = determine_sign(magnitude, lhs.sign)
        elif lhs.sign != rhs.sign:
            magnitude = lhs.magnitude + rhs.magnitude
            sign = determine_sign(magnitude, lhs.sign)

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

        return IntegerNumber(sign, magnitude)
Пример #30
0
    def __gt__(lhs: FractionNumber, rhs: FractionNumber) -> bool:
        log(f'Greater than testing {lhs} and {rhs}...')
        log_indent()

        # Sign is only kept on the numerator, not the denominator
        log(f'Checking if denominators are the same...')
        if lhs._denominator != rhs._denominator:
            log(f'Not same -- finding equivalent fractions with common denominator...'
                )
            log_indent()

            log(f'Calculating common denominator...')
            denominator = rhs._denominator * lhs._denominator
            log(f'{denominator}')

            log(f'Scaling numerator for {lhs} so denominator becomes {denominator}...'
                )
            lhs_numerator = lhs._numerator * rhs._denominator
            log(f'Numerator: {lhs_numerator} Denominator: {denominator}')

            log(f'Scaling numerator for {rhs} so denominator becomes {denominator}...'
                )
            rhs_numerator = rhs._numerator * lhs._denominator
            log(f'Numerator: {rhs_numerator} Denominator: {denominator}')

            log_unindent()
        else:
            log(f'Same')
            lhs_numerator = lhs._numerator
            rhs_numerator = rhs._numerator
            denominator = rhs._denominator

        log(f'Testing {lhs_numerator} > {rhs_numerator}...')
        ret = lhs_numerator > rhs_numerator
        log(f'{ret}')

        return ret