首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >汇编:数组中整数的出现

汇编:数组中整数的出现
EN

Stack Overflow用户
提问于 2020-05-26 01:37:46
回答 2查看 2.8K关注 0票数 1

我正在masm程序集中编写一个程序来计数和返回数组中整数出现的次数。我目前有以下代码,允许我使用随机整数填充数组。我所挣扎的是如何实现一个计数器,该计数器将在数组中的索引处存储每一个整数的出现。例如,如果随机数组是3,4, 3,3,4,5,7,8,我希望我的计数数组容纳3,2,1,1,1,1,因为有(3,3,2,4,等等)。

我有固定在3/8的随机数的界,所以我知道它们将在这个范围内。我目前的想法是将每个数字与添加的3-8进行比较,并分别增加计数数组。我主要缺乏理解的是如何增加数组的特定索引。这段代码是我如何生成一个随机整数数组的,我知道如何开始计数整数的出现,但我不知道我是否在朝着正确的方向前进。有什么建议吗?

代码语言:javascript
复制
push ebp
mov  ebp, esp
mov  esi, [ebp + 16]    ; @ holds array to store count of integer occurances
mov  edi, [ebp + 12]  ; @ holds array to be populated with random ints
mov  ecx, [ebp + 8]   ; value of request in ecx


MakeArray:              
    mov     eax, UPPER          ; upper boundary for random num in array
    sub     eax, LOWER          ; lower boundary for random num in array
    inc     eax             
    call    RandomRange
    add     eax, LOWER
    cmp     eax, 3          ; Where I start to compare the random numbers added
    je      inc_3           ; current thought is it cmp to each num 3-8
    mov     [edi], eax  ; put random number in array
    add     edi, 4      ; holds address of current element, moves to next element
    loop    fillArrLoop

inc_3:          ; if random num == 3
    inc     esi         ; holds address of count_array, increments count_array[0] to 1?
    mov     [edi], eax  ; put random number in array to be displayed
    add     edi, 4      ; holds address of current element, moves to next element
    loop    MakeArray
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-05-26 04:04:05

,我目前的想法是将每个数字与添加的3-8进行比较。

不,你把事情搞得太复杂了。您不希望对j (计数索引)进行线性搜索,因此arr[i] == j只需使用j = arr[i]

做直方图的标准方法是++counts[ arr[i] ]. 在您的示例中,您知道可能的值是3.8,因此您可以使用arr[i] - 3将数组值映射到计数桶,因此您将对counts[0..5]进行操作。给定寄存器中的元素值,具有缩放索引寻址模式的内存目的地add 指令可以在一个x86指令中完成这一任务。

如果可能的值不是连续的,则通常使用哈希表来映射值以计数桶。您可以把这个简单的例子看作是允许一个琐碎的散列函数。

由于您正在生成随机数来填充arr[i]和直方图,您可以组合这两个任务,而不是减去3,只是还没有添加它。

代码语言:javascript
复制
; inputs: unsigned len, int *values, int *counts
; outputs: values[0..len-1] filled with random numbers, counts[] incremented
; clobbers: EAX, ECX, EDX  (not the other registers)
fill_array_and_counts:
    push ebp
    mov  ebp, esp

    push esi        ; Save/restore the caller's ESI.
 ;; Irvine32 functions like RandomRange are special and don't clobber EAX, ECX, or EDX except as return values,
 ;; so we can use EDX and ECX even in a loop that makes a function call.

    mov  edi, [ebp + 16]    ; int *counts  ; assumed already zeroed?
    mov  edx, [ebp + 12]    ; int *values  ; output pointers
    mov  ecx, [ebp + 8]     ; size_t length

    MakeArray:                       ; do{
        mov     eax, UPPER - LOWER + 1   ; size of random range, calculated at assemble time
        call    RandomRange                  ; eax = 0 .. eax-1
        add     dword ptr [edi + eax*4], 1   ; ++counts[ randval ]

        add     eax, LOWER               ; map 0..n to LOWER..UPPER
        mov     [edx], eax               ; *values = randval+3
        add     edx, 4                   ; values++

        dec     ecx
        jnz     MakeArray            ; }while(--ecx);

    pop   edi                  ; restore call-preserved regs
    pop   ebp                  ; including tearing down the stack frame
    ret

如果调用方没有为您设置counts数组的零点,那么您应该自己完成这一操作,也许使用rep stosd将EAX=0作为ECX元素的memset,然后从堆栈args中重新加载EDI和ECX。

我假设上下是集合时间常数,比如UPPER = 8LOWER equ 3,因为它们都是大写名称,而它们不是函数args。如果是这样的话,那么没有必要在运行时进行计算,只需让汇编程序为您计算UPPER - LOWER + 1

我避免了loop指令because it's slow,也没有做其他简单指令不能做的事情。

只有几个桶的直方图的一个标准性能技巧是有多个计数数组并展开它们:Methods to vectorise histogram in SIMD?。这隐藏了存储/重新加载的延迟,当同一计数器需要在一行中增加几次时。但是,随机值通常会避免相同值的长时间运行,因此避免了最坏的性能。

对于大型数组,可能会从AVX2获得一些好处,因为只有6个可能的桶:Micro Optimization of a 4-bucket histogram of a large array or list。(如果愿意,可以用AVX2 xorshift128+ PRNG在SIMD向量中生成随机数。)

票数 0
EN

Stack Overflow用户

发布于 2020-05-26 01:51:52

如果您的范围是固定的(3-8),则有一个固定长度的数组,可以保存计数:

代码语言:javascript
复制
(index0:Count of 3),(index1:Count of 4)..(index5:Count of 8s)

一旦从随机数组中获得了一个元素,您只需接受该元素并通过一个开关:

代码语言:javascript
复制
cmp 3, [element]
jne compare4
mov ebx, [countsArrayAddress]     ; Can replace [countsArrayAddress] with  [ebp + 16]
add ebx, 0                        ; First index, can comment out this line
mov ecx, [ebx]
add ecx, 1                        ; Increment count
mov [ebx], ecx                    ; Count at the zeroth offset is now incremented
compare4:
cmp 4, [element]
jne compare5
mov ebx, [countsArrayAddress]
add ebx, 4                         ; Second index (1*4)
mov ecx, [ebx]
add ecx, 1
mov [ebx], ecx
...

你是这个意思吗?我来自于使用fasm语法,但它看起来非常相似。上面的块有一点未优化,但请考虑这说明了如何构建计数数组。数组有一个固定长度,必须在堆栈上(子rsp为正确的数量)或堆上,即使用heapalloc/malloc调用来分配。(编辑,见您正在使用32位寄存器)

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62013305

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档