Единственная функция для преобразования десятичных значений в двоичные, шестнадцатеричные и восьмеричные не преобразуется в двоичные

Я пытаюсь создать стандартную функцию для преобразования любого десятичного значения в его восьмеричный, шестнадцатеричный и двоичный эквивалент, но по какой-то причине она не работает для двоичного кода. Я попытался добавить дополнительные меры предосторожности в условный оператор, чтобы проверить базу 2, но это все равно не сработало.

Это функция (я знаю, что это плохо работает с шестнадцатеричными значениями. Я позабочусь об этом позже):

def convert(num, base):
    remainder = num % base
    conv = []

    if(remainder == 0):
        conv.append('0')
    elif(remainder != 0 and base == 2):
        conv.append('1')
    else:
        conv.append(str(remainder))

    result = ''.join(conv)
    output = result[::-1]

    return int(output)

В строке elif(remainder != 0 and base == 2): я проверяю, не равен ли остаток 0, а основание равно 2, чтобы добавить 1 во временный список conv. Затем я преобразовываю список в строку, переворачиваю его и возвращаю как int.

Например. Если ввод 17, вывод должен быть таким:

    1     1     1     1
    2     2     2    10
    3     3     3    11
    4     4     4   100
    5     5     5   101
    6     6     6   110
    7     7     7   111
    8    10     8  1000
    9    11     9  1001
   10    12     A  1010
   11    13     B  1011
   12    14     C  1100
   13    15     D  1101
   14    16     E  1110
   15    17     F  1111
   16    20    10 10000
   17    21    11 10001

Это функции, которые заботятся о вводе и печати:

def print_formatted(number):
    # your code goes here

    for i in range(number):
        print(
            str(i + 1) + " " + 
            str(convert(i + 1, 8)) + " " + 
            str(convert(i + 1, 16)) + " " + 
            str((convert(i + 1, 2)))
            )


if __name__ == '__main__':
    n = int(input())
    print_formatted(n)

Обновить

Вместо того, чтобы повторять все уравнение, я решил использовать встроенные функции и обрезать первые два символа (например, 0b), чтобы они хорошо соответствовали формату. Я пытаюсь разнести их друг от друга в зависимости от ширины двоичного вывода, но я не мог придумать, как это сделать. Это то, что у меня есть до сих пор:

def convert(num, base):
    # get the highest power
    val = ''
    hex_char_list = ['A', 'B', 'C', 'D', 'E', 'F']

    if(base == 2):
        bin_num = bin(num)
        bin_list = list(bin_num)
        bin_list_2 = bin_list[2:]
        val = ''.join(bin_list_2)

    if(base == 8):
        oct_num = oct(num)
        oct_list = list(oct_num)
        oct_list_2 = oct_list[2:]
        val = ''.join(oct_list_2)

    if(base == 16):
        hex_num = hex(num)
        hex_list = list(hex_num)
        hex_list_2 = hex_list[2:]
        val = ''.join(hex_list_2)

        if val in hex_char_list:
            val = val.upper()

    return val

def print_formatted(number):
    # your code goes here
    width = len(convert(number, 2).format(number))

    for i in range(number):
        print(
            str(i + 1) + width + 
            str(convert(i + 1, 8)) + width + 
            str(convert(i + 1, 16)) + width + 
            str((convert(i + 1, 2)))
            )


if __name__ == '__main__':
    n = int(input())
    print_formatted(n)

person oo92    schedule 21.09.2019    source источник
comment
Какой текущий выход вы получаете?   -  person PrinceOfCreation    schedule 21.09.2019
comment
Какие десятичные значения? Как обычно, этот вопрос вообще не касается десятичных значений. num уже является двоичным к моменту вызова вашего метода.   -  person user207421    schedule 21.09.2019


Ответы (2)


Ваш elif лишний - если вы сделаете %2, результат может быть только 0 или 1 - не нужно обрабатывать его по-другому.


Ваш код не преобразует все число - вы проверяете модуль числа, а не то, как часто в него вписывается ваша база (и более высокие степени вашей базы).

Вам нужно получить максимально возможную мощность для вашей базы, которая вписывается в ваше число. Затем вам нужно узнать, как часто это число вписывается в ваше число, вычесть его из числа и продолжить оставшуюся часть этой операции. Вы уменьшаете свою силу на единицу и продолжаете, пока ваше число не станет равным 0. Затем вы складываете все числа в строку.

Ваш код исправлен:

def convert(num, base):
    # get the highest power
    power = 0
    while num // (base**(power+1)) > 0:
        power += 1

    # divide, remember, subtract - until down to the lowest power
    result = []
    while num >= 0:
        p = base**power
        if p == 1:
            result.append(num)
            break
        result.append(num // p)
        num -= result[-1]*p
        power -= 1

    return ''.join(map(str,result))

чтобы получить вывод:

1 1 1 1
2 2 2 10
3 3 3 11
4 4 4 100
5 5 5 101
6 6 6 110
7 7 7 111
8 10 8 1000
9 11 9 1001
10 12 10 1010
11 13 11 1011
12 14 12 1100
13 15 13 1101
14 16 14 1110
15 17 15 1111
16 20 10 10000

Или вы используете встроенные функции:

def make(i):
    for k in range(i+1):
        print(f"{k:>10} {bin(k):>10} {hex(k):>10} {oct(k):>10}")
        # or slice away the prefixes:
        # print(f"{k:>10} {bin(k)[2:]:>10} {hex(k)[2:]:>10} {oct(k)[2:]:>10}")


make(17)

Результат:

         0        0b0        0x0        0o0
         1        0b1        0x1        0o1
         2       0b10        0x2        0o2
         3       0b11        0x3        0o3
         4      0b100        0x4        0o4
         5      0b101        0x5        0o5
         6      0b110        0x6        0o6
         7      0b111        0x7        0o7
         8     0b1000        0x8       0o10
         9     0b1001        0x9       0o11
        10     0b1010        0xa       0o12
        11     0b1011        0xb       0o13
        12     0b1100        0xc       0o14
        13     0b1101        0xd       0o15
        14     0b1110        0xe       0o16
        15     0b1111        0xf       0o17
        16    0b10000       0x10       0o20
        17    0b10001       0x11       0o21
person Patrick Artner    schedule 21.09.2019
comment
Или вы можете использовать '{i:>#10} {i:>#10b} {i:>#10x} {i:>#10o}'.format(i=k) (# запрашивает префикс). - person Yann Vernier; 21.09.2019
comment
@Onur Опубликуйте новый вопрос, пожалуйста. На ваш оригинальный ответ был дан ответ. Это новое в форматировании строк и не имеет ничего общего с тем, как создавать восьмеричные/двоичные/шестнадцатеричные числа. Кроме того, мой пример здесь включал форматирование с пробелами. Просто рассчитайте ширину двоичного файла для вашего самого большого числа и отформатируйте его соответствующим образом. См. stackoverflow.com/questions/4302166/format-string-dynamically и использование-pythons-format-specification-mini-language-to- выравнивание поплавков - person Patrick Artner; 21.09.2019

Проблема в том, что вы берете только мод вашего числа (num % base), то есть самый правый («наименее значащий») бит. Нам нужен не самый младший бит, а вся декомпозиция.

NB: проблема здесь применима и ко всем другим основаниям (десятичным, шестнадцатеричным...).

Действительно, если запустить

n = 1000
print_formatted(n)

с вашими функциями вы получаете, что разложение 1000 по разным основаниям:

1000 0 8 0

(все они неверны).

Здесь я предлагаю рекурсивную реализацию:

def convert(integerToConvert, base = 2):
    '''
    When given a num and a base, will get the 
    conversion of that number in that base
    '''

    # The negative integer case is not taken into account
    if (integerToConvert < 0):
        print("ERROR: INTEGER < 0")
        return;

    # When the integer is 0, we know that we are done. There is no more bit
    if (integerToConvert == 0):
        print("WE ARE DONE")
        return;

    # get the current least significant coeff in the integerToEncode
    currentLeastSignificant = integerToConvert % base;
    print(currentLeastSignificant)

    # remove the least significant coeff and start again
    convert((integerToConvert - currentLeastSignificant) / base, base)

Я провел несколько быстрых тестов:

convert(17, 2)
1
0.0
0.0
0.0
1.0
WE ARE DONE

convert(16, 2)
0
0.0
0.0
0.0
1.0
WE ARE DONE

convert(17, 16)
1
1.0
WE ARE DONE

NB1: я печатаю числа, но вы можете хранить их в структуре данных по вашему выбору.

NB2: Самый значимый коэффициент печатается последним (можно сравнить с ожидаемым результатом)

NB3: все эти вычисления немного дороги, поэтому, если для вас важна скорость, лучше всего хранить все разложения в массивах и обращаться к ним (постоянное время).

person GabCaz    schedule 21.09.2019
comment
Эй, мужик. Я только что увидел твой ответ. Я дал вам голос из признательности. Если вы считаете, что это был хорошо заданный вопрос, не могли бы вы также проголосовать за меня? - person oo92; 28.09.2019
comment
@OnurOzbek Я уже проголосовал за вопрос. Я надеюсь, что ответ помог, хотя он, вероятно, менее эффективен, чем у Патрика Артнера (я не знаю, какова временная сложность режима...) - person GabCaz; 28.09.2019