Assembly x86:在32位数字中计数从1到0的转换
我喜欢在32位数字中计算1到0的转换数。我使用Assembly x86:在32位数字中计数从1到0的转换,assembly,x86,nasm,Assembly,X86,Nasm,我喜欢在32位数字中计算1到0的转换数。我使用shr,发现从0到1的转换次数是以相反的顺序进行的,但我没有得到所需的结果。我该怎么办 extern printf SECTION .data msg: db "The number of transitions are : %d",10,0 inta1: dd 1234567 ; integer 1234567
shr
,发现从0到1的转换次数是以相反的顺序进行的,但我没有得到所需的结果。我该怎么办
extern printf
SECTION .data
msg: db "The number of transitions are : %d",10,0
inta1: dd 1234567 ; integer 1234567
num: dd 4660
SECTION .text
global main
main:
mov eax, [num]
mov ecx,32
mov ebx,0
.loop: dec ecx
cmp ecx,0
jl .exit
shr eax,1
jc .loop
dec ecx
shr eax, 1
jnc .loop
inc ebx
jmp .loop
.exit:
push ebx
push dword msg
call printf
add esp, 8
输出:
转换的数量为:2
而对于4660(
0000000000000001001000110100
)而言,1到0的转换次数是4。基本问题是,您的代码查找一个0
,后跟一个1
,如果不匹配,则重新开始。因此,如果它看到00
,它将重新开始寻找另一个0
,如果下一位是1
,它将重新开始。因此,当过渡前面有偶数个0
s时,您将错过过渡
另请注意,您说您想要1到0的转换,但您正在寻找0到1的转换,但您正在从右到左(lsb到msb)寻找,因此这可能是正确的,具体取决于您想要的位顺序
显而易见的解决方案是将jnc.loop
更改为不重新开始,而只返回到前面的dec ecx
,尽管您还需要cmp ecx,0;jl.从那里退出
注意:当结果(在eax
中)全部为0位时,您还可以通过使用Z
标志(由shr
指令设置)来摆脱ecx
和计数位数的需要
综上所述,这给了你一些类似的东西:
.loop1: shr eax, 1
jc .loop1
.loop2: jz .exit
shr eax, 1
jnc .loop2
inc ebx
jmp .loop1
琐事:几个月前,我在尝试实现基于位图的内存管理器的一个方面时想到了这一点 我发现的最有效的解决方案如下(我根据您的示例代码对其进行了调整): 请注意,计算是在没有循环的情况下完成的。这是一种纯粹的位摆弄,设置位最终由
POPCNT
指令进行计数,从而得到所需的结果
作为示例-应用于4660的给定值,该算法的功能如下:
00000000000000000001001000110100 --- MOV EBX, EAX
00000000000000000010010001101000 --- SHL EBX, 1
11111111111111111110110111001011 --- NOT EAX
00000000000000000010010001001000 --- AND EBX, EAX => 'and' the last two lines
=> POPCNT (count the bits of the last line) to get the result of 1 to 0 transitions.
你得到了什么值?转换的数量是:2最后一个
jmp.loop
应该是jmp.loop1
(+1)。你可以在底部用jnz
构造循环,然后用测试eax,eax/jmp loop\u入口点
输入它。这样,循环中就少了一条指令(没有无条件分支)。还请注意,您可以使用adc ebx,0将CF
添加到ebx
。或setc dl
/添加bl,dl
。无论哪种方式,您都可以避免移位位上的条件分支,因为这可能无法很好地预测。@SaumyaSahay,如果您必须在书本和popcnt
之间进行选择,您应该选择popcnt
(书本会过时)。@Saumya Sahay:是的,如果您手动实现一个例程来计算DWORD
中的位,则可以在不使用POPCNT
的情况下完成此操作。这项工作已经完成,非常烦人,但幸运的是,目前几乎所有的处理器都支持多年。它是被介绍的。依我看,对于处理器功能而言,这可能是一个不错的年龄。
00000000000000000001001000110100 --- MOV EBX, EAX
00000000000000000010010001101000 --- SHL EBX, 1
11111111111111111110110111001011 --- NOT EAX
00000000000000000010010001001000 --- AND EBX, EAX => 'and' the last two lines
=> POPCNT (count the bits of the last line) to get the result of 1 to 0 transitions.