Jump to content


bit twiddling hack request!


6 replies to this topic

#1 Nils Pipenbrinck

    Senior Member

  • Members
  • PipPipPipPip
  • 597 posts

Posted 08 February 2007 - 08:10 PM

Hi folks!

I'm searching for a fast way to find out if a number stored in a float is near to an integer. Basically something like this:

bool IsNear = (fabs(float_number - (int)float_number) <= some_small_value)

I don't really care about the rounding mode, the exact value of some_small_value ect. Only a heuristic is needed. I wouldn't even mind a code that gives false negatives at times. No handling for NAN's and denormals required as well.

To the background: The system I'm working on is quite slow when it comes to FPU stuff. It's not soft-float but close from a performance point of view. To translate it from my system to the x86 world, imagine an FPU operation would be 5 to 10 times slower than the integer counterpart. Rounding and transfering data from and to the FPU are even slower.

So - how do I find out fast if a float is roughly representable as an integer. I need this to accelerate a function which can be done a lot quicker with whole numbers (a special case occures quite often).

Any ideas? Where are the IEEE 754 wizards? :-)

Nils

#2 pater

    Valued Member

  • Members
  • PipPipPip
  • 117 posts

Posted 18 February 2007 - 06:32 PM

Can we make an assumption about the order of magnitude of the represented values? I.E. anything that has an exponent that it larger than 15 is always close to an integer, because of the precision (although this is irrelevant, since anything > 2^32 is cannot be represented as int anyway). Anything with an exponent smaller than 0 can never be close to an int (except to 0, which can be tested quite easily).

#3 Nick

    Senior Member

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

Posted 18 February 2007 - 11:26 PM

Could you tell us a bit more about the function you want to optimize?

One trick I'm thinking of is to add a large number and subtract it again so the less significant bits gets pushed out. Using 12582912 this actually results in rounding to integer. So you could use it like this:

void main()

{

    float value = 1.001f;


    const float large = 12582912;

    const float small = 12582912 / 256;


    volatile float x = value + large;

    volatile float y = x - large;


    volatile float z = value + small;

    volatile float w = z - small;


    bool isNear = (y == w);

}



#4 Razor

    Member

  • Members
  • PipPip
  • 46 posts

Posted 19 February 2007 - 12:03 AM

That's a cute trick Nick!

I don't suppose you get away with just using fixed point?

#5 dave_

    Senior Member

  • Members
  • PipPipPipPip
  • 584 posts

Posted 19 February 2007 - 12:40 AM

I think nick's done the closest thing you can. (although I'm not sure it works for big values?)
Is it actually quicker?

#6 .oisyn

    DevMaster Staff

  • Moderators
  • 1842 posts

Posted 19 February 2007 - 10:25 AM

Why volatile?

But Nils talked about FPU operations being much slower than their integer counterparts. Another trick is to check the upper N bits (depending on your threshold) starting from the decimal point. If these bits are all zeroes or all ones then it is near an integer.

template<unsigned N> bool IsNear(float f)
{
	unsigned dword = reinterpret_cast<unsigned &>(f);
	unsigned exponent = (dword >> 23) & 0xff;
	unsigned topbit = 0;

	if (exponent < 127-N) 
		return true;	// number is close enough to 0
	else if (exponent < 126)
		return false;	// number is too far away from 0, but less than 0.5
	else if (exponent == 126)
		topbit = 1 << (N - 1); // we need the implicit 1 for values in the range 0.5..1

	const unsigned ones = 0x7fffffff >> (31 - N);
	unsigned mantissa = dword & 0x007fffff;
	unsigned value = ((mantissa >> (150 - N - exponent)) & ones) | topbit;
	return value == 0 || value == ones;
}

Note that this code rounds upwards - if you use N=2, which means a threshold of 0.25, 1.75 is determined to be near an integer while 2.25 is not (but the float preceding 2.25 is). It also might be subject to more optimizations ;). For N=1, this function always returns true (duh ;))
C++ addict
-
Currently working on: the 3D engine for Tomb Raider.

#7 Nils Pipenbrinck

    Senior Member

  • Members
  • PipPipPipPip
  • 597 posts

Posted 19 February 2007 - 10:59 PM

Thanks, mates.

Oisyns code looks pretty good for my requirement. I think working out an estimate about the integer nearness over the mantissa would have been the way to go. However, it's not relevant for me anymore. I've used the detection code as posted at the thread start and I delivered today, so there is no chance to change it anymore.

In practice it's no bottleneck (also it still is slower than it could be). I was more an academic challenge and I was curious what you guys would come up with.

I like booth ways. Oisyn cracks the number into the component, and Nick does the arithmetic thing. Neat solutions.

Nils





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users