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}')
def __init__(self, numerator: IntegerNumber, denominator: IntegerNumber): if denominator == IntegerNumber.from_int(0): raise Exception('Denominator cannot be 0') self._numerator = numerator.copy() self._denominator = denominator.copy() self._normalize_sign()
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
def defineRandomIntegerNumber(self, numericalBase): l = randint(1, 10) representation = "" for i in range(l): representation += IntegerNumber.NumericalSymbols[randint( 0, numericalBase - 1)] number = IntegerNumber(numericalBase, representation) number.removeLeadingZeros() return number
def main(): log_whitelist([(inspect.getfile(IntegerNumber), '__lt__')]) 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 = IntegerNumber.from_str(args[0]) input2 = IntegerNumber.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")
def _normalize_sign(self: FractionNumber): # Normalize so that sign is on the numerator and the denominator is always positive if self._numerator.sign is None: # sign of None means magnitude of 0 pass # if num's sign is None, the only value it can be is 0, so skip elif self._numerator.sign != self._denominator.sign: self._numerator = IntegerNumber(Sign.NEGATIVE, self._numerator.magnitude) elif self._numerator.sign == self._numerator.sign: self._numerator = IntegerNumber(Sign.POSITIVE, self._numerator.magnitude) self._denominator = IntegerNumber(Sign.POSITIVE, self._denominator.magnitude)
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
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
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
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
def run(self): while True: try: self.displayMenu() command = input("Enter option: ") if command == "1": n, m = self.readOperands() print("\nResult: ", n, " + ", m, " = ", n + m, "\n") elif command == "2": n, m = self.readOperands() print("\nResult: ", n, " - ", m, " = ", n - m, "\n") elif command == "3": n, m = self.readOperands() print("\nResult: ", n, " * ", m, " = ", n * m, "\n") elif command == "4": n = self.readIntegerNumber() m = self.getSmallIntegerNumber() print("\n Result: ") print( n, " / ", m, " = ", n // m, " remainder ", IntegerNumber(n.getNumericalBase(), IntegerNumber.NumericalSymbols[n % m])) elif command == "5": n = self.readIntegerNumber() m = int(input("Enter destination base: ")) print("\nResult: ", n, " = ", n.conversionToBase(m)) elif command == "x": break else: print("\nUnknown command...\n") except ValueError: print("\nValue should be an integer number.\n") except IntegerNumberException as ine: print("\n\n" + str(ine) + "\n\n") except Exception as e: print("\n\n" + str(e) + "\n\n") self.continuity()
def readIntegerNumber(self): """read a number""" numericalBase = int(input("Enter base: ")) repr = input("Enter the number: ") return IntegerNumber(numericalBase, repr)
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
def denominator(self: FractionNumber, denominator: WholeNumber): self._denominator = IntegerNumber(Sign.POSITIVE, denominator) self._normalize_sign()
def numerator(self: FractionNumber, numerator: WholeNumber): self._numerator = IntegerNumber(self._sign, numerator) self._normalize_sign()
def sign(self: FractionNumber, sign: Union[Sign, None]): self._numerator = IntegerNumber(sign, self._numerator.magnitude) self._normalize_sign()
def testConversions(self): assert (IntegerNumber(4, "33221100").conversionToBase(9) == IntegerNumber( 9, "106810")) assert (IntegerNumber( 4, "123032122").conversionToBase(16) == IntegerNumber(16, "1B39A")) assert (IntegerNumber(4, "33221100") + IntegerNumber(4, "123032122") == IntegerNumber(4, "222313222")) assert (IntegerNumber(7, "1230056").conversionToBase(4) == IntegerNumber( 4, "212230223")) assert (IntegerNumber(7, "445566").conversionToBase(4) == IntegerNumber( 4, "103033320")) assert (IntegerNumber(16, "ABCDE1").conversionToBase(4) == IntegerNumber( 4, "222330313201")) assert (IntegerNumber(16, "7").conversionToBase(8) == IntegerNumber( 8, "7")) assert (IntegerNumber(6, "54321").conversionToBase(5) == IntegerNumber( 5, "214330")) assert (IntegerNumber(6, "3").conversionToBase(2) == IntegerNumber( 2, "11")) assert (IntegerNumber(7, "1230056") - IntegerNumber(7, "445566") == IntegerNumber(7, "451160")) assert (IntegerNumber(16, "ABCDE1") * IntegerNumber(16, "7") == IntegerNumber(16, "4B2A127")) assert (IntegerNumber(6, "54321") // 3 == IntegerNumber(6, "15304")) assert (IntegerNumber(6, "54321") // 4 == IntegerNumber(6, "12350")) assert (IntegerNumber(10, "120") % 7 == 1) assert (IntegerNumber(10, "17") * IntegerNumber(10, "7") + IntegerNumber(10, "1") == IntegerNumber(10, "120"))
def from_str(val: str) -> FractionNumber: inputs = val.split('/', 2) return FractionNumber(IntegerNumber.from_str(inputs[0].strip()), IntegerNumber.from_str(inputs[1].strip()))
def from_int(numerator: int) -> FractionNumber: return FractionNumber(IntegerNumber.from_int(numerator), IntegerNumber.from_int(1))
def from_integer(numerator: IntegerNumber) -> FractionNumber: return FractionNumber( numerator, IntegerNumber.from_whole(WholeNumber.from_str('1')))