2020-06-11 15:59:42 +00:00
|
|
|
"""Convert a positive Decimal Number to Any Other Representation"""
|
|
|
|
|
2022-10-16 09:33:29 +00:00
|
|
|
from string import ascii_uppercase
|
|
|
|
|
|
|
|
ALPHABET_VALUES = {str(ord(c) - 55): c for c in ascii_uppercase}
|
|
|
|
|
2020-06-11 15:59:42 +00:00
|
|
|
|
|
|
|
def decimal_to_any(num: int, base: int) -> str:
|
|
|
|
"""
|
2020-09-10 08:31:26 +00:00
|
|
|
Convert a positive integer to another base as str.
|
|
|
|
>>> decimal_to_any(0, 2)
|
|
|
|
'0'
|
|
|
|
>>> decimal_to_any(5, 4)
|
|
|
|
'11'
|
|
|
|
>>> decimal_to_any(20, 3)
|
|
|
|
'202'
|
|
|
|
>>> decimal_to_any(58, 16)
|
|
|
|
'3A'
|
|
|
|
>>> decimal_to_any(243, 17)
|
|
|
|
'E5'
|
|
|
|
>>> decimal_to_any(34923, 36)
|
|
|
|
'QY3'
|
|
|
|
>>> decimal_to_any(10, 11)
|
|
|
|
'A'
|
|
|
|
>>> decimal_to_any(16, 16)
|
|
|
|
'10'
|
|
|
|
>>> decimal_to_any(36, 36)
|
|
|
|
'10'
|
|
|
|
>>> # negatives will error
|
|
|
|
>>> decimal_to_any(-45, 8) # doctest: +ELLIPSIS
|
|
|
|
Traceback (most recent call last):
|
2022-10-27 17:42:30 +00:00
|
|
|
...
|
2020-09-10 08:31:26 +00:00
|
|
|
ValueError: parameter must be positive int
|
|
|
|
>>> # floats will error
|
|
|
|
>>> decimal_to_any(34.4, 6) # doctest: +ELLIPSIS
|
|
|
|
Traceback (most recent call last):
|
2022-10-27 17:42:30 +00:00
|
|
|
...
|
2020-09-10 08:31:26 +00:00
|
|
|
TypeError: int() can't convert non-string with explicit base
|
|
|
|
>>> # a float base will error
|
|
|
|
>>> decimal_to_any(5, 2.5) # doctest: +ELLIPSIS
|
|
|
|
Traceback (most recent call last):
|
2022-10-27 17:42:30 +00:00
|
|
|
...
|
2020-09-10 08:31:26 +00:00
|
|
|
TypeError: 'float' object cannot be interpreted as an integer
|
|
|
|
>>> # a str base will error
|
|
|
|
>>> decimal_to_any(10, '16') # doctest: +ELLIPSIS
|
|
|
|
Traceback (most recent call last):
|
2022-10-27 17:42:30 +00:00
|
|
|
...
|
2020-09-10 08:31:26 +00:00
|
|
|
TypeError: 'str' object cannot be interpreted as an integer
|
|
|
|
>>> # a base less than 2 will error
|
|
|
|
>>> decimal_to_any(7, 0) # doctest: +ELLIPSIS
|
|
|
|
Traceback (most recent call last):
|
2022-10-27 17:42:30 +00:00
|
|
|
...
|
2020-09-10 08:31:26 +00:00
|
|
|
ValueError: base must be >= 2
|
|
|
|
>>> # a base greater than 36 will error
|
|
|
|
>>> decimal_to_any(34, 37) # doctest: +ELLIPSIS
|
|
|
|
Traceback (most recent call last):
|
2022-10-27 17:42:30 +00:00
|
|
|
...
|
2020-09-10 08:31:26 +00:00
|
|
|
ValueError: base must be <= 36
|
2020-06-11 15:59:42 +00:00
|
|
|
"""
|
|
|
|
if isinstance(num, float):
|
|
|
|
raise TypeError("int() can't convert non-string with explicit base")
|
|
|
|
if num < 0:
|
|
|
|
raise ValueError("parameter must be positive int")
|
|
|
|
if isinstance(base, str):
|
|
|
|
raise TypeError("'str' object cannot be interpreted as an integer")
|
|
|
|
if isinstance(base, float):
|
|
|
|
raise TypeError("'float' object cannot be interpreted as an integer")
|
|
|
|
if base in (0, 1):
|
|
|
|
raise ValueError("base must be >= 2")
|
|
|
|
if base > 36:
|
|
|
|
raise ValueError("base must be <= 36")
|
|
|
|
new_value = ""
|
|
|
|
mod = 0
|
|
|
|
div = 0
|
|
|
|
while div != 1:
|
|
|
|
div, mod = divmod(num, base)
|
|
|
|
if base >= 11 and 9 < mod < 36:
|
|
|
|
actual_value = ALPHABET_VALUES[str(mod)]
|
|
|
|
mod = actual_value
|
|
|
|
new_value += str(mod)
|
|
|
|
div = num // base
|
|
|
|
num = div
|
|
|
|
if div == 0:
|
|
|
|
return str(new_value[::-1])
|
|
|
|
elif div == 1:
|
|
|
|
new_value += str(div)
|
|
|
|
return str(new_value[::-1])
|
|
|
|
|
|
|
|
return new_value[::-1]
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
import doctest
|
|
|
|
|
|
|
|
doctest.testmod()
|
|
|
|
|
|
|
|
for base in range(2, 37):
|
|
|
|
for num in range(1000):
|
|
|
|
assert int(decimal_to_any(num, base), base) == num, (
|
2020-06-11 20:22:16 +00:00
|
|
|
num,
|
|
|
|
base,
|
|
|
|
decimal_to_any(num, base),
|
|
|
|
int(decimal_to_any(num, base), base),
|
|
|
|
)
|