Fastest way to do abs(x) in dsPIC assembly

Thread Starter

tom66

Joined May 9, 2009
2,595
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:
Rich (BB code):
int abs(int x) { return (x < 0) ? -x : x; }
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:
Rich (BB code):
btfsc R0,7
decf R0
btfsc R0,7
comf R0
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.
 

Papabravo

Joined Feb 24, 2006
21,226
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.
 

Thread Starter

tom66

Joined May 9, 2009
2,595
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...
 

Papabravo

Joined Feb 24, 2006
21,226
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...
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.
 

Thread Starter

tom66

Joined May 9, 2009
2,595
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.
Subtracting a negative number from 0 will give you the absolute value in a signed 2's complement number system.
...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.)
 

someonesdad

Joined Jul 7, 2009
1,583
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.
 

Thread Starter

tom66

Joined May 9, 2009
2,595
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.
 

someonesdad

Joined Jul 7, 2009
1,583
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...
 

Thread Starter

tom66

Joined May 9, 2009
2,595
Here is my final code:

Rich (BB code):
btsc    W0, #15      ; skip if positive, 2 cycles if skip taken / 1 cycle if not
subr    W0, #0, W1   ; subtract reversed, compute W1 = 0 - W0, 1 cycle
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.
 
Top