Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 确定数组中负数和正数的数目_Assembly_X86_Nasm_32 Bit - Fatal编程技术网

Assembly 确定数组中负数和正数的数目

Assembly 确定数组中负数和正数的数目,assembly,x86,nasm,32-bit,Assembly,X86,Nasm,32 Bit,我需要在汇编程序中确定数组中负数和正数的数目。似乎汇编程序没有将它们识别为负数。我怎样才能解决这个问题?我这样定义数组: word_array db 3, -2, 11, -1, -2, -7, -5, -20 我有一个计算积极因素的函数: count_positives: mov dx, word [word_array + 2*ecx - 2] cmp edx, 0 JL skip inc ebx skip: loopnz count_positives 阅读评论 proc: mov

我需要在汇编程序中确定数组中负数和正数的数目。似乎汇编程序没有将它们识别为负数。我怎样才能解决这个问题?我这样定义数组:

word_array db 3, -2, 11, -1, -2, -7, -5, -20
我有一个计算积极因素的函数:

count_positives:
mov dx, word [word_array + 2*ecx - 2]
cmp edx, 0
JL skip
inc ebx
skip:
loopnz count_positives
阅读评论

proc:
  mov si, data ; si points to the data
  mov cx, [len] ; cx gets the length of the data
  shr cx,1 ; the length was in bytes, we want words
  mov bx, 0
  mov dx, cx

checkNext:
  mov ax, [si]
  text ax, ax ; alternatively: test ax, 8000h
  js isNegative
  inc bx ; counting positive numbers

isNegative:
  add si, 2 ; moving to next word
  loop checkNext ; decrease cx, jump if not 0

  sub dx, bx ; bx has the positive numbers, dx - the negative ones
  ret ; done

data dw -1,2,-3,4
len dw $-data

您正在加载DX的低16位,而高16位(包括符号位)保留了以前存在的垃圾。使用16位操作数大小进行比较


计算负数或非负数,然后从总计数中减去负数得到另一个

如果需要计数负数和正数,则需要两个计数器,以及一个
test
cmp
后接两个分支(以便零不会进入任何一个计数器)

根据Sten的回答改编,但有一些改进。请注意,
测试值,-1
相当于
cmp值,0

section .rodata

word_array dw -1,2,-3,4
len  equ $-word_array     ; length in bytes.  assembler constant, so we can mov reg, imm8/imm32   rather than loading it as data.

section .text
;; clobbers ESI, ECX.  Returns in EAX, EDX
proc:
  mov   esi, word_array  ; esi points to the array.  In MASM, use OFFSET word_array
  mov   ecx, len/2 - 1      ; [esi + ecx*2] points to the last element
  xor   edx, edx           ; non_neg_count = 0

countloop:
    ; cmp   [esi + ecx*2], 0   ; This can't macro-fuse (memory and immediate operand).  Also can't micro-fuse on SnB, because of a 2-reg addressing mode
  movsx   eax, word [esi + ecx*2]  ; use a 2-reg addressing mode to save loop overhead, since this there's no ALU execution port component to this insn.  It doesn't need to micro-fuse to be one uop
  test    eax, eax        ; can macro-fuse with js
  js isNegative
  inc   edx               ; counting non-negative numbers
isNegative:
  dec   ecx               ; can macro-fuse with jge, but probably won't unless alignment stops it from being decoded in the same cycle as the earlier test/js
  jge countloop       ; jge, not jnz, because we want ecx from [0 : len-1], rather than [1 : len]

; after the loop, ecx=-1, edx=non_neg_count
; neg_count = array_count - non_neg_count
  mov   eax, len/2
  sub   eax, edx        ;   eax =  neg_count

  ret    ; return values in eax, edx
在英特尔上,循环为4个UOP。(如果两个测试/分支对在同一个周期中命中解码器,则在Haswell之前的Sandybridge上更可能为5,因此只有一个宏融合。HSW可以在单个解码组中进行2个宏融合)

带有
设置bl/添加edx、ebx
的无分支版本可能运行良好

通过将eax归零,然后在循环中使用
scasw
ax
与[esi]进行比较,并将esi增加两倍,您可以稍微节省代码大小,但这通常不是一个好的性能选择


如果是正面与非负面问题: 如果需要,零计数是
n-eax-edx
,其中
n
是元素数

我在这里使用了不同的循环结构,只是为了多样性。循环应为7个UOP


在setcc写入bl之后读取ebx可以避免部分寄存器合并惩罚,因为我们在循环外对ebx进行异或归零。(保存/恢复EBX的上下文切换或中断将消除该性能优势,但对于短循环,可能仍然值得将xor归零从循环中提升出来。)

您使用
db
将word_数组声明为字节。也许您打算使用
dw
(对于16位字)。比如:
word\u数组dw3、-2、11、-1、-2、-7、-5、-20
。同样,由于您使用
dx
使用
edx
寄存器的低16位,因此我建议您更改为
cmp-dx,0
而不是
cmp-edx,0
,如果您不比较寄存器的右侧部分,您的负数可能会显示为正数。实际上,请使用
test-dx,dx
,或者完全跳过加载并使用
cmp字[word_数组+2*ecx-2],0
。不要使用
循环
指令,它很慢。使用
dec ecx/jnz
@PeterCordes:因为我只是在评论,所以我试图说明为什么现有代码可能无法产生正确的结果。我认为在将长度输入cx后,您缺少了
mov dx,cx
,因为您使用dx时没有初始化它。
section .rodata

word_array dw -1,2,0,-3,4
len  equ $-word_array     ; length in bytes.  assembler constant, so we can mov reg, imm8/imm32   rather than loading it as data.

section .text
;; clobbers ESI, EDI, EBP.  Returns in EAX, EDX
proc_pos_and_neg:
  mov   esi, word_array   ; esi points to the array.  In MASM, use OFFSET word_array
  xor   edx, edx           ; pos_count = 0
  xor   eax, eax           ; neg_count = 0

  lea   edi, [esi + len]  ; points one past the end of the array
  xor   ebx, ebx          ; clear upper portion, because setcc r32 isn't available, only setcc r8  :(

countloop:
  cmp    word [esi], 0
  setg   bl               ; 0 or 1, depending on  array[i] > 0
  lea    edx, [edx + ebx]  ; add without affecting flags
  setl   bl
  add    eax, ebx          ; can clobber flags now

  add    esi, 2            ; simple pointer-increment
  cmp    esi, edi
  jb  countloop            ; loop while our pointer is below the pointer to one-past-the-end

ret     ; neg_count in eax,  pos_count in edx