import string ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' def from_base(number, base, alphabet=None): if base < 2: raise ValueError('base must be >= 2.') if not isinstance(base, int): raise TypeError('base must be an int.') if base == 10: return int(number) if alphabet is None: alphabet = ALPHABET number = str(number) alphabet = alphabet[:base] if number.count('.') > 1: raise ValueError('Too many decimal points') mixed_case = ( any(c in string.ascii_uppercase for c in alphabet) and any(c in string.ascii_lowercase for c in alphabet) ) if not mixed_case: alphabet = alphabet.upper() number = number.upper() char_set = set(number.replace('.', '', 1)) alpha_set = set(alphabet) differences = char_set.difference(alpha_set) if len(differences) > 0: raise ValueError('Unknown characters for base', base, differences) alpha_dict = {character: index for (index, character) in enumerate(alphabet)} try: decimal_pos = number.index('.') except ValueError: decimal_pos = len(number) result = 0 for (index, character) in enumerate(number): if index == decimal_pos: continue power = (decimal_pos - index) if index < decimal_pos: power -= 1 value = alpha_dict[character] * (base ** power) result += value return result def to_base(number, base, decimal_places=10, alphabet=None): if base < 2: raise ValueError('base must be >= 2.') if not isinstance(base, int): raise TypeError('base must be an int.') if base == 10: return str(number) if alphabet is None: alphabet = ALPHABET if base > len(alphabet): raise ValueError(f'Not enough symbols in alphabet for base {base}.') result = '' whole_portion = int(number) float_portion = number - whole_portion if whole_portion == 0: result = alphabet[0] while whole_portion > 0: (whole_portion, remainder) = divmod(whole_portion, base) result = alphabet[remainder] + result if float_portion != 0: result += '.' for x in range(decimal_places): float_portion *= base whole = int(float_portion) float_portion -= whole result += alphabet[whole] return result