有谁知道如何使用Assembly x86语言对N个奇数进行复数?

时间:2018-12-31 07:27:02

标签: assembly x86

有人知道如何使用使用MUL助记符的Assembly x86语言对N个奇数进行倍数运算 例如:SUM = 1 * 3 * 5 * 7 * .......... * n

1 个答案:

答案 0 :(得分:1)

要将数字与MUL指令相乘,您可以将一个数字放在eax(或raxax中,具体取决于操作数的大小),另一个数字放在其他位置(在任何位置其他寄存器或内存中),然后执行MUL并期望结果在edx:eax(或rdx:raxdx:ax中)。

例如(32位,NASM语法,未经测试):

    mov eax,1      ;eax = 1
    mov ebx,2      ;ebx = 2
    mov ecx,5      ;ecx = 5
    mul ebx        ;edx:eax = 1 * 2
    mul ecx        ;edx:eax = (1 * 2) * 5

当然,当它们为常量时,您可以作弊,并在汇编代码时让汇编器执行。例如(32位,NASM语法,未经测试):

    mov eax,1*2*5*7

您还可以循环执行MUL。例如,如果值来自表或数组(32位,NASM语法,未经测试):

    mov eax,[table]
    mov esi,table+4
    mov ecx,31-1            ;31 items in table?
.next:
    mul dword [esi]         ;edx:eax = temp * table[i]
    add esi,4
    loop .next

但是,如果值之间存在某种关系,则不需要表。您的序列对我来说似乎是错误的,我怀疑您实际上是想使用“ 1*3*5*7 ... N”(并怀疑2是一个错字),而“ 1*3*5*7 ... N”是一个序列,可以不用一张桌子。例如(32位,NASM语法,未经测试):

    mov ecx,31          ;ecx = N = 31
    mov ebx,1           ;ebx = the value the result was multiplied with last
    mov eax,1           ;eax = the result
.next:
    lea ebx,[ebx+2]     ;ebx = the value to multiply with the result next
    mul ebx             ;edx:eax = new current result
    cmp ebx,ecx         ;Has N been reached?
    jb .next            ; no, keep going

请注意,您可以作弊以提高性能。例如,您可以执行以下操作(32位,NASM语法,未经测试):

    mov ecx,31          ;ecx = N = 31

    mov eax,1           ;eax = the current result
    mov ebx,1           ;ebx = the value the result was multiplied with last
    cmp ecx,9           ;Is the last value greater than 9?
    jle .next           ; no, don't cheat
    mov eax,1*3*5*7*9   ; yes, cheat by skipping the first 4 multiplications
    mov ebx,9           

.next:
    lea ebx,[ebx+2]     ;ebx = the value to multiply with the result next
    mul ebx             ;edx:eax = new current result
    cmp ebx,ecx         ;Has N been reached?
    jb .next            ; no, keep going

您可以使用预先计算的查找表进行更多欺骗。例如(32位,NASM语法,未经测试):

    mov ecx,31                      ;ecx = N = 31
    mov eax,[resultTable + ecx*4]   ;eax = result for N

您当然可以将表格的大小减半:

    mov ecx,31                      ;ecx = N = 31
    shr ecx,1                       ;ecx = N/2 = 15
    mov eax,[resultTable + ecx*4]   ;eax = result for N

您还可以在运行时构建表,将其有效地转变为一种缓存:

    mov ecx,31                         ;ecx = N = 31

    mov edx,ecx                        ;edx = N
    shr edx,1                          ;edx = N/2
    cmp dword [resultTable + edx*4],0  ;Is the result for this N already known?
    je .unknown                        ; no, have to calculate it
    mov eax,[resultTable + edx*4]      ; yes, just use the result from last time
    jmp .done

.unknown:
    mov eax,1                          ;eax = the current result
    mov ebx,1                          ;ebx = the value the result was multiplied with last
    cmp ecx,9                          ;Is the last value greater than 9?
    jle .next                          ; no, don't cheat
    mov eax,1*3*5*7*9                  ; yes, cheat by skipping the first 4 multiplications
    mov ebx,9           

.next:
    lea ebx,[ebx+2]                    ;ebx = the value to multiply with the result next
    mul ebx                            ;edx:eax = new current result
    cmp ebx,ecx                        ;Has N been reached?
    jb .next                           ; no, keep going

    shr ecx,1                          ;ecx = N/2
    mov [resultTable + edx*4],eax      ;Store the result for next time

.done:

但是,任何先前较低值N的结果都可以用作计算N较高值的结果的起点。这导致以下方法(32位,NASM语法,未经测试):

    mov ecx,31                    ;ecx = N = 31

    shr ecx,1                     ;ecx = N/2
    mov ebx,[highestN2]           ;ebx = the highest N/2 that's been done before
    cmp ecx,ebx                   ;Has this N/2 been done before?
    ja .unknown                   ; no
    mov eax,[resultTable + ecx*4] ; yes, use the previously calculated result
    jmp .done

.unknown:
    mov eax,[resultTable + ebx*4] ;eax = highest result previously calculated
.next:
    inc ebx                       ;ebx = next N/2 to use
    lea edx,[ebx*2+1]             ;edx = next N to use
    mul edx                       ;edx:eax = old result * N
    mov [resultTable + ebx*4],eax ;Store it for later
    cmp ebx,ecx                   ;Have we done enough?
    jb .next                      ; no, keep going
    mov [highestN2],ebx           ;Set the new highest N/2 calculated so far

.done: