Кто-нибудь знает, как умножить нечетное число N на языке ассемблера x86? - PullRequest
0 голосов
/ 31 декабря 2018

Кто-нибудь знает, как умножить нечетное число N на языке ассемблера x86, использующем мнемонику MUL Пример: SUM = 1 * 3 * 5 * 7 * .......... * n

1 Ответ

0 голосов
/ 31 декабря 2018

Чтобы умножить числа на инструкцию MUL, вы вводите одно число в eax (или rax или ax в зависимости от размера операнда), а другое число где-то еще (в любом другом регистре или в памяти), затемвыполните MUL и ожидайте результат в edx:eax (или rdx:rax или dx: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:
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...