[英]Shift right/left based on an even/odd popcount
我的代碼應該檢查一個變量是否有奇數或偶數位打開,然后右移打開的位數,如果數量是偶數,或者如果它是奇數,則向左移動那么多次。
這是我的代碼:
IDEAL
MODEL small
STACK 100h
DATASEG
TAV db 00001001b
t_copy db 00001001b
CODESEG
start:
xor cx,cx
mov cx,8
xor al,al
L1:
shr [t_copy],1
jnc nc
inc al
nc:
dec cx
jnz L1
mov cl,al
and al,00000001h
cmp al,0h
jz even_
jnz odd
odd:
shl [TAV],cl
jmp exit
even_:
shr [TAV],cl
exit:
mov ax, 4c00h
int 21h
END start
當我運行代碼時,它不會移動,也不會更改變量的值。 我認為它將變量的值更改為 memory 中的索引。您知道我該如何解決嗎?
當您運行 TASM 為您創建的 .EXE 時,執行從代碼段中的 label開始,CS 段寄存器指向它。 為了讓你的程序正確到function,同樣DS段寄存器應該指向你程序的數據段。 遺憾的是,默認情況下並非如此,因為 DS 指向程序段前綴 PSP。 您必須使用以下代碼自行設置 DS:
mov ax, @data
mov ds, ax
如果您選擇MODEL tiny
(而不是MODEL small
),那么問題就不會出現,因為所有 4 個段寄存器都將彼此相等。
xor cx,cx mov cx,8
在加載寄存器之前將寄存器清零是不必要的操作。
jnc nc inc al nc:
盡管這個構造是正確的,但如果設置了進位,則遞增 AL 可以通過adc al, 0
簡單得多。 如果進位標志清零,則不添加任何內容,如果進位標志已設置,則添加 1。
and al,00000001h cmp al,0h
檢查一個值是否是偶數/奇數是通過查看你做得好的最低有效位來完成的。 重點是,您之后不需要cmp
,因為and
指令已經定義了要用於分支的零標志。
更好的是,如果您使用test
而不是and
,您將收到相同的零標志並且根本不會修改寄存器。 編寫test cl, 1
將使您免於使用額外的寄存器。
jz even_ jnz odd odd:
這個jnz
條件跳轉沒有任何用處。 如果條件滿足則執行跳轉到奇數label,如果條件不滿足則執行跳轉到奇數label 。
shr [t_copy],1
您可以通過處理來自寄存器而不是來自 memory 的數據來改進您的解決方案。您也不需要副本。
CODESEG
start:
mov ax, @data
mov ds, ax
xor cx, cx ; CL is popcount, CH is a convenient 0
mov al, [TAV]
L1:
shr al, 1 ; The bit that comes out of AL
adc cl, ch ; is added to CL
test al, al ; If AL got empty, further adding would be useless
jnz L1
test cl, 1 ; Non-destructive checking of the least significant bit
jnz ON
shr [TAV], cl ; Shift right if popcount is EVEN
jmp exit
ON:
shl [TAV], cl ; Shift left if popcount is ODD
exit:
編輯:下面描述的這個錯誤實際上並不存在,我誤讀了代碼。
你很接近,但這里有一個小錯誤。 當您執行and al,1
時,您實際上已經更改了al
並且原始人口計數現在丟失了。 幸運的是,有一種簡單的方法可以解決這個問題,使用test al,1
代替。 這會以and al,1
相同的方式影響零標志,除了al
保持與test
之前相同。 所以試試這個,看看它是否有幫助:
mov cl,al
test al,1
;cmp al,0h ;this line is redundant.
jz even_
;jnz odd ;this line is redundant.
odd:
shl [TAV],cl
jmp exit
even_:
shr [TAV],cl
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.