Реализация функции возведения в степень - Assembler
Формулировка задачи:
Всем привет.
Прохожу один курс по асму, попалась такая задача:
написать функцию, принимающую два беззнаковых числа (каждое из которых может равняться нулю), возвести в степень и вернуть ответ в rax.
Написал такой код:
Проверяю под отладчиком - возвращает правильный результат, но ответ системой не принимается (значит где-то ошибся). Помогите с поиском ошибки.
;числа в rdi и rsi pow: cmpq $0,%rdi movq $0,%rax jz exit cmpq $0,%rsi movq $1,%rax jz exit dec %rsi pushq %rdi movq %rdi,%rax more: movq (%rsp),%rdx mulq %rdx dec %rsi cmpq $0,%rsi ja more exit: retq
Решение задачи: «Реализация функции возведения в степень»
textual
Листинг программы
use64 ; Входные данные: RCX - база (X), RDX - степень (Y); числа целые знаковые ; Результат: CF=0 - всё хорошо, RAX = X^Y (знаковое число); CF=1 - произошло переполнение, RAX = -1 SIntPower: ; Проверка исходных значений mov eax,1 ; результат RAX = 1 (пока что) test rdx,rdx ; jz .exit ; если Y = 0, результат = 1 (даже для X = 0) - ЗАКОММЕНТИРОВАНО, т.к. нет смысла, и так будет выход на первом цикле вычислений js .neg ; если Y < 0, прыгаем ; Вычисление .loop: shr rdx,1 ; CF = младший бит EDX jnc .nomul ; если CF=0, пропускаем умножение imul rax,rcx ; иначе RAX = RAX * RCX jo .overflow ; произошло переполнение? test rdx,rdx .nomul: jz .exit ; выходим, если RDX = 0 imul rcx,rcx ; иначе RCX = RCX^2 jno .loop ; повторяем цикл, если не было переполнения .overflow: xor eax,eax ; иначе возвращаем RAX = -1 и CF=1 (это будет после dec rax) в случае переполнения .zero: dec rax ; результат RAX = 0 .exit: ret .neg: ; Отрицательная степень cmp rcx,1 je .exit ; если X = 1, результат = 1 - эти 2 строки можно вынести к началу (после mov eax,1), это ускорит возведение 1 в степень, но замедляют другие случаи возведения в положительную степень cmp rcx,-1 jne .zero ; если X <> -1, результат будет = 0 (максимально возможное значение: 2^-1 = 0.5, но мы его всё равно округлим в меньшую сторону до 0) test dl,al ; иначе (если X = -1), проверяем чётность Y (AL = 1) jz .exit ; если Y чётная, результат = 1 neg rax ; иначе результат = -1 (можно заменить на mov rax,rcx) ret ; Входные данные: RCX - база (X), RDX - степень (Y); числа целые БЕЗзнаковые ; Результат: CF=0 - всё хорошо, RAX = X^Y (БЕЗзнаковое число); CF=1 - произошло переполнение, RAX = 0FFFFFFFFFFFFFFFFh (-1) UIntPower: ; Подготовка mov eax,1 ; результат RAX = 1 (пока что) ; cmp rcx,rax ; je .exit ; если X = 1, результат = 1 - ЗАКОММЕНТИРОВАНО, т.к. эти 2 строки ускоряют возведение 1 в степень, но замедляют другие случаи mov r8,rdx ; R8 = Y (т.е. RDX будет уничтожен после умножения через mul) mov r9d,0FFFFFFFFh ; R9 = 0FFFFFFFFh ; Вычисление jmp .start ; пропускаем imul (он нужен только для следующих циклов) .loop: imul rcx,rcx ; RCX = RCX^2 (перемещено сюда, чтобы не делать лишних jcc-инструкций внутри цикла) .start: shr r8,1 ; CF = младший бит R8 jnc .nomul ; если CF=0, пропускаем умножение mul rcx ; иначе RDX:RAX = RAX * RCX test rdx,rdx jnz .overflow ; произошло переполнение? test r8,r8 .nomul: jz .exit ; выходим, если R8 = 0 cmp rcx,r9 jbe .loop ; повторяем цикл, если RCX <= 0FFFFFFFFh (R9), иначе будет переполнение при возведении в квадрат .overflow: or rax,-1 ; иначе возвращаем RAX = 0FFFFFFFFFFFFFFFFh stc ; и CF=1 .exit: ret
Объяснение кода листинга программы
- Устанавливается режим использования 64-битного кода.
- Объявляются две функции: SIntPower (возведение в степень для знаковых чисел) и UIntPower (возведение в степень для беззнаковых чисел).
- В функции SIntPower проверяется, что степень (Y) не равна 0. Если равна, результат будет 1.
- Если степень (Y) отрицательная, проводятся дополнительные проверки.
- В цикле происходит возведение числа (X) в степень (Y) путем последовательного умножения.
- Если произошло переполнение, CF устанавливается в 1, а результат RAX -1.
- Если степень (Y) отрицательная и число (X) равно 1, результат будет 1.
- Если степень (Y) отрицательная и число (X) равно -1, результат будет 0 или -1 в зависимости от четности степени.
- Функция UIntPower аналогична функции SIntPower, только работает с беззнаковыми числами.
- Результат возвращается в RAX, а флаг CF устанавливается в 1, если произошло переполнение.
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д