Для простоты я получил свой первый проект MASM32, и он выглядит следующим образом: «Напишите программу на ассемблере для генерации и отображения первых 24 чисел Фибоначчи, начиная с 1 и заканчивая 46368». Поскольку это мой первый проект, я, честно говоря, понятия не имею, как начать или написать этот код. Любая помощь приветствуется. Большое спасибо.
Язык ассемблера и числа Фибоначчи
- Что вы пытались до сих пор? 29.03.2016
- Вы начинаете с написания программы, которая отображает число. 29.03.2016
- Вы можете пойти очень простым путем и просто создать данные, содержащие первые 24 числа, и распечатать их. ;) 29.03.2016
- Попробуйте сначала написать программу на другом языке, например C, а затем посмотрите, сможете ли вы снова написать ее на ассемблере. 29.03.2016
- @DavidHoelzer: в этом случае в формулировке задания говорится, что числа должны быть сгенерированы программой сборки. 29.03.2016
- Всегда есть старый способ написать блок-схему, основанную на алгоритмическом подходе. 29.03.2016
- С чего начать: посмотрите на вывод компилятора и, если вы все еще застряли, найдите
[x86] fibonacci
здесь. в стекопереполнении. Для расчетной части я бы рекомендовал мой ответ на другой вопрос Фибоначчи для эффективного цикла. Все начинается с простого, затем становится сложным, так что просто прекратите читать, как только вы запутаетесь. Он хранится в массиве, но вы можете изменить это наprintf
вызовов. 29.03.2016 - Этот дубликат также хочет напечатать серию в 32-битном формате x86 с вызовом
_printf
. Или, может быть, просто печатает последнее значение, но демонстрирует использование printf. Однако код ужасно неэффективен, поскольку все временные файлы хранятся в памяти. 29.03.2016
Ответы:
fibunacci, как правило, решается рекурсивно, в то время как решение с помощью простого цикла не менее просто
вы уже знаете, что ваш массив будет состоять из 24 слов,
и на первый взгляд кажется, что ваш цикл будет состоять из 24 шагов.
в то время как f(1) и f(2) уже установлены, и вам нужны как минимум эти 2 элемента для работы, количество необходимых элементов 22, а не 24 ... так что давайте начнем с того, что мы уже знаем
fib dw 24 dup (0) ; i don't know masm too well, this should create 24 words
mov word ptr[fib ],1 ; f(1)
mov word ptr[fib+2],1 ; f(2)
mov cx,22 ; this will be the loop counter
l1:
; add up the last 2 elements
dec cx
jnz l1
хорошо, пока все хорошо. "Добавить последние 2 элемента" НАМАШИВАЕТСЯ для 2 регистров, где хранятся последние два элемента, чтобы не всегда приходилось читать их из памяти. поэтому давайте использовать AX и BX, AX для элемента n-2, BX для n-1. мы складываем их и сохраняем результат в «следующем» элементе массива.
для массивов отлично использовать si и di, пока мы пишем, DI (целевой индекс) — наш лучший выбор
fib dw 24 dup (0) ; i don't know masm too well, this should create 24 words
calculate:
cld
mov word ptr[fib ],1 ; f(1)
mov ax, 1
mov word ptr[fib+2],1 ; f(2)
mov bx, 1
mov di, offset fib+4 ; does this work in MASM ?
mov cx,22 ; this will be the loop counter
l1:
add ax,bx
stosw ; write new element to array
; note: this is equivalent to mov [di], AX and add si,2
dec cx
jnz l1
после сложения нам нужно загрузить ax и bx с правильными значениями, ax с f(n) и bx с f(n-1)... мы могли бы сделать это с чтением из массива, но если мы посмотрим поближе , AX — это f(n) (последний вычисленный элемент) для этого цикла, который будет f(n-1) для следующего цикла, а BX — это f(n-1) , который будет f(n-2) для следующего цикла. следующая петля. Так что все, что нам нужно сделать, это просто поменять их местами.
fib dw 24 dup (0) ; i don't know masm too well, this should create 24 words
calculate:
cld
mov word ptr[fib ],1 ; f(1)
mov ax, 1
mov word ptr[fib+2],1 ; f(2)
mov bx, 1
mov di, offset fib+4 ; does this work in MASM ?
mov cx,22 ; this will be the loop counter
l1:
add ax,bx
stosw ; write new element to array
; note: this is equivalent to mov [di], AX and add si,2
xchg ax,bx
dec cx
jnz l1
и вуаля: вы вычислили 24 элемента
PS: я не уверен, что MASM скомпилирует это, я использую другой ассемблер, дайте мне подсказку, и я исправлю
xchg ax,bx
делает то же самое. Для условия конца цикла вы можетеcmp edi, 24*2 + OFFSET fib
или что-то в этом роде вместо того, чтобы тратить ecx на счетчик. Конечно, вам вообще не нужно сохранять результаты: вызовprintf
из цикла — это самый простой способ (сохранить состояние цикла в регистрах, сохраняемых вызовом). И почему вы используете 16-битные указатели? ОП, кажется, спрашивает конкретно о 32-битной версии. 29.03.2016add ebx, edi
/ print ebx /add edi, ebx
/ print edi делает свое дело. В любом случае, люди из IMO должны обучать рекурсии, используя функцию, в которой рекурсия имеет смысл, а цикл требует структуры данных, подобной стеку. Обход дерева является хорошим примером. 29.03.2016cmp/jcc
может объединяться с AMD и Intel даже до SnB, ноdec/jcc
может объединяться только с Intel SnB-семейством. Сравнение с конечным указателем по-прежнему связывает регистр для хранения конечного указателя, поэтому вы правы в том, что преимущество, как правило, невелико. (Редко, когда конечная точка может быть непосредственной в реальном коде, поскольку приращения указателя обычно более эффективны, чем режимы индексированной адресации, особенно в семействе Intel SnB). Однако уменьшение индекса отлично подходит для циклов с индексацией, которые могут перемещаться по массиву в обратном направлении. 29.03.2016xchg
составляет 3 мкп на Intel. Вы можете использоватьlea esi, [edi, ebx]
/mov edi, ebx
/mov ebx, esi
или что-то в этом роде, если хотите избежать развертывания цикла, чтобы избавиться от лишних ходов. 29.03.2016