程序集中的平方根,如何移位和更改位

时间:2016-09-29 21:02:26

标签: assembly sqrt

我想在汇编中编写一个快速整数平方根算法,它采用无符号32位。我一直在阅读this,并得到了一个主意。这是我的伪代码:

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循环中执行操作?我从哪里开始?

1 个答案:

答案 0 :(得分:2)

(英特尔语法,自行转换为AT&amp; 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&amp; T这应该足以让你开始了)

正如玛格丽特所指出的,数字是数字,它是数值。所以0x8000已经在CPU线中编码,因为b15设置为1而其他位设置为0.当你想要将值从/转换为字符串时,所有的转换事件都会发生,但只要你用值计算它就会#39 ;在同一时间以各种形式存在于登记册中。这取决于你如何看待寄存器。在源代码中使用hexa / decimal / binary是这样的,编写数字的STRING表示,它由汇编程序转换为值本身。

二进制表示是特殊的,因为CPU可以处理特定的位(使用和/ xor /或,旋转,位测试/设置等),因为它具有类似于&#34; wire&#34;它是它的本地代表。就像人类在作弊时一样#34;在计算&#34; 10 * 3456&#34;时,在结尾处仅写入额外的0以获得结果,因为在十进制格式中,10 *是特殊的。对于CPU来说,位操作和2数学的所有功能都会发生同样的情况。但十进制技巧是不可能的,那些有CPU以适当的方式计算,实际乘以10。

无论如何,当你只有位数时,你想获得位掩码本身,比如如何从15获得0x8000:

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

因此,如果你坚持你的算法方法,你必须每次都重新计算for counter to bit mask(或者使用一些我不知道的位设置/重置指令,因为永远不需要他们。)

但是如果你研究我的代码,你会发现有直接的快捷方式来处理位掩码本身,而不计算第32位&#34;部分,使代码更短更快(虽然我可能通过推/弹杀死它,也许使用一个更多的寄存器,如esi来存储值会更好...然后再次演示堆栈是如何已使用,以及标志如何不受某些指令的影响,因此如果您小心不修改所需的标志,则可以推迟使用cmp结果。)