assembly 如何检查两个数字在汇编中是否有颠倒的位?

bxjv4tth  于 2022-12-13  发布在  其他
关注(0)|答案(2)|浏览(162)

我的代码应该得到2个相同长度(k)的arr,并检查有多少对数字具有相同的索引(1在arr1中,另一个在arr2中),并且是相反的,这意味着1中的第一位应该是另一个中的最后一位,第二个到第一个将是第二个到第一个,然后继续...
这是我的代码:

IDEAL
MODEL small
STACK 100h
DATASEG

k dw 2                       ;length of arr1 and arr2
ARR1 dw 2 dup (?)
ARR2 dw 2 dup (?)
CODESEG
start:  
    mov ax,@data
    mov ds,ax
    
    lea si,[ARR1]
    lea di,[ARR2]
    mov cx,k                 ; cx=length of arr
    xor dx,dx
    mov [ARR1],1000000000000001b
    mov [ARR2],1000000000000001b
    mov [ARR1+1],0033h
    mov [ARR2+1],0033h
        xor dx,dx
        L1:                                      ; loops through every index in both arr1, and arr2
            mov bx,k
            sub bx,cx
            push cx
            mov cx,16
            L2:
                xor ax,ax
                shr [si+bx],1
                jnc nc1
                inc al
                nc1:
                clc
                shl [di+bx],1
                jnc nc2
                inc ah
                nc2:
                clc
                cmp al,ah
                jne end_loop2
                
                dec cx
                jnz L2
                
            inc dx
            end_loop2:
            pop cx
            
            dec cx
            jnz L1


exit:
    mov ax, 4c00h
    int 21h
END start

我的调试器没有给予我任何错误,但当我运行代码时,它不工作,当我左移arr 2中的数字时,它没有改变CF,尽管它应该改变。
你知道为什么会这样吗?

hfwmuf9z

hfwmuf9z1#

mov [ARR1],1000000000000001b
mov [ARR2],1000000000000001b
mov [ARR1+1],0033h
mov [ARR2+1],0033h        ; ARR1/ARR2 contain 1, 51, 0, ?

你的程序定义了2个数组,每个数组有2个字长的元素。因为一个字在内存中占用2个字节,所以给第2个元素赋值必须使用+2的偏移量。给第3个元素赋值必须使用+4的偏移量,依此类推。
第一次
内循环(L2)正在处理字但外循环(L1)在第一次外部迭代时CX是2,因此BX = k-CX变为0,并且在第二次外部迭代CX=1时,BX = k -CX变为1,然后开始处理由第1个数组元素的高字节和第2个数组元素的低字节组成的字元素中的值。
好消息是,你不需要用那种复杂的方式(使用BX)来遍历这些数组,只需在外部循环的每次迭代中将SI和DI加2即可。
你的程序包含了一些冗余的指令,比如xor dx, dx,还有一些不必要的指令,比如clc。为了清楚起见,你应该删除这些无用的指令行。
检查有多少对数字具有相同的索引(1在arr 1中,另一对在arr 2中)并且是相反的
知道数组中每2个元素,这意味着程序的最终结果必须是[0,2]范围内的数字。
如果没有前面提到的错误,你的程序会运行得很好,除了一个消除数组的解决方案不是我会选择的。
下面是我的实现。仔细阅读尾部评论!

lea  si, [ARR1]      ; SI is address of 1st array
    mov  [si], 8001h     ; Assign 1st element
    mov  [si+2], 0033h   ; Assign 2nd element
    lea  di, [ARR2]      ; DI is address of 2nd array
    mov  [di], 8001h     ; Assign 1st element
    mov  [di+2], 0033h   ; Assign 2nd element

    mov  bp, k           ; Number of array elements
    xor  dx, dx          ; Final result (will be 1 based on the fixed data)
L1:
    mov  cx, [di]        ; CX is current element from 2nd array
    mov  bx, [si]        ; BX is current element from 1st array
    xor  ax, ax          ; AL is status byte, AH is a convenient 0
L2:
    shr  bx, 1           ; The bit that comes out of BX
    adc  al, ah          ;   is added to AL (that was zeroed beforehand)
    shl  cx, 1           ; The bit that comes out of CX (at the opposite side)
    sbb  al, ah          ;   is subtracted from AL
    jnz  NOK             ; If both bits matched then AL would still be zero
    test bx, bx          ; Has BX more ON bits ?
    jnz  L2              ; Yes

                         ; Early exiting if BX has no more ON bits
                         ; If, at the same time, CX too has no more ON bits
                         ; then an OK pair was found

    test cx, cx
    jnz  NOK
OK:
    inc  dx              ; Found an OK pair
NOK:
    add  si, 2           ; Next array element is 2 bytes higher in memory
    add  di, 2
    dec  bp              ; Repeat for every element in the array(s)
    jnz  L1
bnl4lu3b

bnl4lu3b2#

如果串行实现,则内部循环可被压缩为至少

again:
    add ax,ax  ; shift ax, while moving MSB to carry
    sbb bx, 0  ; subtract carry (i.e 0 or 1) from bx
               ; here the LSB of bx will be 0 afterwards,
               ; iff the top bit of ax == lsb of bx
               ; in this case the top 15 bits of bx will
               ; be preserved for further iterations
    shr bx, 1  ; now we shift out the LSB, setting CF on failure
    jc not_ok 
    jnz again  ; there are further bits on bx to check
               ;
    test ax,ax ; we need to check that ax == 0, when bx == 0
    jnz not_ok ;
ok:            ; there was full match

我认为在AX上单独提前退出没有多大意义,但是可以对输入进行排序,放置BX <= AX,这样BX将更快地用完位。
使用奇偶校验标志,如how-to-exchange-between-2-bits-in-a-1-byte-number中所示,可以极大地简化内部循环:

ok = (bitreverse(al) == bh) && (bitreverse(bl) == ah)

通过以下实现,除了ax = input0, bx = input1,甚至不需要任何其他寄存器。

test al, 0x81
    jpe 1f          // parity even IFF al == 0x81 OR al == 0
    xor  al, 0x81   // toggle bits 0x80 and 0x01, if there was only 1 bit
1:  test al, 0x42
    jpe 2f
2:  xor  al, 0x42
    test al, 0x24
    jpe 3f
3:  xor  al, 0x24
    test al, 0x18
    jpe 4f
    xor  al, 0x18
4:  cmp  al, bh
    jnz  NOT_OK
    
// and same for the pair bl, ah

相关问题