我需要找出序列101b以16位数字显示多少次。但是我还需要找到距离较远的那些。
例如:在数字01010101中出现4次。因为3是它的一部分,而第四个(如果索引0是左位)由索引1、4和7的3位组成。
因为您可以将其关联为对称的101b序列。
这看起来确实很复杂,但是真的吗?我认为这可能有点棘手。
我设法找出了它定期显示的次数,例如示例编号中可以看到的3次。但是我不知道如何找到对称的。 编辑:我的老师的意思是轮换,我误解了这个问题,尽管感谢大家的帮助
mov cx,15
Check:
push dx;the number that I need to check
and dx,0111b
cmp dx,101b
jne Again
Again:
pop dx
shr dx,1
loop check
答案 0 :(得分:3)
类似这样的东西(未经测试):
mov dx, yourNumber
mov cx, 16
xor ax, ax
count:
mov bx, dx
and bx, 0b111
cmp bx, 0b101
jne nope
inc ax
nope:
rol dx, 1
dec cx
jnz count
因此,基本上,将寄存器旋转16次,并在每次迭代中进行测试,以通过用0b111屏蔽该寄存器的最低3位是否等于0b101。经过此计算后,结果在ax
中,而您测试的数字应仍在dx
答案 1 :(得分:2)
逻辑:
如果您将值与1010101010101010b(0xAA)进行异或运算,则任何0101b的4位组将变为1111b,而任何非4位的组均将变为1111b。
如果将1加到1111b,它将溢出,如果将1加到任何其他数字,它将不会溢出。您可以进行安排,以便当加法运算溢出时会导致进位标志被设置。
您可以使用adc
指令将进位标志添加到计数/总和中,以获取溢出的组的总数(最初为0101b的组数)。
这只会找到与组的开头对齐的0101b。要使其适用于“ 0101b任何位置”,您需要进行4次操作,并且每次之间都要旋转一次。
代码:
mov cx,4 ;Number of times to rotate/repeat
xor ax,ax ;ax = current sum of 4-bit groups that were 0101b = 0
.nextRotation:
mov bx,dx ;bx = the value
xor bx,0xAAAA ;dx = any 4-bit group that was 0101b is now 1111b
add bx,0x1000 ;Carry set if fourth/highest group was originally 0101
adc ax,0 ;Add carry to the sum
add bl,0x10 ;Carry set if second group was originally 0101b
adc ax,0 ;Add carry to the sum
shl bx,4
add bx,0x1000 ;Carry set if third group was originally 0101b
adc ax,0 ;Add carry to the sum
add bl,0x10 ;Carry set if first/lowest group of 4 bits was originally 0101b
adc ax,0 ;Add carry to the sum
;ax = number of 4-bit groups that were originally 0101b
rol dx,1
loop .nextRotation
答案 2 :(得分:2)
我不确定我是否了解第4个副本在哪里。我(和@sivizius)以为它是由7、0和1位(环绕到最高位)组成的。但这显然不是您想要的。
(同样,您的位编号没有意义。您说8位数字的最高位是位0,但是在注释中,您坚持要使用16位数字。所以{{ 1}}?)
无论如何,我想您想找到像1<<15
和1.0.1
这样的模式吗? (其中1..0..1
是模式中的可忽略占位符,可以匹配0或1)。
您可以在.
循环中查找具有类似内容的内容。
shr dx, 1
因此,与您为; dumb brute force method.
countloop: ; do {
mov ax, dx
and al, 111b ; select the bits that matter in 101
cmp al, 101b ; check that it's the pattern we want
; do count += ZF somehow
mov ax, dx
and al, 10101b ; select the bits that matter in 1.0.1
cmp al, 10001b ; check that it's the pattern we want
; do count += ZF somehow
mov ax, dx
and al, 1001001b ; select the bits that matter in 1..0..1
cmp al, 1000001b ; check that it's the pattern we want
; do count += ZF somehow
... for all the rest of the patterns.
; Wider patterns will need to use AX instead of AL
shr dx, 1
cmp dx, 101b
jae countloop ; }while(x >= 0b101);
;;; exit the loop as soon as DX contains no bits high enough to possibly match
;;; with a big loop, this is worth the extra cmp
;;; instead of just using jnz on the shr dx,1 result
所做的操作完全相同,只是您将“无关位”强制为零。
我没有想到比在循环体内单独检查所有可能的模式更好的方法了。
“计数+ = ZF”可以是(386)101b
/ setz al
,也可以是add cl, al
上的简单jnz
。 (我认为最大可能计数小于255,因此8位计数器就可以了。)
请注意,我没有将inc cx
用作循环计数器,而是在将所有位移出cx
后结束了循环
在没有SETCC的情况下无分支地执行此操作的另一种方法是
dx
答案 3 :(得分:1)
这看起来确实很复杂,但是真的吗?我认为这可能有点棘手。
是的,这确实很复杂。这是我的距离:
第1步:进行“行程编码”,忽略前导零和尾随零。示例(对于8位数字):
01010101 = 1(1s), 1(0s), 1(1s), 1(0s), 1(1s), 1(0s), 1(1s)
11001011 = 2(1s), 2(0s), 1(1s), 1(0s), 2(1s)
11111101 = 6(1s), 1(0s), 1(1s)
第2步:找到“ 1的游程,0的游程,1的游程”的排列,并将每个游程的计数相乘。示例(对于8位数字):
01010101 = 1(1s), 1(0s), 1(1s), 1(0s), 1(1s), 1(0s), 1(1s)
= 1 *1 *1
+ 1 *1 *1
+ 1 *1 *1
+ 1 *1 *1
+ 1 *1 *1
+ 1 *1 *1
+ 1 *1 *1
+ 1 *1 *1
+ 1 *1 *1
= 1+1+1+1+1+1+1+1 = 9
11001011 = 2(1s), 2(0s), 1(1s), 1(0s), 2(1s)
= 2 *2 *1
+ 2 *2 *2
+ 2 *1 *2
+ 1 *1 *2
= 4+8+4+2 = 18
11111101 = 6(1s), 1(0s), 1(1s)
= 6 *1 *1
= 6
在这一点上;很容易得出结论,有效的实现将涉及列表,并且如果使用递归,则可能会更容易实现(查找涉及列表中第一个游程的排列,然后丢弃第一个游程和第一个零游程的排列并递归)。