Shop OBEX P1 Docs P2 Docs Learn Events
PASM math — Parallax Forums

PASM math

Bobb FwedBobb Fwed Posts: 1,119
edited 2009-02-10 05:33 in Propeller 1
This has had to come have up before, but I couldn't find a whole lot with the search...
I am looking for common math uses in PASM. I have found some algorithms, but there has to be better ones out there. I found propeller.wikispaces.com/MATH as well, but the functions are HUGE!

Here is what I found for multiplying:
problem: only 16 bit inputs, but fast
'----- MULTIPLY --------------------------------
' par1 * par2
' 16-bit max input, 32-bit results
multiply2               SHL     par1, #16       ' get multiplicand into x[noparse][[/noparse]31..16]
                        MOV     midx, #16       ' ready for 16 multiplier bits
                        SHR     par2, #1        WC ' get initial multiplier bit into c

        :loop IF_C      ADD     par2, par1      WC ' conditionally add multiplicand into product
                        RCR     par2, #1        WC ' get next multiplier bit into c.
                                                ' while shift product
                        DJNZ    midx, #:loop    ' loop until done
                        MOV     ret_val, par2   ' return product
        multiply2_ret   RET



Here is mine:
problem: much slower especially when multiplying two large numbers
'----- MULTIPLY --------------------------------
' par1 * par2
' 32-bit in/out ... slower than multiply2
multiply                MOV     ret_val, #0
                        CMP     par1, #0        WZ ' if multiplyer of 0 return 0
              IF_Z      JMP     #multiplyend
                        CMP     par2, #0        WZ ' if multiplyer of 0 return 0
              IF_Z      JMP     #multiplyend

                        CMP     par1, par2      WZ, WC
             IF_Z_OR_NC JMP     #:skip
                        MOV     accum, par1     ' these commands help speed up process by reducing number of loops
                        MOV     par1, par2
                        MOV     par2, accum
              :skip
                        MOV     midx, par2
              :loop     ADD     ret_val, par1
                        DJNZ    midx, #:loop
        multiplyend
        multiply_ret    RET


I also have one that works as a signed multiplier.

Here is the divider I found:
problem: it can't divide (for example) 350/100 ... unless a whole number is returned, the output is unexpected
'----- DIVIDE ----------------------------------
' par1 / par2
divide                  SHL     par2, #15       ' get divisor into y[noparse][[/noparse]30..15]
                        MOV     midx, #16       ' ready for 16 quotient bits

        :loop           CMPSUB  par1, par2      WC ' if y =< x then subtract it, set C
                        RCL     par1, #1        ' rotate c into quotient, shift dividend
                        DJNZ    midx, #:loop    ' loop until done
                        MOV     ret_val, par1   ' move to return
        divide_ret      RET



And finally...
Square root I found:
'----- SQUARE ROOT -----------------------------
' sqrt(par1)
root                    MOV     accum, #0       ' reset accumulator
                        MOV     par2, #0        ' reset root
                        MOV     midx, #16       ' ready for 16 root bits

        :loop           SHL     par1, #1        WC ' rotate top two bits of y 
                        RCL     accum, #1       ' ..into accumulator
                        SHL     par1, #1        WC
                        RCL     accum, #1
                        SHL     par2, #2        ' determine next bit of root
                        OR      par2, #1
                        CMPSUB  accum, par2     WC
                        SHR     par2, #2
                        RCL     par2, #1
                        DJNZ    midx, #:loop    ' loop until done

                        MOV     ret_val, par2   ' move to return
        root_ret        RET



and power I made:
problem: slow and dependent on [noparse][[/noparse]slow] multiply for large numbers
'----- POWER -----------------------------------
' par1^par2 -- par1 to-the-power-of par2
pow                     CMP     par2, #0        WZ ' if power of 0 return 1
              IF_Z      MOV     ret_val, #1
              IF_Z      JMP     #powend
                        CMP     par2, #1        WZ ' if power of 1 return par1
              IF_Z      MOV     ret_val, par1
              IF_Z      JMP     #powend

                        MOV     accum, par1     ' make copy
                        MOV     m2idx, par2     ' repeat par2 times
                        SUB     m2idx, #1
                        MOV     ret_val, par1

        :loop           MOV     par1, ret_val   ' use results in next use
                        MOV     par2, accum
                        CALL    #multiply
                        DJNZ    m2idx, #:loop 
        powend
        pow_ret         RET



I'm a function-oriented-man so I have formatted these so the inputs are always par1, par2, etc. and the output is always in ret_val. It may make it slightly slower, but portability is very handy.

It seems there should be a collection of PASM math "functions" lying around somewhere. Any input?

Comments

  • jazzedjazzed Posts: 11,803
    edited 2009-02-09 19:44
    Can you make a quick remainder function from divide?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2009-02-09 19:56
    Maybe someone who is better at all this binary math stuff can help.
  • AleAle Posts: 2,363
    edited 2009-02-09 20:05
    Bobb, that page contains several different routines for different cases. For integer numbers there are not much better ones than what you posted. The HUGE functions you cite are probably the ones dealing with BCD floating point numbers. Those are quite large.
    The Spin interpreter contains some functions that are sort of small but well, a bit slow. If you look at the FFT source (referenced in that page) there are some other routines. they are faster but also longer. You cannot have everything.

    btw: I wrote that page wink.gif, most of the routines, BCD, binary and FFT, I'm missing some good fixed point ones. Suggestions are always welcome, pieces of code too.
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2009-02-09 20:10
    I just figured someone can write things better/smaller/faster than what I wrote :-P (or that I found on a first sweep).
  • jazzedjazzed Posts: 11,803
    edited 2009-02-09 20:21
    Oh well. Guess i'll have to take time and dig a remainder myself. I'm some using Ale's small multiply/divide ... they're pretty generic. It's handy that you made the wiki Ale. Thanks.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve
  • mctriviamctrivia Posts: 3,772
    edited 2009-02-10 05:33
    i love binary math it is so simple and straight forward. much easier then base 10. that book looks interesting. Would it be boring to someone that is fairly proficient in binary math and has ADD?
Sign In or Register to comment.