Fastest way to do abs(x) in dsPIC assembly

Discussion in 'Programmer's Corner' started by tom66, Jul 29, 2010.

  1. tom66

    Thread Starter Senior Member

    May 9, 2009
    2,613
    213
    I've been looking on the 'net and I haven't found many examples of how to do the abs(x) function for signed variables in assembly efficiently, both in speed and in code space.

    abs(x) can be implemented in C like this:
    Code ( (Unknown Language)):
    1.  
    2. int abs(int x) { return (x < 0) ? -x : x; }
    3.  
    But translating that into assembly is the difficult part. It's also not very efficient, involving a branch and compare.

    Now I have found that this code may do the job, for 8-bit PICs:
    Code ( (Unknown Language)):
    1.  
    2. btfsc R0,7
    3. decf R0
    4. btfsc R0,7
    5. comf R0
    6.  
    From here: http://www.piclist.com/techref/microchip/condrepl.htm

    This essentially tests if the number is negative and computes its complement. It can vary from 4 cycles to 6 cycles. I'm working with dsPIC processors, but this code can be made to fit with few changes.

    But I was wondering if there was a faster way. I am dealing with a speed critical application and every last bit of speed I can squeeze out would be good. If anyone knows it would be great. Thanks.
     
  2. Papabravo

    Expert

    Feb 24, 2006
    10,135
    1,786
    Subtracting a negative number from 0 will give you the absolute value in a signed 2's complement number system. This may be faster than complement and increment especially if you have a "zero" available without additional overhead. I'm also assuming that you have no NEGATE instruction that takes the twos complement in a single instruction.
     
  3. tom66

    Thread Starter Senior Member

    May 9, 2009
    2,613
    213
    Doing x = 0 - x will not compute the absolute function it will compute the inversion function, i.e. give it a positive number and it will give you a negative output. Good idea on flipping the sign though. But how to check if a number is negative? There is a bra n, addr instruction which branches on negative, but I'm sure there must be a way to go faster...
     
  4. Papabravo

    Expert

    Feb 24, 2006
    10,135
    1,786
    Reread my post. I said subtracting a negative number from zero might be faster than complement and increment. I never claimed it would compute the function without a test. Certainly you would expect that I would KNOW that with a positive number there is nothing to do. I'm not exactly a noob at this after half a century.
     
  5. tom66

    Thread Starter Senior Member

    May 9, 2009
    2,613
    213
    Sorry if I insulted you. It wasn't intentional in any way. I don't know you and probably never will, so I do not know your experience, skill, history or knowledge.
    ...can certainly be misread as doing x = 0 - x will give you abs(x). The rest puts it into context better, so I guess I misread your post. And to fully answer your post the dsPICs have a sub Wns,#Slit4,Wnd instruction, which gives me zero at no overhead.

    Also, programming for 50 years? Impressive... I touched my first computer in '97 (an old Commodore 64.)
     
  6. someonesdad

    Senior Member

    Jul 7, 2009
    1,585
    141
    I don't know the PIC architecture, so this may not be useful. But if these numbers have a sign bit somewhere, setting that to positive would be one instruction. If the representation is 2's complement, remember that the most negative number doesn't have an absolute value, so you may need extra logic for that condition.
     
  7. tom66

    Thread Starter Senior Member

    May 9, 2009
    2,613
    213
    someonesdad that wouldn't work, because you'd have to complement the number to get a proper representation, or decrement it. For example if you change the sign on -2 you get +125, this is just due to how 2's complement is stored.

    I think the problem here is not converting negative to positive or vice-versa, it is determining the sign of the number quickly; perhaps there's some way to copy the sign and invert in one instruction, but I doubt it.

    I'm curious as to how the C version of abs(x) handles the most negative number which can't be stored as a positive number. It may just represent it as the closest value, i.e. -128 becomes +127, or it may overflow, producing -128.
     
  8. someonesdad

    Senior Member

    Jul 7, 2009
    1,585
    141
    Like I said, I don't know the PIC architecture, so take the comments with a grain of salt. :p

    If you want to know how the C compiler handles something, just dump the assembly and see what it does...
     
  9. tom66

    Thread Starter Senior Member

    May 9, 2009
    2,613
    213
    Here is my final code:

    Code ( (Unknown Language)):
    1.  
    2. btsc    W0, #15      ; skip if positive, 2 cycles if skip taken / 1 cycle if not
    3. subr    W0, #0, W1   ; subtract reversed, compute W1 = 0 - W0, 1 cycle
    4.  
    This calculates the absolute value, abs(x), of W0, and puts it in W1. It takes 2 cycles exactly, whether or not the number is positive or negative. I haven't tested this yet but it should work.
     
  10. Papabravo

    Expert

    Feb 24, 2006
    10,135
    1,786
    Cool beans man!
     
Loading...