Реализация функции возведения в степень - Assembler

Узнай цену своей работы

Формулировка задачи:

Всем привет. Прохожу один курс по асму, попалась такая задача: написать функцию, принимающую два беззнаковых числа (каждое из которых может равняться нулю), возвести в степень и вернуть ответ в rax. Написал такой код:
Листинг программы
  1. ;числа в rdi и rsi
  2. pow:
  3. cmpq $0,%rdi
  4. movq $0,%rax
  5. jz exit
  6. cmpq $0,%rsi
  7. movq $1,%rax
  8. jz exit
  9. dec %rsi
  10. pushq %rdi
  11. movq %rdi,%rax
  12. more:
  13. movq (%rsp),%rdx
  14. mulq %rdx
  15. dec %rsi
  16. cmpq $0,%rsi
  17. ja more
  18. exit:
  19. retq
Проверяю под отладчиком - возвращает правильный результат, но ответ системой не принимается (значит где-то ошибся). Помогите с поиском ошибки.

Решение задачи: «Реализация функции возведения в степень»

textual
Листинг программы
  1. use64
  2.  
  3. ; Входные данные: RCX - база (X), RDX - степень (Y); числа целые знаковые
  4. ; Результат: CF=0 - всё хорошо, RAX = X^Y (знаковое число); CF=1 - произошло переполнение, RAX = -1
  5. SIntPower:
  6.                 ; Проверка исходных значений
  7.                 mov     eax,1                   ; результат RAX = 1 (пока что)
  8.                 test    rdx,rdx
  9. ;               jz      .exit                   ; если Y = 0, результат = 1 (даже для X = 0) - ЗАКОММЕНТИРОВАНО, т.к. нет смысла, и так будет выход на первом цикле вычислений
  10.                 js      .neg                    ; если Y < 0, прыгаем
  11.  
  12.                 ; Вычисление
  13.         .loop:  shr     rdx,1                   ; CF = младший бит EDX
  14.                 jnc     .nomul                  ; если CF=0, пропускаем умножение
  15.                 imul    rax,rcx                 ; иначе RAX = RAX * RCX
  16.                 jo      .overflow               ; произошло переполнение?
  17.                 test    rdx,rdx
  18.         .nomul: jz      .exit                   ; выходим, если RDX = 0
  19.                 imul    rcx,rcx                 ; иначе RCX = RCX^2
  20.                 jno     .loop                   ; повторяем цикл, если не было переполнения
  21.         .overflow:
  22.                 xor     eax,eax                 ; иначе возвращаем RAX = -1 и CF=1 (это будет после dec rax) в случае переполнения
  23.         .zero:
  24.                 dec     rax                     ; результат RAX = 0
  25.         .exit:  ret
  26.  
  27.         .neg:   ; Отрицательная степень
  28.                 cmp     rcx,1
  29.                 je      .exit                   ; если X = 1, результат = 1 - эти 2 строки можно вынести к началу (после mov eax,1), это ускорит возведение 1 в степень, но замедляют другие случаи возведения в положительную степень
  30.                 cmp     rcx,-1
  31.                 jne     .zero                   ; если X <> -1, результат будет = 0 (максимально возможное значение: 2^-1 = 0.5, но мы его всё равно округлим в меньшую сторону до 0)
  32.                 test    dl,al                   ; иначе (если X = -1), проверяем чётность Y (AL = 1)
  33.                 jz      .exit                   ; если Y чётная, результат = 1
  34.                 neg     rax                     ; иначе результат = -1 (можно заменить на mov rax,rcx)
  35.                 ret
  36.  
  37. ; Входные данные: RCX - база (X), RDX - степень (Y); числа целые БЕЗзнаковые
  38. ; Результат: CF=0 - всё хорошо, RAX = X^Y (БЕЗзнаковое число); CF=1 - произошло переполнение, RAX = 0FFFFFFFFFFFFFFFFh (-1)
  39. UIntPower:
  40.                 ; Подготовка
  41.                 mov     eax,1                   ; результат RAX = 1 (пока что)
  42. ;               cmp     rcx,rax
  43. ;               je      .exit                   ; если X = 1, результат = 1 - ЗАКОММЕНТИРОВАНО, т.к. эти 2 строки ускоряют возведение 1 в степень, но замедляют другие случаи
  44.                 mov     r8,rdx                  ; R8 = Y (т.е. RDX будет уничтожен после умножения через mul)
  45.                 mov     r9d,0FFFFFFFFh          ; R9 = 0FFFFFFFFh
  46.  
  47.                 ; Вычисление
  48.                 jmp     .start                  ; пропускаем imul (он нужен только для следующих циклов)
  49.         .loop:  imul    rcx,rcx                 ; RCX = RCX^2 (перемещено сюда, чтобы не делать лишних jcc-инструкций внутри цикла)
  50.         .start: shr     r8,1                    ; CF = младший бит R8
  51.                 jnc     .nomul                  ; если CF=0, пропускаем умножение
  52.                 mul     rcx                     ; иначе RDX:RAX = RAX * RCX
  53.                 test    rdx,rdx
  54.                 jnz     .overflow               ; произошло переполнение?
  55.                 test    r8,r8
  56.         .nomul: jz      .exit                   ; выходим, если R8 = 0
  57.                 cmp     rcx,r9
  58.                 jbe     .loop                   ; повторяем цикл, если RCX <= 0FFFFFFFFh (R9), иначе будет переполнение при возведении в квадрат
  59.         .overflow:
  60.                 or      rax,-1                  ; иначе возвращаем RAX = 0FFFFFFFFFFFFFFFFh
  61.                 stc                             ; и CF=1
  62.         .exit:  ret

Объяснение кода листинга программы

  1. Устанавливается режим использования 64-битного кода.
  2. Объявляются две функции: SIntPower (возведение в степень для знаковых чисел) и UIntPower (возведение в степень для беззнаковых чисел).
  3. В функции SIntPower проверяется, что степень (Y) не равна 0. Если равна, результат будет 1.
  4. Если степень (Y) отрицательная, проводятся дополнительные проверки.
  5. В цикле происходит возведение числа (X) в степень (Y) путем последовательного умножения.
  6. Если произошло переполнение, CF устанавливается в 1, а результат RAX -1.
  7. Если степень (Y) отрицательная и число (X) равно 1, результат будет 1.
  8. Если степень (Y) отрицательная и число (X) равно -1, результат будет 0 или -1 в зависимости от четности степени.
  9. Функция UIntPower аналогична функции SIntPower, только работает с беззнаковыми числами.
  10. Результат возвращается в RAX, а флаг CF устанавливается в 1, если произошло переполнение.

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

10   голосов , оценка 4.1 из 5

Нужна аналогичная работа?

Оформи быстрый заказ и узнай стоимость

Бесплатно
Оформите заказ и авторы начнут откликаться уже через 10 минут