程序集 x86:如何计算 32 位长整数中的设置位数
Posted
技术标签:
【中文标题】程序集 x86:如何计算 32 位长整数中的设置位数【英文标题】:Assembly x86: How to count the number of set bits in a 32-bit long int 【发布时间】:2016-09-20 21:31:52 【问题描述】:我是一个新手,我正在尝试编写代码来计算 32 位整数中设置的位数。
我写了这个,但我得到了很多错误:
.586
.model flat,stdcall
.stack 4096
; Windows libraries
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
.DATA
data: .LONG 0x0F0F0101
count: .BYTE 0x00
.TEXT
_main: NOP
MOVB $0x00, %CL
MOVL data, %EAX
comp: CMPL $0x00, %EAX
JE end
SHRL %EAX
ADCB $0x0, %CL
JMP comp
end: MOVB %CL, count
RET
我有以下错误:
C:\Users\RaiN\Desktop\Test\test1.asm(20) : error A2034: must be in segment block
C:\Users\RaiN\Desktop\Test\test1.asm(25) : error A2108: use of register assumed to ERROR
C:\Users\RaiN\Desktop\Test\test1.asm(25) : error A2008: syntax error : .
C:\Users\RaiN\Desktop\Test\test1.asm(26) : error A2108: use of register assumed to ERROR
C:\Users\RaiN\Desktop\Test\test1.asm(26) : error A2008: syntax error : .
C:\Users\RaiN\Desktop\Test\test1.asm(28) : error A2008: syntax error : .
C:\Users\RaiN\Desktop\Test\test1.asm(29) : error A2108: use of register assumed to ERROR
C:\Users\RaiN\Desktop\Test\test1.asm(30) : error A2008: syntax error : $0x00
C:\Users\RaiN\Desktop\Test\test1.asm(31) : error A2008: syntax error : dato
C:\Users\RaiN\Desktop\Test\test1.asm(32) : error A2108: use of register assumed to ERROR
C:\Users\RaiN\Desktop\Test\test1.asm(32) : error A2008: syntax error : CMPL
C:\Users\RaiN\Desktop\Test\test1.asm(34) : error A2008: syntax error : !%
C:\Users\RaiN\Desktop\Test\test1.asm(35) : error A2008: syntax error : $0x0
C:\Users\RaiN\Desktop\Test\test1.asm(37) : error A2108: use of register assumed to ERROR
C:\Users\RaiN\Desktop\Test\test1.asm(37) : error A2008: syntax error : MOVB
C:\Users\RaiN\Desktop\Test\test1.asm(38) : error A2088: END directive required at end of file
C:\Users\RaiN\Desktop\Test\test1.asm(33) : error A2107: cannot have implicit far jump or call to near label
C:\Users\RaiN\Desktop\Test\test1.asm(36) : error A2107: cannot have implicit far jump or call to near label
我该如何解决这个问题?
非常感谢!!!
【问题讨论】:
作弊:用C编写,使用-S开关编译,然后查看生成的汇编程序! 你使用什么汇编程序?您的输出看起来非常像您尝试将 GNU 汇编器语法与 Microsoft 汇编器一起使用。这行不通。 我使用 WinAsm Studio。对于测试,我需要使用 Microsoft Assembler @Yimin Rong 作弊将使用 POPCNT 指令。 ;) 这并不是一个新问题。 Last time我写了这个,要求是使用内联汇编。但是把它变成“真正的”汇编器应该不会太难。也就是说,Bit Twiddling Hacks 中的 5's 和 3's 方法已知比 popcnt 指令更快(取决于特定 cpu 的实现),并且不需要 asm。 【参考方案1】:新代码是:
.text
.global main
main:
movq %rsp, %rbp #for correct debugging
# write your code here
.DATA
stringa: .ASCIZ "Questa è la stringa di caratteri ASCII che usiamo come esempio"
lettera: .BYTE 'e'
conteggio: .BYTE 0x00
.TEXT
_main: NOP
MOV $0x00, %CL
LEA stringa, %ESI
MOV lettera, %AL
comp: CMPB $0x00, (%ESI)
JE fine
CMP (%ESI), %AL
JNE poi
INC %CL
poi: INC %ESI
JMP comp
fine: MOV %Cl, conteggio
INT $0x27
RET
【讨论】:
既然您将此作为“答案”发布,这是否意味着问题已解决?还是这里还有问题?【参考方案2】:您要计算的内容称为Hamming Weight 您可以通过使用Logical shifts 和位掩码来实现此目的
这是一个简单的程序。我假设您使用的是 x86 程序集。
.386
.model flat,stdcall
option casemap:none
include kernel32.inc
includelib kernel32.lib
.code
start:
mov eax,1h ;your number in eax 100 is sample here
mov ecx,0h ;is the counter register
xor edx,edx ;is done to make edx 0, you can also do mov edx,0
notDoneWithNumber:
cmp eax,0
je done
mov edx,eax ;edx is here a compare register, not nice, but it works
shr eax,1 ;we push all the bits one place to the right, bits at position 1 will be "pushed out of the byteword"
and edx,1h ;make sure we only get, wether the last bit is set or not(thats called bitmaking)
cmp edx,0h
jz notDoneWithNumber ;if the found value is a zero we can skip the inc of the count register
inc ecx
jmp notDoneWithNumber
done: ;register ecx will now hold your hamming weight
end start
【讨论】:
感谢您的代码,但我必须改进我之前发布的解决方案...可以构建代码但我无法在 DOS 上执行它们。我不明白如何插入 I/O 功能和系统暂停。 哦,我以为你只需要一个有效的算法。说到DOS,恐怕我真的帮不了你,对不起。and edx, 1
已经根据结果设置了 ZF。你不需要cmp edx, 0
。您也可以通过使用shr eax / jnz notDone
作为循环底部的跳转来简化分支。即如果移位留下任何非零位,则重复循环。 (如果您在屏蔽它后无条件地 add ecx, edx
,而不是有条件地运行 inc
,则此方法效果最佳。与使用难以预测的分支跳过 inc
相比,仅添加零要有效得多。)
当然,与graphics.stanford.edu/~seander/… 或特别是 SSSE3 pshufb 相比,整个一次一位的算法非常慢(将输入切成 4 位半字节,并将其用作并行 LUT 索引)。或者,popcnt
指令当然是在支持它的 CPU 上一次处理一个整数的理想选择。
是的,你说得对,algortihm 非常慢。老实说,我对组装也很陌生,我想给出一个答案,这很容易理解并且结构清晰。以上是关于程序集 x86:如何计算 32 位长整数中的设置位数的主要内容,如果未能解决你的问题,请参考以下文章
用C语言实现大整数的运算?64bit整数可以用一个字符数组来保存它
用c语言实现大整形运算,64位长整型的加减法,输入限制为64位长度整数