问题
I have a 32 Bit number and want to count know how many bits are 1.
I'm thinking of this pseudocode:
mov eax, [number]
while(eax != 0)
{
div eax, 2
if(edx == 1)
{
ecx++;
}
shr eax, 1
}
Is there a more efficient way?
I'm using NASM on a x86 processor.
(I'm just beginning with assembler, so please do not tell me to use code from extern libraries, because I do not even know how to include them ;) )
(I just found How to count the number of set bits in a 32-bit integer? which also contains my solution. There are other solutions posted, but unfortunatly I can't seem to figure out, how I would write them in assembler)
回答1:
The most efficient way (in terms of execution time, anyway) is to have a lookup table. Obviously you're not going to have a 4-billion entry table, but you could break the 32 bits down into 8-bit chunks and only need a 256-entry table, or further down into 4-bit chunks and only need 16 entries. Good luck!
回答2:
In processors that have SSE4 support, you have the POPCNT instruction that does this for you.
The most naive algorithm is actually faster than what you thought up (DIV instructions are really slow).
mov eax, [number]
xor ecx,ecx
loop_start:
test eax,1
jnz next
inc ecx
next:
shr eax, 1
mov eax,ecx
Regarding your comment about previous SO answers, I'm going to take an example answer from there and walk you through how I'll convert it.
long count_bits(long n) {
unsigned int c; // c accumulates the total bits set in v
for (c = 0; n; c++)
n &= n - 1; // clear the least significant bit set
return c;
}
(I'm going to assume you know how to define a function and fun stuff like that). What is needed is a very simple loop, a counter variable (traditionally, ecx is both the index and a counter), and bit testing instructions.
mov edx,n
xor ecx,ecx
loop_start:
test edx,edx
jz end
mov ebx,edx
dec ebx
and edx,ebx
inc ecx
jmp loop_start
end:
mov eax,ecx
ret
Implementing something like the Hamming Weight algorithm in assembly isn't complicated, but is just complicated enough that you'd rather not do it as an initial homework problem.
回答3:
My x86 assembler is a bit rusty, but this comes to mind:
clc ; clear carry
xor ecx, ecx ; clear ecx
shl eax, 1 ; shift off one bit into carry
adc ecx, 0 ; add carry flag to ecx
; ... repeat the last two opcodes 31 more times
ecx
contains your bit count.
x86 shift instructions set CF
to the last bit shifted out, where adc ecx, 0 reads it.
回答4:
mov eax,[c]
xor ebx,ebx
SSS: shr eax,1 ; after shift, if eax=0 ZF flag=1
jz XXX ; end (no more bit on eax)
adc bl
jmp SSS
XXX: adc bl
movb [Nbit],bl
回答5:
This program gives you the number of 1's in a 32 bit number. Try out :)
extern printf
SECTION .data
msg: db "The number of 1 bits are: %d",10,0
inta1: dd 1234567
num: dd 2147483647
SECTION .text
global main
main:
mov eax, [num]
mov ecx,32
mov edx,0
.loop: dec ecx
cmp ecx,0
jl .exit
shr eax,1
jnc .loop
inc edx
jmp .loop
.exit:
push edx
push dword msg
call printf
add esp, 8
回答6:
Using bsf (Bit Scan Forward) is probably a bit more efficient than plain shifting.
xor edx,edx
mov eax,num
bsf ecx,eax
je end_bit_count
; align?
loop_bit_count:
inc ecx
inc edx
shr eax,cl
bsf ecx,eax
jne loop_bit_count
end_bit_count:
回答7:
The best way:
tabx:array [0..255] of byte = //number of bit for each byte (COPY THIS TABLE)
(0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8);
In MASM:
asm
mov eax,number //32 bit
movzx ecx,tabx[al] //for clear ecx except cl
addb cl,tabx[ah] //add ah to cl
shr eax,16 //put left part in ah-al
addb cl,tabx[al]
addb cl,tabx[ah]
mov result,ecx
来源:https://stackoverflow.com/questions/2931497/nasm-count-how-many-bits-in-a-32-bit-number-are-set-to-1