# The Ultimate Fast Absolute Value

12 replies to this topic

### #1blueone

New Member

• Members
• 8 posts

Posted 10 June 2006 - 08:38 AM

Bitwise operation--------------------

In computer programming, a bitwise operation operates on one or two bit patterns or binary numerals at the level of their individual bits. On many computers, bitwise operations are slightly faster than addition and subtraction operations and significantly faster than multiplication and division operations.

I dont know if there was already existing fast absolute value in this forum but Id like to share my own :lol: .

This is absolute value for short int. It will return a new value as unsigned short.

unsigned short abss(ushort g)
{
if (g&32768u)
return 32768u-(g&32767u);
return (g);
}

This is absolute value for int.

unsigned int absi(int g)
{
if (g&2147483648u)
return 2147483648u-(g&2147483647u);
return (g);
}

This is absolute value for long int.

unsigned long int absl(long int g)
{
if (g&9223372036854775808llu)
return 9223372036854775808llu-(g&9223372036854775807llu);
return (g);
}

Is this what you are looking for? :lol:

float absf(float g)
{
unsigned int *gg;
gg=(unsigned int*)&g;
*(gg)&=2147483647u;
return g;
}

Another one :yes:

double absd(double g)
{
unsigned long int *gg;
gg=(unsigned long int*)&g;
*(gg)&=9223372036854775807llu;
return g;
}

Hope you like its performance :worthy: :sneaky: :lol:

### #2Nick

Senior Member

• Members
• 1227 posts

Posted 10 June 2006 - 09:12 AM

I hate to be the one to tell you but these things are well known. It's cool though that you found them on your own! :yes:

A typically faster and more importantly cleaner way to compute absolute value is:

inline int abs(int x)

{

return (x > 0) ? x : -x;

}


On most platforms this compiles into code without branches (no jumps) and computing -x takes just one clock cycle.

For floating point we can also use the slightly nicer hexadecimal notation:

inline float abs(float x)

{

int y = (int&)x & 0x7FFFFFFF;

return (float&)y;

}



### #3.oisyn

DevMaster Staff

• Moderators
• 1842 posts

Posted 10 June 2006 - 10:54 AM

Nick: unfortunately, your abs float code performs terrible on the xbox360 for example, as it requires the variable to be stored to memory. This has massive stalls.

And why is fabs slow anyway? The cpu only has to set a single bit to 1. Is it the long path to the FPU? Or is it that fabs itself isn't slow, but the C runtime function around it that is?

Also, here is an abs(int) without conditional code:
int abs(int value)
{
static const int INT_BITS = sizeof(int) * CHAR_BIT;
int topbitreplicated = value >> (INT_BITS - 1);
return (value ^ topbitreplicated) - topbitreplicated;
}

a shift, a xor and an add.
-
Currently working on: the 3D engine for Tomb Raider.

### #4Nick

Senior Member

• Members
• 1227 posts

Posted 10 June 2006 - 06:24 PM

.oisyn said:

Nick: unfortunately, your abs float code performs terrible on the xbox360 for example, as it requires the variable to be stored to memory. This has massive stalls.
It's functionally the same as blueone's version. Most processors have an instruction for floating-point absolute value though. x87 has fabs, and for SSE the andps instruction can be used. On processors without such instructions I believe changing the sign in memory is the fastest method.

Quote

And why is fabs slow anyway? The cpu only has to set a single bit to 1. Is it the long path to the FPU? Or is it that fabs itself isn't slow, but the C runtime function around it that is?
I guess it depends on the compiler and the runtime. With Visual C++ 2005 in Release mode on an x86 processor the function translates into a single fabs instruction.

Quote

Also, here is an abs(int) without conditional code:
int abs(int value)

{

static const int INT_BITS = sizeof(int) * CHAR_BIT;

int topbitreplicated = value >> (INT_BITS - 1);

return (value ^ topbitreplicated) - topbitreplicated;

}

a shift, a xor and an add.
On x86 processors the fastest approach is to use this sequence:

cdq

xor eax, edx

sub eax, edx


cdq is equivalent to 'mov edx, eax; sar edx, 31'. This is also what Visual C++ 2005 uses when using the math.h abs() function.

New Member

• Members
• 4 posts

Posted 28 June 2006 - 11:48 AM

Nick said:

For floating point we can also use the slightly nicer hexadecimal notation:

inline float abs(float x)

{

int y = (int&)x & 0x7FFFFFFF;

return (float&)y;

}


No we cannot. IEEE floating point does not set the internal representation in any way, shape or form. And you rounded.

### #6Nick

Senior Member

• Members
• 1227 posts

Posted 28 June 2006 - 01:49 PM

No we cannot. IEEE floating point does not set the internal representation in any way, shape or form. And you rounded.
Yes we can. Yes it does. I made the value positive.

But feel free to elaborate... :huh:

### #7Jare

Valued Member

• Members
• 247 posts

Posted 29 June 2006 - 12:12 AM

IEEE floating point does not set the internal representation in any way, shape or form.

### #8jmgk

New Member

• Members
• 5 posts

Posted 29 June 2006 - 04:05 AM

hi,

in x86 asm, for a int, you can do


btr eax,31



but dunno if its fast enought

jmgk

### #9Reedbeta

DevMaster Staff

• 5340 posts
• LocationSanta Clara, CA

Posted 29 June 2006 - 04:12 AM

Unfortunately, that doesn't work. You can't just reset the sign bit as numbers are stored in two's complement format.
reedbeta.com - developer blog, OpenGL demos, and other projects

### #10tbp

Valued Member

• Members
• 135 posts

Posted 29 June 2006 - 11:16 AM

Use unions.

### #11Jare

Valued Member

• Members
• 247 posts

Posted 29 June 2006 - 06:25 PM

Reedbeta said:

You can't just reset the sign bit as numbers are stored in two's complement format.
IEEE floating point numbers do not use two's complement for either the mantissa or the exponent. The mantissa M is always positive, and the exponent E is stored with a bias. The sign bit is exactly what it says: a bit indicating whether the number has a negative sign in front of it or not. The link explains everything in quite clear terms.

Or did I misunderstand you?

### #12martinsm

Member

• Members
• 88 posts

Posted 29 June 2006 - 06:39 PM

Reedbeta was answering to jmgk post, not yours.

### #13Reedbeta

DevMaster Staff

• 5340 posts
• LocationSanta Clara, CA

Posted 29 June 2006 - 10:00 PM

Yes. He claimed you could do it by just resetting bit 31 for integers. That would certainly work for an IEEE float stored in an integer register though. Which is exactly what Nick's code sample does.
reedbeta.com - developer blog, OpenGL demos, and other projects

#### 1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users