[英]Shift right/left based on an even/odd popcount
My code should check if a variable has an odd or even number of bits turned on, and then shift right the amount of bits turned on if the amount is even or if it is odd shift left that many times.我的代码应该检查一个变量是否有奇数或偶数位打开,然后右移打开的位数,如果数量是偶数,或者如果它是奇数,则向左移动那么多次。
This is my code:这是我的代码:
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
When I run the code it doesn't shift and doesn't change the value of the variable.当我运行代码时,它不会移动,也不会更改变量的值。 I think it changes the value of the variable as index in the memory. Do you know how I can fix it?
我认为它将变量的值更改为 memory 中的索引。您知道我该如何解决吗?
When you run the.EXE that TASM creates for you, execution begins at the start label in the code segment and the CS segment register points at it.当您运行 TASM 为您创建的 .EXE 时,执行从代码段中的 label开始,CS 段寄存器指向它。 For your program to function correctly, similarly the DS segment register should point to the data segment of your program.
为了让你的程序正确到function,同样DS段寄存器应该指向你程序的数据段。 Sadly this is not so by default since DS is pointing at the Program Segment Prefix PSP.
遗憾的是,默认情况下并非如此,因为 DS 指向程序段前缀 PSP。 You have to setup DS yourself with the following code:
您必须使用以下代码自行设置 DS:
mov ax, @data
mov ds, ax
If you would have chosen for MODEL tiny
(instead of MODEL small
) the problem would not have shown itself since then all 4 segment registers would have been equal to each other.如果您选择
MODEL tiny
(而不是MODEL small
),那么问题就不会出现,因为所有 4 个段寄存器都将彼此相等。
xor cx,cx mov cx,8
Zeroing the register before loading the register is an unnecessary operation.在加载寄存器之前将寄存器清零是不必要的操作。
jnc nc inc al nc:
Although this construct is correct, incrementing AL if the carry is set can be much simpler via adc al, 0
.尽管这个构造是正确的,但如果设置了进位,则递增 AL 可以通过
adc al, 0
简单得多。 If the carry flag is clear nothing is added, and if the carry flag is set then 1 is added.如果进位标志清零,则不添加任何内容,如果进位标志已设置,则添加 1。
and al,00000001h cmp al,0h
Checking whether a value is even/odd is done by looking at the least significant bit which you are doing fine.检查一个值是否是偶数/奇数是通过查看你做得好的最低有效位来完成的。 Point is, you don't need that
cmp
afterwards since the and
instruction already defines the zero flag that you want to use for branching.重点是,您之后不需要
cmp
,因为and
指令已经定义了要用于分支的零标志。
Better still, if you used test
instead of and
, you would receive the same zero flag and not modify the register at all.更好的是,如果您使用
test
而不是and
,您将收到相同的零标志并且根本不会修改寄存器。 Writing test cl, 1
would save you from using the additional register.编写
test cl, 1
将使您免于使用额外的寄存器。
jz even_ jnz odd odd:
This jnz
conditional jump serves no purpose.这个
jnz
条件跳转没有任何用处。 If the condition is met the execution jumps to the odd label, and if the condition is not met the execution falls through into the odd label.如果条件满足则执行跳转到奇数label,如果条件不满足则执行跳转到奇数label 。
shr [t_copy],1
You can improve your solution by processing the data from a register instead of from the memory. You would not need the copy either.您可以通过处理来自寄存器而不是来自 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:
EDIT: This error described below doesn't actually exist, I misread the code.编辑:下面描述的这个错误实际上并不存在,我误读了代码。
You're close, but there's one small mistake here.你很接近,但这里有一个小错误。 When you do
and al,1
, you've actually altered al
and the original population count is now lost.当您执行
and al,1
时,您实际上已经更改了al
并且原始人口计数现在丢失了。 Fortunately, there's an easy way to fix this, use test al,1
instead.幸运的是,有一种简单的方法可以解决这个问题,使用
test al,1
代替。 This affects the zero flag the same way that and al,1
does, except al
remains the same it was before the test
.这会以
and al,1
相同的方式影响零标志,除了al
保持与test
之前相同。 So try this out and see if it helps:所以试试这个,看看它是否有帮助:
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.