Archived

This topic is now archived and is closed to further replies.

nPawn

How fast is the abs() function?

Recommended Posts

I''m trying to optimize a set of code that has to check a large list repeatedly to see if an object is in range of the main player and worth drawing/animating and i have to decide if the abs function is going to be slower or faster than checking with greater than and less than? here''s the function: bool CObject::InRange(float x, float z, float radius) { //x and y are coords of main player if (abs((int)(x - m_fPosX)) < radius) { if (abs((int)(z - m_fPosZ)) < radius) {//object is inside the radius return true return true; } } //object is NOT inside the radius return false return false; } would it be quicker to do this instead: bool CObject::InRange(float x, float z, float radius) { if ((x - m_fPosX) < radius) && ((x - m_fPosX) > -radius)) { if ((z - m_fPosZ) < radius) && ((x - m_fPosZ) > -radius)) { return true; } } return false; } or perhaps there''s an even quicker way without bothering to set up an elaborate tree system?

Share this post


Link to post
Share on other sites
abs() may be implemented as a macro; the C standard library provides both function and macro versions. For most uses, the macro version is more than sufficient, and it looks like this:

#define abs(x) ((x > 0) ? x : -x)

Given that expansion, I think your first version of InRange() would be faster (fewer operations).

Share this post


Link to post
Share on other sites
Thanks, I was thinking maybe the abs function was done in assembly and simply sets the signed bit to off, which would be dang quick compared to doing some greater than / less than checking.

Hmm in fact maybe i could even just do a quick bit shift to clear the sign bit? Is the leading bit on a float the sign bit? If so i could shift it left once, clearing the leading bit to zero, then shift it back right, and the number would then be positive? Something like:

x << 1;
x >> 1;


I'll also try the macro way and see if that gives any improvement.

Edited by - nPawn on October 19, 2001 1:36:53 PM

Share this post


Link to post
Share on other sites
quote:
Original post by nPawn
x << 1;
x >> 1;


x &= (1 << 31);

I'm too preoccupied to think what that compiles to, but it's clearer what you're trying to do (and a single AND is better than 2 shifts).

Edit: and don't worry about the shift. Since both operands are constants, the compiler will replace that with the literal equivalent at compile time (provided your compiler is set to optimize.)

Edited by - Oluseyi on October 19, 2001 2:05:06 PM

Share this post


Link to post
Share on other sites
The absolute value of a float (ie 32-bit floating point number in IEEE) can be found like this in C/C++:

  
#define FLOAT_BITS(f) (*(int*)&(f))

inline float fabs(float f)
{
return FLOAT_BITS(f) & 0x7FFFFFFF;
}

Share this post


Link to post
Share on other sites
Oluseyi: It would actually be:

x &= ~(1 << 31);

Or, to make it easier:

x &= 0x7fffffff;

But clearing the MSB isn''t going to help you at all if you''re dealing with integers.

Integers use a two''s complement signed implementation, so clearing the MSB is going to be fine for positive numbers, but for negative numbers, you''ll just end up with a completely unrelated positive number.

-1 = 0xFFFFFFFF

With your code, you''d end up turning that into 0x7FFFFFFF which most certainly is not 1

I''m afraid you''ll have to do a comparison. There is a tricky way of doing it in assembly without a comparison, provided you''re working in 16-bit real mode:

;
; Input: AX = Number
; Output: AX = Absolute value
; Trashed: DX
;

cwd
xor ax, dx
sub ax, dx

That''s a trick I picked up from Abrash''s graphics book. However, he mentions this code is actually slower on 486s than a TEST and jump. So I guess you''ll have to use

test eax, eax
jns short .dont_negate
neg eax
.dont_negate
...

If there''s a particularly fast way of doing a 32-bit absolute value in assembly (faster than TEST+JNS), please let me know! (Try emailing trzy@mailandnews.com if you can.)


---
Bart

Share this post


Link to post
Share on other sites
quote:
Original post by trzy
Oluseyi: It would actually be:

x &= ~(1 << 31);

Or, to make it easier:

x &= 0x7fffffff;

Thanks. Missed that.

I did think about the two''s complement aspect of things, but I''m too lazy to immediately come back and rectify the code. I just did this problem last week in SPARC assembly...

Thanks. That''s why I like forums; someone else will spot and correct your mistakes (hopefully).

Share this post


Link to post
Share on other sites