The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: garr on April 29, 2010, 05:06:11 PM

Title: Help with an assembler project
Post by: garr on April 29, 2010, 05:06:11 PM
/sigh
keep smashing my head on the desk with this one  :dazzled:
I have to calculate powers recursively for  this one: x^y. But it's a specific way the teacher wants us to do it. we have to have 2 procedures - one that is an input procedure that gets passed the address of 2 memory variables, and the other one is the actual recursive procedure that does the calculation.  The way he wants us to do the calculation is:
(assume n2 is the exponent and n1 the base). If n2 is even then return power(n1*n1, n2 >> 1) else return n1*power(n1 * n1, n2 >> 1)
I can do this procedure the normal way by looping down n2 to calculate... but alas this is not what he wants.

Here is what I have now:
TITLE MASM Template (main.asm)

;includes
INCLUDE include\masm32rt.inc

.data
TWO         SDWORD      2
base SDWORD      0 ;our base
exponent SDWORD 0 ;exponent
product SDWORD 1 ;answer is stored here

.code
;------------------------------------------------------------------------
;This is our recursive procedure that constantly calls itself to multiply
;------------------------------------------------------------------------
power   PROC uses edx,  n1:SDWORD, n2:SDWORD

      print             "n2 & n1 & product: "
      print             str$(n2)
      print             "   "
      print             str$(n1)
      print             "   "
      print             str$(product),13,10
     
      mov               edx,0                   ;zero out edx for division
      cmp               n2,0                    ;compare the exponent to 0, if its zero we are done
      jle               stop                    ;goto the return statement

      mov               eax,n2                  ;move exponent to eax
      IDIV              TWO                     ;divide by TWO (2)
      cmp               edx,0                   ;cmp the remainder to 0
      je                L1                      ;if it is zero then its even so jump to L1

      mov               eax,n1             ; else copy the current product to eax
      IMUL              n1                      ;multiply it by n1 which is the base
      IMUL              n1                      ;multiply it again as per the project
      mov               product,edx             ;product is in edx and move that back to product
     
      SAR               n2,1
      Invoke            power,n1,n2
      jmp               stop                    ;skip the label
                   
L1:
      mov               eax,n1
      IMUL              n1                      ;edx = eax * n1   
      mov               product,edx             ;move product into product from edx
     
      SAR               n2,1
      Invoke            power,n1,n2

stop: 
      RET
power ENDP

;-------------------------------------------
;Our procedure to obtain input from the user
;-------------------------------------------

getInput PROC  n1:PTR SDWORD, n2:PTR SDWORD

    mov                 n1, sval(input("Enter the integer base: "))
    mov                 n2, sval(input("Enter the integer exponent: "))
    mov                 ebx,n1
    mov                 product,ebx

    cmp                 n2, 0   ;check our exponent if it is negative get the absolute value
    jl                  getABS
   
    Invoke              power, n1, n2
    RET
getABS:
    NEG                 n2
    Invoke              power, n1, n2
    RET
getInput ENDP

main PROC
    Invoke        getInput,Addr base,Addr exponent
    print         "Answer: "                    ;print our answer
    print         str$(product),13,10 
   
    inkey 
    exit
main ENDP
END main


there are some print statements in there to help troubleshoot. For some reason product is being zeroed out. I did this in java because I was unfamiliar with the shifting and the effect it had on the project. Here it is if it helps anyone:
import java.util.Scanner;

public class AsmProj3test {
   
    public static void main(String[] args) {
    Scanner input = new Scanner(System.in);
    int base;
    int exponent;
    int answer;
   
    System.out.print("Enter base: ");
    base = input.nextInt();
    System.out.print("Enter exponent: ");
    exponent = input.nextInt();
   
    if(exponent < 0)
    Math.abs(exponent);
   
    answer = power(base,exponent);
    System.out.println("Answer is: " + answer);
    }
   
    public static int power(int n1, int n2)
    {
    if(n2 <= 0)
    return 1;
   
    if(n1 % 2 == 0)
    {
    return power(n1*n1, n2>>>1);
    }
    else
    return n1*power(n1*n1,n2>>>1);
    }
}


So i essentially need a way to transfer the power function over to assembly. Help please! Thanks! :cheekygreen:
Title: Re: Help with an assembler project
Post by: clive on April 29, 2010, 05:18:42 PM
The product is not in EDX

; x = n1**abs(n2)

        mov     esi,1           ; x = 1

        mov     eax,n2
        cdq                     ; ABS(n2)
        xor     eax,edx
        sub     eax,edx
        jz      label_30        ; is zero, n1**0 = 1

        mov     edi,n1          ; y = n1

        ; eax = abs(n2)

label_10:

        test    al,1            ; Is LSB set
        jz      label_20        ; No

        imul    esi,edi         ; x = x * y

label_20:

        shr     eax,1
        jz      label_30        ; Continue if non zero, else exit early

        imul    edi,edi         ; y = y * y

        jmp     label_10

label_30:

        ; esi = x = n1**abs(n2)
Title: Re: Help with an assembler project
Post by: garr on April 29, 2010, 09:19:02 PM
ahhh well your code went over my head. I changed it so eax is going into product instead of edx. I don't think the teacher really cares about the product becoming a 64 bit answer. I don't even know what you did  :toothy
At what point do i get to
    if(n1 % 2 == 0)
    {
    return power(n1*n1, n2>>>1);
    }
    else
    return n1*power(n1*n1,n2>>>1);
?
Title: Re: Help with an assembler project
Post by: clive on April 30, 2010, 12:05:32 AM
You understand that it should be N2 % 2 right? Not N1

    if(n2 % 2 == 0)


I'm not doing it recursively, but by powers of 2 in a loop. Achieves the same thing.

        test    al,1            ; Is LSB set, equivalent to if ((n2 % 2) == 0)
        jz      label_20        ; No, remainder of EAX/2 = 0
Title: Re: Help with an assembler project
Post by: clive on April 30, 2010, 12:51:06 AM
        TITLE MASM Template      (main.asm)

;includes

        INCLUDE \masm32\include\masm32rt.inc

        .code

;------------------------------------------------------------------------
;This is our recursive procedure that constantly calls itself to multiply
;------------------------------------------------------------------------

power   PROC uses edx,  n1:SDWORD, n2:SDWORD

        mov     eax,1           ; n1**0 = 1

        mov     edx, n2         ; move exponent to edx, edx = n2
        cmp     edx, 0          ; compare the exponent to 0, if its zero we are done
        jle     stop            ; goto the return statement

        mov     eax, n1         ; eax = n1
        imul    eax, eax        ; eax = eax (n1) * eax (n1), edx preserved

        shr     edx,1           ; edx = n2 >> 1, carry = n2 % 2
        jnc     L1              ; if it is zero (no carry) then its even so jump to L1

        Invoke  power,eax,edx   ; power(n1*n1, n2 >> 1)
        imul    eax, n1         ; * n1

        jmp     stop            ; return(n1 * power(n1*n1, n2 >> 1))

L1:

        Invoke  power,eax,edx   ; return(power(n1*n1, n2 >> 1)

stop:

        ret                     ; returns answer in eax

power   ENDP

;-------------------------------------------
;Our procedure to obtain input from the user
;-------------------------------------------

main    PROC
        LOCAL n1:SDWORD
        LOCAL n2:SDWORD

        mov     n1, sval(input("Enter the integer base: "))
        mov     n2, sval(input("Enter the integer exponent: "))

        cmp     n2, 0   ;check our exponent if it is negative get the absolute value
        jge     positive

        NEG     n2      ; n2 = -n2

positive:

        Invoke  power, n1, n2

; answer in eax = power(n1, abs(n2))

        push    eax
        print   "Answer: "                    ;print our answer
        pop     eax
        print   str$(eax),13,10

        inkey
        exit

main    ENDP

        END main
Title: Re: Help with an assembler project
Post by: garr on April 30, 2010, 01:16:20 AM
alright thanks. yeah that was a typo for the java app i wrote up. Didnt even notice because the input i was putting in was still giving me the right answer.
Title: Re: Help with an assembler project
Post by: raymond on April 30, 2010, 03:46:48 AM
clive
According to your latest posted procedure, what result would it output for an input such as 27?

It seems that you would first re-enter the procedure with eax=22 and edx=3,
then with eax=24 and edx=1,
then with eax=28 and edx=0,

which would exit with eax=1 and return to the imul    eax, n1 instruction where you would multiply by 2,
then return to that instruction twice more to finally exit with eax=23.
Title: Re: Help with an assembler project
Post by: clive on April 30, 2010, 12:33:46 PM
Seems to be working as designed here.

C:\MASM>pp
Enter the integer base: 2
Enter the integer exponent: 7
Answer: 128
Press any key to continue ...

C:\MASM>pp
Enter the integer base: 2
Enter the integer exponent: 0
Answer: 1
Press any key to continue ...

C:\MASM>pp
Enter the integer base: 2
Enter the integer exponent: 1
Answer: 2
Press any key to continue ...

C:\MASM>pp
Enter the integer base: 2
Enter the integer exponent: 2
Answer: 4
Press any key to continue ...

C:\MASM>pp
Enter the integer base: 2
Enter the integer exponent: 3
Answer: 8
Press any key to continue ...

C:\MASM>pp
Enter the integer base: 2
Enter the integer exponent: 16
Answer: 65536
Press any key to continue ...


00000000                    _power@8:
00000000 55                     push    ebp
00000001 8BEC                   mov     ebp,esp
00000003 52                     push    edx
00000004 B801000000             mov     eax,1
00000009 8B550C                 mov     edx,[ebp+0Ch]
0000000C 83FA00                 cmp     edx,0
0000000F 7E1E                   jle     loc_0000002F
00000011 8B4508                 mov     eax,[ebp+8]
00000014 0FAFC0                 imul    eax,eax
00000017 D1EA                   shr     edx,1
00000019 730D                   jnb     loc_00000028
0000001B 52                     push    edx
0000001C 50                     push    eax
0000001D E8DEFFFFFF             call    _power@8
00000022 0FAF4508               imul    eax,[ebp+8]
00000026 EB07                   jmp     loc_0000002F
00000028                    loc_00000028:
00000028 52                     push    edx
00000029 50                     push    eax
0000002A E8D1FFFFFF             call    _power@8
0000002F                    loc_0000002F:
0000002F 5A                     pop     edx
00000030 C9                     leave
00000031 C20800                 ret     8


Quote from: raymond on April 30, 2010, 03:46:48 AM
clive
According to your latest posted procedure, what result would it output for an input such as 27?

It seems that you would first re-enter the procedure with eax=22 and edx=3,
then with eax=24 and edx=1,
then with eax=28 and edx=0,

which would exit with eax=1 and return to the imul    eax, n1 instruction where you would multiply by 2,
then return to that instruction twice more to finally exit with eax=23.

Not that it's my assignment, but 1 * 2^4 * 2^2 * 2, or 128
Title: Re: Help with an assembler project
Post by: raymond on May 01, 2010, 03:48:25 AM
My bad. :red :red :red

Just realized that the "n1" on the stack changes with each iteration. Must be old age taking over. :eek

Nice work clive. :clap:
Title: Re: Help with an assembler project
Post by: dedndave on May 01, 2010, 10:04:13 AM
nah, Ray
you are good for another 2e+4 miles   :bg
a little wear, but the tread is still good