Системы счисления
В системе счисления с основанием больше 10, цифры записываются так: 0, 1, 2, . 9, A, B, C, .
В тексте программ на языке Python можно использовать целочисленные константы, записанные в двоичной (префикс 0b ), восьмеричной (префикс 0o ) и шестнадцатеричной (префикс 0x ) системах счисления. После указанного префикса идут цифры, которые в двоичной системе счисления могут быть только 0 или 1, в восьмеричной — от 0 до 7, в шестнадцатеричной — от 0 до 9, а также буквы латинского алфавита от A до F (могут быть как строчными, так и заглавными). Например, десятичной число 179 можно задать несколькими способами.
A = 179 A = 0b10110011 A = 0o263 A = 0xB3
Если вы знаете стандартные функции языка Python для перевода представления чисел между различными системами счисления, то этими функциями пользоваться нельзя. Также нельзя использовать функции типа eval , exec и т.д.
Если программа выводит результат в системе счисления с основанием больше 10, то цифры записываются так: 0, 1, 2, . 9, A, B, C, .
A: Шестнадцатеричная цифра — 1
Дана шестнадцатеричная цифра, которую необходимо считать в величину типа str . Выведите ее десятичное значение.
Программа должна содержать функцию перевода hex2int(c). Аргумент функции имеет тип str , результат — int .
Перевод чисел в Python
В данной статье мы рассмотрим встроенные функции языка программирования Python по переводу чисел в различные системы счисления. А так же напишем универсальную функцию по переводу десятичных чисел в другие системы счисления.
Перевод чисел из десятичной системы счисления
Для перевода числа из десятичной системы счисления в двоичную можно воспользоваться оператором bin(). В качестве аргумента нужно передать значение в виде числа, а оператор вернет строку с двоичным числом. У результата также будет префикс 0b, указывающий на основание системы счисления.
number = 123 result = bin(number) print(result)
>'0b1111011'
Для перевода в восьмеричную систему счисления есть оператор oct(). Он также возвращает строку с восьмеричным числом и префиксом 0o.
number = 123 result = oct(number) print(result)
>'0o173'
При переводе в шестнадцатеричную систему счисления воспользуемся оператором hex(). Он вернет строку шестнадцатеричным числом и префиксом 0x
number = 123 result = hex(number) print(result)
>'0x7b'
Если же вам не нужен префикс у результата перевода, то всегда можно взять срез у полученной строки.
print(bin(123)[2:]) print(oct(123)[2:]) print(hex(123)[2:])
>'1111011' >'173' >'7b'
Так же выводить числа в других системах счисления можно используя f-строки и формат вывода. Для этого в строке, через символ : указываем буквы b — для двоичной, o — для восьмеричной и x — для шестнадцатеричной системы счисления.
n = 1984 print(f'Двоичное: ') print(f'Восьмеричное: ') print(f'Шестнадцатеричное: ')
Двоичное: 11111000000 Восьмеричное: 3700 Шестнадцатеричное: 7c0
А теперь напишем универсальную функцию convert_to() по переводу чисел из десятичной системы счисления в систему счисления в любым основанием. Наша функция будет ограничена только наличием символов в переводимой системе счисления.
Данная функция принимает три аргумента, два из которых обязательные. Это десятичное целое число number и основание переводимой системы счисления base. Третий аргумент upper служит для указания регистра вывода строки переведенного числа. По умолчанию он установлен в значение False.
def convert_to(number, base, upper=False): digits = '0123456789abcdefghijklmnopqrstuvwxyz' if base > len(digits): return None result = '' while number > 0: result = digits[number % base] + result number //= base return result.upper() if upper else result
Во второй строке мы задаем переменную digits, содержащую набор символов цифр и букв английского языка. Она нам понадобится для составления символов переведенного числа на основании остатков.
В третьей строке мы проверяем основание переданной системы счисления на его длину. Если основание окажется больше, чем количество символов в нашей строке digits, то мы прекращаем выполнение функции через вызов оператора return и возвращаем None. Это такая своеобразная защита функции от неправильно переданных аргументов. Если мы попробуем перевести число в большую систему счисления по основанию, чем у нас есть символов для его записи, то мы его не сможем записать.
Дальше заведем переменную result для хранения результата работы функции и зададим ей значение в виде пустой строки. Теперь с помощью цикла с условием будем находить остаток от деления числа number на основание base, а также уменьшать number в base раз используя целочисленное деление.
Остаток от деления числа на основание переводимой системы счисления мы будем использовать как индекс для получения символа в строке digits и добавлять его к результату result. Добавлять это значение следует слева, т.к. самый первый остаток является самым правым разрядом. Цикл выполняется до тех пор, пока исходное значение переменной number больше нуля.
После завершения цикла мы вернем результат через вызов return. Для этого воспользуемся тернарным оператором и проверим наш третий аргумент. Если он будет в значении True, то для строки result вызовем строкой метод .upper() который заменит все прописные символы английского языка на строчные. Иначе, вернем результат как есть.
А теперь проверим работу нашей функции. Для этого попробуем перевести числа в 2ю, 8ю, 16ю, 32ю и 64ю системы счисления. Для перевода в 32ю систему счисления мы укажем третий необязательный аргумент upper и зададим ему значение True.
print(convert_to(123, 2)) print(convert_to(123, 8)) print(convert_to(123, 16)) print(convert_to(123, 32, upper=True)) print(convert_to(123, 64))
>'1111011' >'173' >'7b' >'3R' >None
Перевод чисел в десятичную систему счисления
Для обратного перевода в десятичную систему счисления мы будем использовать оператор int(). Для этого передадим ему два аргумента, первый — это строка с числом в какой-то системе счисления, а второй — это основание системы счисления самого числа. По умолчанию для этого необязательного аргумента стоит значение равное 10.
В качестве самого числа нужно обязательно передать строку. Строка может содержать или само число или число с префиксом системы счисления.
Для перевода из двоичной системы счисления:
number = '11001' result = int(number, 2) print(result)
number = '0b11001' result = int(number, 2) print(result)
Для перевода из восьмеричной системы счисления:
Перевод десятичного числа в любую систему счисления
Написать программу, которая переводит десятичное число в любую другую систему счисления. Число и основание новой системы счисления вводятся с клавиатуры. При желании реализовать в программе функцию такого преобразования.
Решение задачи на языке программирования Python
Алгоритм перевода десятичного числа в любую другую систему счисления заключается в последовательном целочисленном делении сначала самого десятичного числа, а потом получаемых частных на основание системы счисления, в которую переводится число. Из остатков такого деления собирается представление числа в новой системе счисления. В той, на основание которой происходило деление. Сбор остатков происходит с конца.
Например, перевод десятичных чисел 160 в восьмеричную и 18 в двоичную системы счисления будет выглядеть так:
160 / 8 = 20 | 0 20 / 8 = 2 | 4 2 / 8 = 0 | 2
16010 = 2408
18 / 2 = 9 | 0 9 / 2 = 4 | 1 4 / 2 = 2 | 0 2 / 2 = 1 | 0 1 / 2 = 0 | 1
1810 = 100102
Даже если использовать этот алгоритм для перевода десятичного числа в десятичную систему счисления будет получен верный результат.
150 // 10 = 15 | 0 15 // 10 = 1 | 5 1 // 10 = 0 | 1
15010 = 15010
Проблема появляется в тот момент, когда основание системы счисления начинает превышать 10. В таких случаях нам не хватает привычных символов цифр (0-9) и требуется ввод дополнительных символов для обозначения значений, соответствующих десятичным числам 10, 11, 12 и т. д. Для примера переведем десятичное число в шестнадцатеричную систему счисления:
700 // 16 = 43 | 12 (C) 43 // 16 = 2 | 11 (B) 2 // 16 = 0 | 2
70010 = 2BC16
Десятичные остатки 12 и 11 при формировании шестнадцатеричного числа должны быть представлены одним разрядом. В таких случаях в качестве цифр, чье значение больше 9-ти, используются английские буквы. Так числу 10 будет соответствовать символ A , числу 11 — B и т. д.
Таким образом, при написании программы перевода десятичного числа в любую систему счисления мы должны предусмотреть подмену остатков на соответствующие им символы, если эта замена требуется.
Будем усложнять программу поэтапно и сначала напишем вариант кода, который переводит не в любую систему счисления, а только с основанием до 10-ти.
num = int(input()) base = 0 while not (2 base 9): base = int(input("Основание (2-9): ")) new = '' while num > 0: remainder = num % base new = str(remainder) + new num = num // base print(new)
В цикле сначала вычисляется остаток. Далее присоединям его спереди к строковой переменной new , в которой хранится представление числа в новой системе счисления. Последним действием присваиваем переменной num частное от целочисленного деления прежнего значения num на основание системы счисления.
Поскольку в языке программирования Python есть функция divmod , сократим код, объединив нахождение остатка и целочисленное деление:
. while num > 0: num, remainder = divmod(num, base) new = str(remainder) + new .
Вызов divmod(num, base) возвращает кортеж из частного и остатка от деления num на base . Далее частное присваивается num , остаток — remainder .
Теперь напишем программу, которая переводит число исключительно в шестнадцатеричную систему счисления. Для хранения символов, которыми будут заменяться двузначные остатки, используем строку из этих символов.
num = int(input()) base = 16 letters = 'ABCDEF' new = '' while num > 0: num, remainder = divmod(num, base) if remainder > 9: letter_id = remainder - 10 remainder = letters[letter_id] new = str(remainder) + new print(new)
Числу 10 соответствует символ A . Поэтому если остаток равен десяти, то letter_id будет равно нулю. Символ под индексом 0 в строке букв — как раз A . Если остаток равен 15-ти, то letter_id будет равно пяти, а letters[5] вернет F .
Программу можно упростить, если в строку символов добавить цифры. В этом случае остатки будут точно соответствовать индексам, под которыми находятся соответствующие им символы.
num = int(input()) base = 16 letters = '0123456789ABCDEF' new = '' while num > 0: num, remainder = divmod(num, base) new = letters[remainder] + new print(new)
На этом этапе должно стать понятно, как написать программу конвертации десятичного числа в почти любую систему счисления. Достаточно немного подправить код перевода в шестнадцатеричную систему, дописав в строку дополнительный набор символов, а не заканчивать ее на F .
Чтобы не хранить в программе строку большой длины и избежать ошибки из-за нечаянно пропущенного какого-нибудь символа, вернемся к варианту, в котором остатки больше девяти заменяются в теле условного оператора. При этом буквы будем брать не из определенной в коде строки, а из встроенной таблицы символов.
num = int(input()) base = 0 while not (2 base 36): base = int(input("Основание (2-36): ")) new = '' while num > 0: num, remainder = divmod(num, base) if remainder > 9: letter = remainder - 10 remainder = chr(ord('A') + letter) new = str(remainder) + new print(new)
Вызов ord(‘A’) возвращает код буквы A в таблице Unicode. К этому коду-числу мы прибавляем смещение по алфавиту (значение letter ). С помощью функции chr() получаем соответстующую коду букву.
def convert_integer(decimal, radix): if radix > 36: return "Основание системы счисления должно быть не больше 36-ти" number = '' while decimal > 0: decimal, remainder = divmod(decimal, radix) if remainder > 9: remainder = chr(ord('A') + remainder - 10) number = str(remainder) + number return number num = int(input("Десятичное число: ")) base = int(input("Основание (2-36): ")) print(convert_integer(num, base))
Ограничение по основанию в 36 связано с количеством букв в английском алфавите. Их 26, плюс десять цифр. Расширить диапазон оснований можно за счет взятия недостающих символов из какой-либо другой части таблицы Unicode. Например, можно добавить к условному оператору ветку elif с условием remainder > 35 , а в теле вычитать из remainder 36.
Однако написать программу, которая переводит десятичное число в абсолютно любую систему счисления нельзя. Иначе надо суметь решить задачу генерации случайного символа, который не должен быть похож ни на какой из полученных ранее.
X Скрыть Наверх
Решение задач на Python
Системы счисления
В системе счисления с основанием больше 10, цифры записываются так: 0, 1, 2, . 9, A, B, C, .
В тексте программ на языке Python можно использовать целочисленные константы, записанные в двоичной (префикс 0b ), восьмеричной (префикс 0o ) и шестнадцатеричной (префикс 0x ) системах счисления. После указанного префикса идут цифры, которые в двоичной системе счисления могут быть только 0 или 1, в восьмеричной — от 0 до 7, в шестнадцатеричной — от 0 до 9, а также буквы латинского алфавита от A до F (могут быть как строчными, так и заглавными). Например, десятичной число 179 можно задать несколькими способами.
A = 179 A = 0b10110011 A = 0o263 A = 0xB3
Если вы знаете стандартные функции языка Python для перевода представления чисел между различными системами счисления, то этими функциями пользоваться нельзя. Также нельзя использовать функции типа eval , exec и т.д.
Если программа выводит результат в системе счисления с основанием больше 10, то цифры записываются так: 0, 1, 2, . 9, A, B, C, .
A: Шестнадцатеричную цифру в int
Дана шестнадцатеричная цифра, записанная в строке из одного символа. Определите её числовое значение.
Решение оформите в виде функции hex2int(c: str) -> int.
На проверку сдайте только тело функции.
hex2int('9')
hex2int('F')
B: int в шестнадцатеричную цифру
Решите задачу, обратную предыдущей.
Решение оформите в виде функции int2hex(n: int) -> str.
int2hex(9)
int2hex(15)
C: Из двоичной в int
Дано число, записанное в двоичной системе счисления. Переведите его в тип int.
Решение оформите в виде функции bin2int(s: str) -> int .
Решение должно использовать схему Горнера.
bin2int('10110011')
D: Из шестнадцатеричной в int
Решите предыдущую задачу в случае, когда входное число задано в шестнадцатеричном виде. Соответствующая функция должна называться hex2int(s: str) -> int.
hex2int('B3')
E: Из int в двоичную
Переведите число из int в двоичную систему числения.
int2bin(179)
'10110011'
F: Из int в шестнадцатеричную
Переведите число из десятичной системы в шестнадцатеричную.
int2hex(179)
G: Из любой в любую
Напишите программу, переводящую запись числа между двумя произвольными системами счисления.
На вход программа получает три величины: n, A, k, где n и k – натуральные числа от 2 до 36: основания системы счисления, A – число, записанное в в системе счисления с основанием n, A
Необходимо вывести значение A в системе счисления с основанием k без лидирующих нулей.
2
101111
16
10
35
36
H: Из шестнадцатеричной в двоичную
Переведите число из шестнадцатеричной системы счисления в двоичную. Исходное число может быть очень большим (до \(2\times10^5\) символов). Необходимо вывести результат без лидирующих нулей.
hex2bin('2F')
'101111'
I: Из двоичной в шестнадцатеричную
Переведите число из двоичной системы счисления в шестнадцатеричную. Исходное число может быть очень большим (до \(12\times10^6\) символов).
bin2hex('101111')
J: Из уравновешенной троичной в int
В уравновешенной троичной системе счисления используется основание 3 и три цифры: 0, 1 и -1. Цифру -1 будем обозначать знаком $. Достоинство уравновешенной троичной системы счисления: простота хранения отрицательных чисел и удобство нахождения числа, противоположному данному.
Вот как записываются небольшие числа в уравновешенной троичной системе счисления:
| Десятичная | -9 | -8 | -7 | -6 | -5 | -4 | -3 | -2 | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Уравнов. троичная | $00 | $01 | $1$ | $10 | $11 | $$ | $0 | $1 | $ | 0 | 1 | 1$ | 10 | 11 | 1$$ | 1$0 | 1$1 | 10$ | 100 |
Подробней о уравновешенной троичной системе счисления можно прочитать в Википедии (статья Троичная система счисления, там используется термин «троичная симметричная система счисления»).
Дана запись числа в уравновешенной троичной системе счисления. Переведите её в значение типа int.
ter2int('$01')
K: Из фибоначчиевой в int
Рассмотрим последовательность Фибоначчи: \(\varphi_1=1\), \(\varphi_2=2\), \(\varphi_n=\varphi_+\varphi_\) при \(n\gt 2\). В частности, \(\varphi_3=3\), \(\varphi_4=5\), \(\varphi_5=8\) и т.д.
Любое натуральное число можно представить в виде суммы нескольких членов последовательности Фибоначчи. Такое представление будет неоднозначным, но если наложить дополнительное условие, что в представлении нет двух соседних членов последовательности Фибоначчи, то представление становится единственным.
Будем говорить, что число \(A\) представимо в фибоначчиевой системе счисления в виде \(a_ka_. a_1\), где \(a_i\in\\), если \(A=a_k\varphi_k+. +a_1\varphi_1\) и в записи \(a_ka_. a_1\) нет двух единиц подряд.
Вот как записываются небольшие числа в фибоначчиевой системе счисления:
| Десятичная | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Фибоначчиева | 1 | 10 | 100 | 101 | 1000 | 1001 | 1010 | 10000 | 10001 | 10010 | 10100 | 10101 | 100000 |
Подробней о фибоначчиевой системе счисления можно прочитать в Википедии (статья Фибоначчиева система счисления).
Дана запись числа в фибоначчиевой системе счисления. Переведите его в тип int.
fib2int('10101')
L: Из int в уравновешенную троичную
Дано целое число oт \(-2\times 10^9\) до \(2\times 10^9\). Найдите его представление в уравновешенной троичной системе счисления без лидирующих нулей (за исключением числа 0, запись которого имеет вид 0).
int2ter(-8)
M: Из int в фибоначчиеву
Дано целое число oт 1 до \(2\times 10^9\). Выведите его представление в фибоначчиевой системе счисления без лидирующих нулей.
int2fib(12)
'10101'
N: Инкремент
Дана запись числа в некоторой системе счисления. Увеличьте число на 1 и верните его представление в этой же системе счисления. Сдайте на проверку только тело функции.
Решение оформите в виде функции inc(n: str, base: int) -> str .
inc('19A', 11)
O: Декремент
Решите аналогичную задачу для уменьшения числа на 1.
dec('1A0', 11)
P: Инкремент в уравновешенной троичной системе счисления
Реализуйте инкремент числа в уравновешенной троичной системе счисления.
Решение оформите в виде функции inc_ter(n: str) -> str .
inc_ter('$01')
Q: Декремент в уравновешенной троичной системе счисления
Реализуйте декремент числа в уравновешенной троичной системе счисления.
Решение оформите в виде функции dec_ter(n: str) -> str .
dec_ter('$1$')
R: Фибоначчиев инкремент
Реализуйте инкремент числа в фибоначчиевой системе счисления.
Решение оформите в виде функции inc_fib(n: str) -> str .
inc_fib('100101')
'101000'
S: Фибоначчиев декремент
Реализуйте декремент числа в фибоначчиевой системе счисления.
Решение оформите в виде функции dec_fib(n: str) -> str .
dec_fib('101000')
'100101'
T: Шестнадцатеричное сложение
Дано два шестнадцатеричных числа, длиной до 100000 символов каждый. Вычислите их сумму.
sum_hex('F1', 'F')
U: Уравновешенное троичное сложение
Реализуйте сложение в уравновешенной троичной системе счисления.
sum_ter('1$$$', '$0$')
Пример соответствует выражению 14+(-10)=4.
V: Фибоначчиево сложение
Реализуйте сложение в фибоначчиевой системе счисления.
Решение оформите в виде функции sum_fib(n1: str, n2: str) -> str .
sum_fib('10010', '10101')
'1000001'
W: Шестнадцатеричное вычитание
Реализуйте алгоритм вычитания двух чисел, записанных в шестнадцатеричной системе счисления.
Решение оформите в виде функции dif_hex(n1: str, n2: str) -> str .
dif_hex('100', 'F')
X: Фибоначчиево вычитание
Реализуйте вычитание в фибоначчиевой системе счисления.
Решение оформите в виде функции dif_fib(n1: str, n2: str) -> str . Гарантируется, что первое данное число не меньше второго.
dif_fib('1000001', '10101')
'10010'
Y: Умножение длинного числа на короткое
Реализуйте алгоритм умножения длинного числа, записанного в шестнадцатеричной системе счисления, на короткое число (из одной шестнадцатеричной цифры).
Решение оформите в виде функции mul_hex(n1: str, n2: str) -> str . Гарантируется, что второй параметр состоит ровно из одной цифры.
Сложность решения: линейная от длины первого числа (длина числа до 100000 знаков, ограничение по времени — 1 секунда).
mul_hex('A38', 'D')
'84D8'
Z: Шестнадцатеричное умножение
Реализуйте алгоритм умножения двух чисел, записанных в шестнадцатеричной системе счисления.
Решение оформите в виде функции mul_hex(n1: str, n2: str) -> str .
Сложность решения: квадрат от длины входных чисел (длина чисел до 1000 знаков).
- Использование длинной арифметики Python (например, привести число в int, перемножить, перевести обратно в строку).
- Переход к большему основанию системы счисления (например, к основанию 256 или 65536).
- Переведите строку в список цифр (значений типа int), все вычисления проводите только с числами, а не со строками. Перевод обратно в строку выполняйте в самом конце.
- “Разверите“ число: под индексом \(i\) в списке должна храниться цифра, соответствующая \(16^i\). Тогда при перемножении двух цифр \(a_i\) и \(b_j\) результат попадает в разряд \(i+j\).
- Можно не обращать внимания на переполнения разрядов и не следить за тем, что все полученные цифры будут меньше 16. Считайте, что вы храните произвольные коэффициенты, соответствующие степеням основания, а нормализацию представления выполните в самом конце.
mul_hex('A1', '7F')
'4FDF'
ZA: Развёрнутая фибоначчиева форма
В развёрнутой фибоначчиевой форме запись числа в фибоначчиевой системе счисления не содержит двух подряд идущих нулей. Для каждого числа существует единственное представление в развёрнутой фибоначчиевой форме.
Дано целое число oт 1 до 2·10 9 . Найдите его представление в развёрнутой фибоначчиевой форме.
int2fib(13)
'10110'
ZZ: Умножение Карацубы
Реализуйте алгоритм умножения длинных чисел, записанных в шестнадцатеричной системе счисления, при помощи метода Карацубы.
Решение оформите в виде функции mul_hex(n1: str, n2: str) -> str .
Требования к решению: вычисления должны проводиться в 16-ричной системе счисления (нельзя переходить к большему основанию, например, 256 или 65536). Длина входных чисел — до 10000 знаков, ограничение по времени — 10 секунд.
Советы по реализации
- Метод Карацубы — рекурсивный алгоритм, вы сводите задачу умножения длинных чисел к задаче умножение чисел меньшей длины. При этом при маленькой длине чисел метод Карацубы не даёт выгоды, используйте умножение “в столбик”. Скорее всего при длинах чисел меньше 100 выгоднее использовать умножение “в столбик”, а не метод Карацубы. Возможно, вам придется подбирать эту границу экспериментально.
- Можно не обращать внимания на переполнение разрядов и даже можно считать, что при умножении в некоторых разрядах могут получаться отрицательные значения (там же есть вычитание). Да и вычитание можно реализовать без заёма значений из старших разрядов, просто считайте, что цифры могут быть и отрицательными. Нормализацию представления результата выполняйте в самом конце.
mul_hex('A1', '7F')
