在 MIPS 汇编中,是否可以仅提取字符串的第 i 位和第 j 位,然后将这些单独的位放回其原始位置。
考虑:1100
提取:第 2位和第 3位并交换它们以获得结果1010
查看 AND 真值表结果 r = a AND b
ab r
00 0
01 0
10 0
11 1
看看这两个案例:
10 0
11 1
任何与 1 相加的东西就是它本身,现在这两种情况
00 0
01 0
任何与零相加的东西都是零。
用 4 位 abcd 提取 c 位,知道与与与零的这两个特征,与零与与与与任何事物与一。
abcd
AND 0010
=========
00c0
我们已经隔离了位 c,我们不在乎它是零还是一位,我们已经隔离了它。与零相加的位被强制为零,与 1 相加的位保持不变。
同样,将 abcd 与 0100 与运算得到 0b00 隔离位 b。
所以现在我们有两个中间结果 0b00 和 00c0。你想交换他们的位置,移位会做到这一点,这取决于你的指令集(我知道你说 mips 但请遵循)一些指令集可能会在进位位中旋转或移位,而一些指令集可能会旋转或移位零或算术移位 vs逻辑移位可能会复制最高有效位而不是移入零。因此,您需要检查您正在使用的指令集中有哪些移位可用,如果零解决方案中没有干净的移位,那么您需要添加更多操作来清除移位的任何副作用。在这种情况下,我们要将 b 位向右移动一位,将 c 位向左移动一位,因此您需要查找和使用的操作是
0b00 >> 1 = 00b0
00c0 << 1 = 0c00
现在这些位在正确的位位置我们有三件事
abcd
0c00
00b0
所以我们有两个真值表要检查,一个是上面的 AND 真值表,我们知道任何与一相加的东西,任何与零相加的东西。另一个是 OR 真值表
ab r
00 0
01 1
10 1
11 1
特别是前两个
00 0
01 1
任何与零相或的东西都是它自己。并注意后两个
10 1
11 1
任何与 1 的 OR 都是 1。
我们如何使用 AND 和 OR 来获取位?好吧,我们有两个选择,任何与 0 的 OR 都是它自己,另一个是任何与 1 的 AND 就是它自己。我们需要做的是操纵原始数字 abcd 并使其成为 a00d 或 a11d。这需要 AND 和 OR 表的另一半。与 0 相加的任何东西都是 0,与 1 相加的任何东西都是 1。所以要将 abcd 转换为 a00d,我们需要将其与 1001 相加
abcd
AND 1001
=========
a00d
a 和 d 加 1 本身就是 b 和 c 加 0 是 0
另一种选择是
abcd
OR 0110
=========
a11d
a 和 d 与 0 相或,因此它们不会改变 b 和 c 与 1 相或,因此这些位位置变为 1
最后一步是获取我们的其他中间值并将它们混合
a00d
OR 0c00
=========
ac0d
ac0d
OR 00b0
=========
acbd
另一个选择更复杂,如果我们只是这样做
a11d
AND 0c00
========
0c00
为了使用该身份,我们需要修改 0c00 并将其设为 1c11
0c00 OR 1011 = 1c11
1c11 AND a11d = ac1d
00b0 OR 1101 = 11b1
11b1 AND ac1d = acbd
简而言之,传统的解决方案是用 1 来隔离,用 0 来清除位位置,然后或在新值中:
abcd AND 0100 = 0b00
abcd AND 0010 = 00c0
0b00 >> 1 = 00b0
00c0 << 1 = 0c00
abcd AND 1001 = a00d
a00d OR 0c00 = ac0d
ac0d OR 00b0 = acbd
在 C 中,这将是这样的(这显示了您的临时变量)
//abcd is our original variable
tempb = abcd & 4;
tempc = abcd & 2;
tempb = tempb >> 1;
tempc = tempc << 1;
result = abcd & 9;
result = result | tempc;
result = result | tempb;
//and finished, result contains the...result.
您已经从 gusbro 那里得到了完整的答案,这是答案的一半,我假设使用逻辑运算的任务是问题的一半,问题的另一半是为相关指令集选择指令和寄存器(注意我是如何到目前为止已经解决了这个问题而无需指定指令集,因为此时我们可以使用任何指令集,每一步可能需要多条指令,但在这一点上它是通用的)。
请注意,这是一个四位解决方案,您可能会使用寄存器中超过四位的指令集,因此您需要知道在这些等式中的操作数左侧要添加哪些位,以免弄乱另一个位。
gusbro 使用的另一个我没有使用的身份是任何与自身异或的东西为零。他的两个异或运算可以用一个常数来实现,这取决于指令集可能需要多条指令或需要额外的内存周期。
这类工作的关键是理解这些逻辑身份并应用它们。当有人说(掩码和移位)掩码意味着与一个在您想要保留的位位置有一个的常量进行与运算时,然后移位将该位置于特定位置,例如,您想要采用 abcd 并将 c 位隔离在这样的结果是一个零或一个你会“掩盖和转移”
abcd AND 0010 = 00c0
00c0 >> 1 = 000c
和是掩码,移位是移位,如果 c 为 0,则结果为 0,如果 c 为 1,则结果为 1。
同样你可以
abcd >> 1 = 0abc
0abc AND 0001 = 000c
移位然后掩码。
你的家庭作业可以重新安排为
abcd >> 1 = 0abc
abcd << 1 = bcd0
0abc AND 0010 = 00b0
bcd0 AND 0100 = 0c00
abcd AND 1001 = a00d
00b0 OR 0c00 = 0cb0
a00d OR 0cb0 = acbd
你可以开始看到这个主题的其他变化。这些变化可以根据您所针对的指令集转化为优化。
您可以通过应用蒙版和班次来做到这一点。假设您的数据存储在寄存器中,要获得第 i 位,您将应用带有常数 2^i 的 AND 来清除除第 i 位之外的所有位。然后,您可以使用左移或右移轻松地将该位“移动”到其他位置。
现在,要交换 2 位将需要更多的摆弄。例如,您可以将这两个位提取到某些寄存器中,从原始寄存器中清除这些位,然后移动两个寄存器中的每一个以将它们定位在“交换”位置,最后对所有内容进行 OR。
例如:
li $t0, 12 # Our constant, 1100b, is stored in $t0
andi $t1, $t0, 2 # Mask the second bit and put it in $t1
andi $t2, $t0, 4 # Mask the third bit and put it in $t2
xor $t0, $t0, $t1 # Ensures the second bit $t0 is zero
xor $t0, $t0, $t2 # Ensures the third bit $t0 is zero
sll $t1, $t1, 1 # Moves $t1 one position to the left (second bit goes to third bit)
srl $t2, $t2, 1 # Moves $t2 one position to the right (third bit goes to second bit)
or $t1, $t1, $t2 # now we OR everything
or $t0, $t0, $t1 # to get the final result, in this case 1010b