我制作了一个程序,我尝试在其中显示用户输入的数字的二进制形式。但该程序没有正确地进行掩蔽。我该怎么做才能解决它?
$ 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
如果有人可以帮我解决这个问题,那将是一件很棒的事。
此致
答案 0 :(得分:3)
这是一个问题:
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:
答案 1 :(得分:0)
给定指向$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个系统调用更有效。 (当然,真正的操作系统没有写入int系统调用;这是火星/ SPIM的事情。)