Reputation: 63
I like to count the number of 1 to 0 transition in a 32 bit number. I found that the number of transitions from 0 to 1 in reverse order using shr
, but I don't get the required result. What should I do?
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
Output:
The number of transitions are : 2
whereas for 4660 (00000000000000000001001000110100
) the number of 1 to 0 transitions are 4.
Upvotes: 2
Views: 371
Reputation: 126223
The basic problem is that your code looks for a 0
followed by a 1
and if it doesn't match, it starts over again. So if it sees 00
it starts over looking for another 0
and if the next bit is 1
it starts over. So you miss transitions when they are preceeded by an even number of 0
s
Note also you say you want 1-to-0 transitions, but you're looking for 0-to-1 transitions, BUT you are looking right to left (lsb to msb) so that may be correct, depending on which bit order you want.
The obvious solution is to change the jnc .loop
to not start over, but only go back to the immediately preceeding dec ecx
, though you also need a cmp ecx,0; jl .exit
there.
Note also you could get rid of the need of ecx
and counting the number of bits by using the Z
flag which is set by the shr
instruction when the result (in eax
) is all 0 bits.
Taken together, that gives you something like:
.loop1: shr eax, 1
jc .loop1
.loop2: jz .exit
shr eax, 1
jnc .loop2
inc ebx
jmp .loop1
Upvotes: 4
Reputation: 29022
Trivia: I thought about this some month ago while trying to implement an aspect of a bitmap based memory manager.
The most efficient solution I found is the following (I adapted it to your sample code):
global main
main:
mov eax, [num]
; --- here starts the relevant code ---
mov ebx, eax
shl ebx, 1
not eax
and ebx, eax
popcnt ebx, ebx ; --- count the changed bits ---
; --- continue with your exit routine
.exit:
push ebx
push dword msg
call printf
add esp, 8
Notice that the calculation is achieved without loops. It is pure bit-fiddling with the set bits being counted at last by the POPCNT
instruction giving the desired result.
As an example - applied to the given value of 4660 this algorithm functions like this:
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.
Upvotes: 4