MIPS 汇编将整数转换为二进制并读取 1 的数量?
我正在开发一个程序,它从用户那里获取一个整数,然后输出它的二进制等价物中有多少个 1。所以首先我认为我需要将其转换为二进制,然后使用循环检查所有 32 位以找出有多少个 1。
我已经浏览了几个小时并尝试不同的方法来首先将整数转换为二进制。最好的方法是什么?有没有办法直接读取二进制寄存器值,或者我需要先转换它?这是迄今为止我拥有的所有代码。
.data
EnterInteger: .asciiz "Enter an integer: "
.text
# Print the first message
li $v0, 4
la $a0, EnterInteger
syscall
# Prompt the user to enter the first integer
li $v0, 5
syscall
# Store the first integer in $t0
move $t0, $v0
这是我到目前为止的代码,但它不起作用。当我输入 4673 时,我应该得到“4”,但我只得到“1”
.data
Msg: .asciiz "Enter an integer: "
.text
# Print the first message
li $v0, 4
la $a0, Msg
syscall
# Prompt the user to enter the first integer
li $v0, 5
syscall
# Store the first integer in $t0
move $t0, $v0
addi $t3, $zero, 0
main:
bgt $t3, 32, exit
andi $t0, $v0, 1
bne $t0, $zero, count
count:
addi $t3, $t3, 1
addi, $t1, $zero, 1
# Shift to the next bit and then go back to main
srl $t0, $t0, 1
j main
exit:
# Tell the interpreter to get read to print an integer
li $v0, 1
add $a0, $zero, $t1
#Print the integer
syscall
# End the program
li $v0, 10
syscall
I am working on a program that takes an integer from the user and then outputs how many 1's there are in it's binary equivalent. So first I believe I need to convert it to binary and then use a loop and check all 32 bits to find how many 1's there are.
I have been browsing around for hours and trying different things to first convert the integer to binary. What's the best way to do this? Is there a way to to read a register value in binary directly, or do I need to convert it first? This is all the code I have so far.
.data
EnterInteger: .asciiz "Enter an integer: "
.text
# Print the first message
li $v0, 4
la $a0, EnterInteger
syscall
# Prompt the user to enter the first integer
li $v0, 5
syscall
# Store the first integer in $t0
move $t0, $v0
Here is the code I have so far but it's not working. When I input 4673 I should get "4", instead I only get "1"
.data
Msg: .asciiz "Enter an integer: "
.text
# Print the first message
li $v0, 4
la $a0, Msg
syscall
# Prompt the user to enter the first integer
li $v0, 5
syscall
# Store the first integer in $t0
move $t0, $v0
addi $t3, $zero, 0
main:
bgt $t3, 32, exit
andi $t0, $v0, 1
bne $t0, $zero, count
count:
addi $t3, $t3, 1
addi, $t1, $zero, 1
# Shift to the next bit and then go back to main
srl $t0, $t0, 1
j main
exit:
# Tell the interpreter to get read to print an integer
li $v0, 1
add $a0, $zero, $t1
#Print the integer
syscall
# End the program
li $v0, 10
syscall
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正如迈克尔评论的那样,寄存器中的整数已经是二进制的。寄存器是一组 32 位。
至关重要的是,寄存器上的操作,如
andi $t1, $v0, 1
和srl $v0, $v0, 1
以二进制方式工作。即and
得到的 0 或 1 是模 2 的值,右移 1 位除以 2。这是 MIPS 是二进制计算机的结果,就像您可能学习汇编的现实世界中的每一个 ISA 一样。具有
&
和>>
操作的高级语言(包括 C、Java 和 Python)也始终保证它们以二进制方式工作。 (在非二进制计算机(例如三进制)上,实现 x 和 y 的这些语义将涉及转换为基数 2 数字的数组并手动执行逻辑,然后转换回来。)如果您如果想要使用其他基数(例如基数 10),您需要进行实际除法 (MIPS
divu
) 或求余以删除或隔离最低的基数 10 数字。或者,如果基数是 2 的幂,例如基数 16,则移位 4 位,或与0x0f
进行 AND(取低 4 位,即 0b1111)。其他基数的输入/输出涉及将(二进制)整数从/转换为表示另一个基数的数字的 ASCII 数字字符串。 MARS/SPIM read_int 调用(
syscall
with $v0 = 5)会为您完成此操作,就像 C 库函数 scanf 或 printf 一样。要手动执行此操作,您可以执行诸如total = Total * 10 + digital
之类的操作,其中digit
类似于ascii_char - '0'
。或者对于输出,重复除以 10/模以 10 以获得以 10 为基数的数字,从最低的数字开始。有一些关于手动转换为字符串或从字符串转换的 MIPS 问答,但并不多,因为大多数使用 MIPS 的学生都使用 MARS 或 SPIM 及其玩具系统调用,这些调用通常由 C 库或手动完成。但是 IIRC 如果你搜索一下的话,还是有一些的。
ASCII 十进制或十六进制字符串是数字的序列化格式,而不是它们在计算机内部的存在方式(除了作为字符串,而不是整数)。
Popcount
一次循环一个位,提取并添加低位,是一种简单但通常效率低下的方法来计算设置位的数量。尽管如此,对于第一次尝试来说,简单还是有好处的。前面选择
andi
和srl
作为示例是一个提示。上显示了一些更快的 Bithacks如何计算 32 位整数中设置位的数量? 尽管对于 MIPS 来说这意味着生成大量单独的 32 位常量,每个常量需要 2 个指令。您可以执行两个 SWAR 扩展步骤,然后循环 4 位和组,作为中间基础。
以最快的速度计算整数上的位 1因为 GCC __builtin__popcount(int) 显示了一种计算
n &= n-1
到 清除最低设置位,如果只设置了几个位,则速度更快,即使它们不靠近收银机的底部。As Michael commented, integers in registers are already in binary. A register is a group of 32 bits.
Crucially, operations on registers like
andi $t1, $v0, 1
andsrl $v0, $v0, 1
work in binary. i.e. the resulting 0 or 1 fromand
is the value mod 2, and right-shift by 1 place divides by 2.This is a consequence of MIPS being a binary computer, like every over real-world ISA you might learn assembly for. Higher-level languages including C, Java, and Python that have
&
and>>
operations also always guarantee that they work in binary. (On a non-binary computer, e.g. ternary, implementing those semantics forx & y
would involve converting to an array of base-2 digits and doing the logic manually, then converting back.)If you want to work with other number bases, like base 10, you'd need to do actual division (MIPS
divu
) or remainder to remove or isolate the lowest base-10 digit. Or if the base is a power of 2, like base 16, then shift by 4 bits, or AND with0x0f
(take the low 4 bits, i.e. 0b1111).Input / output in other bases involves converting (binary) integers from / to strings of ASCII digits representing digits in another base. The MARS/SPIM read_int call (
syscall
with $v0 = 5) does that for you, like C library functions scanf or printf. To do it manually, you do stuff liketotal = total * 10 + digit
, wheredigit
is something likeascii_char - '0'
. Or for output, repeated division / modulo by 10 to get the base-10 digits, starting with the lowest.There are some MIPS Q&As about manually converting to/from strings, but not many because most students using MIPS are using MARS or SPIM with their toy system calls that do things normally done by a C library, or by hand. But IIRC there are some if you search.
ASCII decimal or hex strings are a serialization format for numbers, not how they exist inside computers (except as strings, not integers).
Popcount
Looping over the bits one at a time, extracting and adding the low bit, is a simple but often inefficient way to count the number of set bits. Still, simple is good for a first attempt; the choice of
andi
andsrl
as examples earlier is a hint.Some faster bithacks are shown on How to count the number of set bits in a 32-bit integer? although for MIPS that means generating lots of separate 32-bit constants which cost 2 instructions each. You could do two SWAR widening steps and then loop over groups of 4-bit sums, as a middle ground.
Count bits 1 on an integer as fast as GCC __builtin__popcount(int) shows a way where you count iterations of
n &= n-1
to clear the lowest set bit, which is faster if there are only a few bits set, even if they're not near the bottom of the register.