Отображение числа в двоичном виде путем сдвига
Я сделал программу, в которой я пытаюсь отобразить двоичную форму числа, введенного пользователем. Но программа не делает маскировку правильно. Что я должен сделать, чтобы решить это?
пользовательский ввод в $s0
Loop:
and $t0,$s0,2147483648 // anding it with this number because only its MSB is 1 all other bits are zero
sll $s0,$s0,1
move $a0,$t0
li $v0,1
syscall
beq $t1,31,Exit
addi $t1,$t1,1
j Loop
ОБНОВЛЕНИЕ: я изменил этот код в соответствии с предложением dbrank0, но теперь он отображает только один бит вместо 32 бит
Loop:
and $t0,$s0,2147483648
sll $s0,$s0,1
beq $t1,31,Exit
move $a0,$t0
addi $t1,$t1,1
bgtu $t0,0,Check
li $t0,0
j Loop
Disp:
li $v0,1
syscall
j Loop
Check:
li $t0,1
j Disp
Будет много, если кто-нибудь поможет мне решить эту проблему.
С уважением
2 ответа
Вот проблема:
bgtu $t0, 0, Check
li $t0, 0
j Loop
Если это ноль, он не отображается, потому что вы переходите к Loop
вместо Disp
, О, посмотри, Disp
в любом случае написано сразу после этой инструкции! Решение: избавиться от прыжка в целом.
Вот еще одна проблема, как описано в dbrank0:
Disp:
li $v0,1
syscall
Это будет отображать содержимое $a0
как целое число Но если бит был 1, значение $a0
будет 0x80000000, а не 1! Когда вы попытаетесь напечатать 0x80000000, он будет обрабатывать его как целое число со знаком и вместо этого выдает -2147483648.
Вот еще одна проблема:
beq $t1,31,Exit
Во-первых, эта инструкция находится в неловком месте. Почему вы проверяете состояние выхода после and
а также shift
? Вы должны проверить это либо в начале, либо в конце, а не в середине. Кроме того, вам нужно сравнить с 32, потому что есть 32 бита, и вы проверяете перед печатью каждого бита. В настоящее время последний бит будет отрублен в результате.
Есть умный способ заставить вашу программу выполнять меньше работы, чем нужно. Воспользуйтесь тем, что вы отображаете слева направо (т. Е. Самый старший бит отображается первым). Когда MSB установлен, его можно рассматривать как отрицательное число в дополнении к двум!
li $t0, 32
li $v0, 1
Loop:
bltz $s0, Bit1
li $a0, 0
j Disp
Bit1:
li $a0, 1
Disp:
syscall
Tail:
subi $t0, $t0, 1
beqz $t0, Exit
sll $s0, $s0, 1
j Loop
Exit:
Дан указатель на конец достаточно большого буфера в $a1
и входное целое число в $a0
эта функция сохраняет ASCII-цифры для формирования строки.
Это использует AND для извлечения младшего бита. Он работает от младших до старших битов, поэтому мы храним в обратном направлении от конца буфера, оставляя строку ASCII в порядке печати.
.globl to_base2_end # args: (unsigned a, char *buf_end)
to_base2_end:
# Runs at least once, so we get "0" instead of the empty string for 0
.loop: # do {
andi $t0, $a0, 1 # extract the low bit
ori $t0, $t0, '0' # ASCII digit
addiu $a1, $a1, -1
sb $t0, ($a1) # *--buf = ASCII digit
srl $a0, $a0, 1 # a0 >>= 1
bne $a0, $zero, .loop # }while (a0!=0);
move $v0, $a1 # return pointer to the first digit
jr $ra
Обратите внимание, что это уменьшается до первого хранилища, так что вы можете передать ему указатель на '\n'
в конце буфера.
Конечно, вы можете встроить этот цикл вместо использования его в качестве вызываемой функции. Он останавливается, когда целое число равно нулю, вместо зацикливания фиксированных 32 раз, поэтому он не выводит начальные нули.
Этот алгоритм является частным случаем base2 основногоdo { digit = a % base; } while(a /= base);
,
Если вы собираетесь печатать цифры в порядке их создания, вы можете использовать
slt $t0, $a0, $zero # t0 = 0 or 1 = high bit of a0
sll $a0, $a0, 1
Это даст вам версию кода @JeffE без ответвлений. Но если вы заботитесь об эффективности, один системный вызов, который записывает целую строку, гораздо эффективнее, чем 32 системных вызова, чтобы записать 32 целых числа. (И, конечно, реальные ОС не имеют системных вызовов write-int; это вещь Mars/SPIM.)