装配中的平方根,如何移位和更改位
我想在汇编中编写一个快速整数平方根算法,它采用无符号的32位。 我一直在阅读这个,并有一个想法。 这是我的伪代码:
res <- 0
for i from 15 downto 0 do:
change the ith bit of result to 1
if res^2 > x then:
change the ith bit of res back to 0
return res
到目前为止,我已经完成了:
sqrt:
movl $0, %eax
movl $15, %edx
jmp .L8
.L9
.L8
cmpq cmpq $0, %edx
jge .L9
我被困在for循环操作中,改变第i位并移位。 我也不想使用分区或sqrt指令。 我知道我应该使用shr
,但我不知道从哪里开始或如何去做。 我如何在for循环中执行操作? 我从哪说起呢?
(英特尔语法,自行转换为AT&T)
mov ebx,<number> ; *number* to find sqrt of
mov ecx,0x8000 ; bitmask (starting with b15 bit set)
;^^^ 0x8000 = decimal 32768 = binary 1000 0000 0000 0000
xor eax,eax ; result <- 0
sqrt_loop:
xor eax,ecx ; set bit in eax
push eax ; store result (will be destroyed by mul)
mul eax ; edx:eax <- eax*eax (ignoring edx next)
cmp eax,ebx ; compare with *number*
pop eax ; restore result
jbe keep_bit ; res^2 <= *number* -> bit stays set
xor eax,ecx ; unset bit in eax
keep_bit:
shr ecx,1 ; next bit
jnz sqrt_loop ; loop till all bits are tried
(我没有尝试过+调试它,所以可能会有一些错误,但是我认为与你的伪算法一起,并且通过调试将它重写到AT&T应该足以让你开始)
正如玛格丽特指出的那样,数字就是数字,这就是价值。 因此,0x8000已经在CPU线路中编码,因为b15设置为1,其他位设置为0.所有转换的内容都是在将值从/转换为字符串时发生的,但只要您使用值进行计算,它就在同时注册所有形式的注册。 这取决于你如何看待注册表。 在源代码中使用hexa / decimal / binary是写入数字的STRING表示,由汇编器将其转换为值本身。
二进制表示是特殊的,因为CPU可以处理特定位(具有和/或/或,旋转,位测试/设置等),因为它具有“线”的那些值并且它是本地表示。 这就像人在计算“10 * 3456”时“欺骗”一样,在末尾只写了0来得到结果,因为在十进制格式中,10 *是特殊的。 对于CPU而言,位操作和2数学的所有功能都是一样的。 但十进制技巧是不可能的,那些CPU有正确的计算方式,乘以10为真实。
无论如何,当你只有位数,并且你想获得位掩码本身时,比如如何从15:
mov ecx,15 ; i-th bit
mov eax,1 ; set b0 (lowest bit)
shl eax,cl ; shift all bits (all zeroed + b0 set) cl-many times left
; eax now contains 0x8000 = b15 set, other bits zeroed
所以如果你坚持用你的算法,你必须每次都重新计算计数器到位掩码(或者使用一些我不知道从头开始的设置/重置指令,因为几乎从不需要它们)。
但是,如果你研究我的代码,你会看到有直接的捷径去处理位掩码本身,而没有计算“第i位”部分,使代码更短更快(尽管我可能通过push / pop来杀死它,也许使用一些像esi
这样的寄存器来存储值会更好......然后这再次演示了如何使用堆栈以及标记如何不受特定指令的影响,因此如果你使用cmp
结果,你可以以推迟的方式使用cmp
结果注意不要修改所需的标志)。