5

I need a optimized binary search algorithm on a array of sorted numbers. I did this and found that using float to store numbers is faster than using integer, because at the end i must calculate

(frameNumber-this->frameNumber[imin])/(this->frameNumber[imax]-this->frameNumber[imin])

this->frameNumber[imin] is the biggest frameNumber less equal that frameNumber and this->frameNumber[imax] is the smallest one greater equal than that. That code is to calculate the progress between that two keyframes. the frameNumber array is static. I only have to sort it once. But access it many times with a binary search and the above code to calculate the progress.

The conversion from int to float spent some cycles. Then I discovered that in the asm there a a lot of fpu instructions. I'm worrying they might be slower than integer.

So here is the question. Can I convert an array of sorted floating point numbers to an int* and run a binary search on it?

That means:

void binary_search(float key,float* array,...)
{
    int key_integer=*(int*)&key;
    int* array_intege(int*)array;
    binary_search_for_integers(key_integer,array_integer,...);
}

Or my above conclusion are wrong? (Such as casting int to float is not so costy, or comparision between floating points is the same fast as integers?

Thanks a lot!

  • 2
    Your question isn't clear, but the straight answer is no you can't convert an array like this. – Amit Jul 31 '15 at 21:54
  • 5
    Normally, this will not work -- it will interpret each element's bits as ints instead of floats. However, there is an interesting quirk with IEEE floating point that they preserve ordering if interpreted as integers of the same length. So your binary search could actually work if `sizeof(int)==sizeof(float)` on your system and none of the values are NaN. But it's not guaranteed by the C or C++ standards. – rlbond Jul 31 '15 at 21:56
  • 1
    It also doesn't work for negative numbers. – fangzhangmnm Jul 31 '15 at 22:03
  • After some testing on my machine, it works in VS2012 if the values in the float array are all positive. Negative values will be in reverse order (this is because floats use a sign bit instead of two's complement). EDIT: Looks like you beat me to that caveat. – rlbond Jul 31 '15 at 22:04
  • @fangzhangmnm: Are you doing `(frameNumber-this->frameNumber[imin])/(this->frameNumber[imax]-this->frameNumber[imin])` at the end? – Jeremiah Dicharry Jul 31 '15 at 22:15
  • Can you explain more about C standards? It seems that libraries like Bullet and Ogre defined their own floats. I found int32_t in . But is float always 32-bit? thanks – fangzhangmnm Jul 31 '15 at 22:21
  • @JeremiahDicharry Yes. Do you mean I should use integer arrays and integer diversions such as `((float)(((a-b)<<4)/(c-b)))*16.0f` ? – fangzhangmnm Jul 31 '15 at 22:25
  • 1
    int32_t is 32-bits in C standard C99, but float size isn't defined, it just has to have a minimum range. https://en.wikipedia.org/wiki/C_data_types – Jeremiah Dicharry Jul 31 '15 at 22:28
  • @fangzhangmnm: Where are you doing the division? After the binary_search? – Jeremiah Dicharry Jul 31 '15 at 22:32
  • @JeremiahDicharry Yes. After I find the keyframes before and after current frame I could interpolate them using the result of that division. In addition, the length of each timeline is about 1-300. – fangzhangmnm Jul 31 '15 at 22:39
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/84853/discussion-between-jeremiah-dicharry-and-fangzhangmnm). – Jeremiah Dicharry Jul 31 '15 at 22:44

1 Answers1

4

This seems like a bad idea. Using integer compares on float data actually will result in a correctly ordered array of floats, as @rlbond points out. (See http://www.h-schmidt.net/FloatConverter/IEEE754.html to play with the binary representations of floats.) Check that sizeof(int32_t) == sizeof(float) before using this.

A hack like this is not really needed. float comparison is not much more expensive than int comparison, on modern hardware. (Intel Haswell: ucomiss is 1 uop, with 1 per cycle throughput. Comparing with a memory operand is 2 uops, no micro-fusion, though. And it can't macro-fuse like cmp/jcc) However, FP add/sub and FP mul have higher latencies than their integer equivalents, and less throughput. It seems silly to convert a whole array to float as you're writing to it just because you want to do some FP math with the min and max values at the end.

A load-and-convert-int-to-float instruction (x86 cvtsi2ss (signed-integer 2 scalar single)) is about as fast, and takes the same code space, as a normal load (movss).

If your data originally was integer, and you only use some of it, use int (avoiding the conversion for values you never need later). If you do access all of it, and only ever use your data as floats, then store it as float. If you use it as both, it's probably best to store it as int, so it's faster when you do use it as integer, and about the same speed either way when you use it as float.

From your code sample, you're just using the values at the min and max positions? It's a lot faster to find the min and max values in an array than it is to sort the whole array. min/max even vectorizes with packed-min instructions.

Many platforms don't have as fast floating point as modern Intel CPUs, so don't go overboard with floating point.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Nonono not min and max values. I modified the code from [link](https://en.wikipedia.org/wiki/Binary_search_algorithm) and imin and imax are just two iterators. 'this->frameNumber[imin]' is the biggest frameNumber less equal that 'frameNumber' and 'this->frameNumber[imax]' is the smallest one greater equal than that. That code is to calculate the progress between that two keyframes. So I will use all of it only as floats. That data is static. I only need to sort and convert it as it is loaded from hard disc. – fangzhangmnm Jul 31 '15 at 23:44