Чтобы умножить числа на инструкцию 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: