Jump to content


- - - - -

The Ultimate Fast Absolute Value


12 replies to this topic

#1 blueone

    New Member

  • Members
  • Pip
  • 8 posts

Posted 10 June 2006 - 08:38 AM

Bitwise operation--------------------
From Wikipedia, the free encyclopedia

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:

#2 Nick

    Senior Member

  • Members
  • PipPipPipPip
  • 1227 posts
  • LocationOttawa, Ontario, Canada

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.
C++ addict
-
Currently working on: the 3D engine for Tomb Raider.

#4 Nick

    Senior Member

  • Members
  • PipPipPipPip
  • 1227 posts
  • LocationOttawa, Ontario, Canada

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.

#5 WatsonLadd

    New Member

  • Members
  • Pip
  • 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.

#6 Nick

    Senior Member

  • Members
  • PipPipPipPip
  • 1227 posts
  • LocationOttawa, Ontario, Canada

Posted 28 June 2006 - 01:49 PM

WatsonLadd said:

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:

#7 Jare

    Valued Member

  • Members
  • PipPipPip
  • 247 posts

Posted 29 June 2006 - 12:12 AM

WatsonLadd said:

IEEE floating point does not set the internal representation in any way, shape or form.
Obligatory Wikipedia link: http://en.wikipedia....-point_standard

#8 jmgk

    New Member

  • Members
  • Pip
  • 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

#9 Reedbeta

    DevMaster Staff

  • Administrators
  • 5306 posts
  • LocationBellevue, WA

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

#10 tbp

    Valued Member

  • Members
  • PipPipPip
  • 135 posts

Posted 29 June 2006 - 11:16 AM

Aliasing = bad.

Use unions.

#11 Jare

    Valued Member

  • Members
  • PipPipPip
  • 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?

#12 martinsm

    Member

  • Members
  • PipPip
  • 88 posts

Posted 29 June 2006 - 06:39 PM

Reedbeta was answering to jmgk post, not yours.

#13 Reedbeta

    DevMaster Staff

  • Administrators
  • 5306 posts
  • LocationBellevue, WA

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