News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Help with an assembler project

Started by garr, April 29, 2010, 05:06:11 PM

Previous topic - Next topic

garr

/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:

clive

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)
It could be a random act of randomness. Those happen a lot as well.

garr

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);
?

clive

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
It could be a random act of randomness. Those happen a lot as well.

clive

        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
It could be a random act of randomness. Those happen a lot as well.

garr

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.

raymond

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.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

clive

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
It could be a random act of randomness. Those happen a lot as well.

raymond

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:
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

dedndave

nah, Ray
you are good for another 2e+4 miles   :bg
a little wear, but the tread is still good