rsort.h
#if !defined(CGL_RSORT_H)
# define CGL_RSORT_H
#include "config.h"
#include <vector>
namespace cgl {
class rsort
{
public :
rsort & sort(const int * data_p, unsigned int size);
rsort & sort(const float * data_p, unsigned int size);
const std::vector<unsigned int> & pos() const { return positions; }
private :
unsigned int counters[4 * 256];
unsigned int offsets [256];
std::vector<unsigned int> positions;
};
} // cgl
rsort.cpp
#include "rsort.h"
#include <assert.h>
cgl::rsort &
cgl::rsort::sort(const int * data_p, unsigned int size)
{
assert(data_p && size); // FAILURE: null input
// clear counters
for(unsigned int i = 0; i < 4 * 256; ++i) counters[i] = 0;
// init positions
if(positions.size() < size)
for(unsigned int i = 0; i < size; ++i) positions.push_back(i);
bool already_sorted = true;
int negvals = 0;
for(unsigned int i = 0; i < size; ++i)
{
// check for sorted input
if(i && data_p[i] < data_p[i-1])
already_sorted = false;
// check for presence of negative values
if(data_p[i] < 0)
negvals++;
// init counters for all 4 passes
++counters[0 + ((data_p[i] & 0x000000ff) >> 0)];
++counters[256 + ((data_p[i] & 0x0000ff00) >> 8)];
++counters[512 + ((data_p[i] & 0x00ff0000) >> 16)];
++counters[768 + ((data_p[i] & 0xff000000) >> 24)];
}
if(already_sorted)
return *this;
std::vector<unsigned int> new_positions(positions.size());
for(int pass = 0; pass < 4; ++pass)
{
if(!negvals || pass < 3)
{
// compute offsets
offsets[0] = 0;
for(int i = 1; i < 256; ++i)
offsets[i] = offsets[i - 1] + counters[(pass << 8) + i - 1];
}
else
{
// positive values' offsets are biased to be sorted
// in positions after negative values
offsets[0] = negvals;
for(int i = 1; i < 128; ++i)
offsets[i] = offsets[i - 1] + counters[(pass << 8) + i - 1];
offsets[128] = 0;
for(int i = 129; i < 256; ++i)
offsets[i] = offsets[i - 1] + counters[(pass << 8) + i - 1];
}
// sort positions
for(unsigned int i = 0; i < size; ++i)
{
unsigned int pos = positions[i];
unsigned int bval = (data_p[pos] >> (8 * pass)) & 0xff;
new_positions[offsets[bval]++] = pos;
}
// save new positions for the next pass
positions.swap(new_positions);
}
return *this;
}
// IEEE floats are required for the following to work
// an IEEE float is a 32-bit number with the following structure:
// [sign-1bit|exponent-8bits|mantissa-23bits]
// sign bit is set for negative values; exponent is biased and
// thus can be treated as always positive
cgl::rsort &
cgl::rsort::sort(const float * data_p, unsigned int size)
{
assert(data_p && size); // FAILURE: null input
// clear counters
for(unsigned int i = 0; i < 4 * 256; ++i) counters[i] = 0;
// init positions
if(positions.size() < size)
for(unsigned int i = 0; i < size; ++i) positions.push_back(i);
bool already_sorted = true;
int negvals = 0;
for(unsigned int i = 0; i < size; ++i)
{
// check for sorted input
if(i && data_p[i] < data_p[i-1])
already_sorted = false;
// check for presence of negative values
if(data_p[i] < 0)
negvals++;
// init counters for all 4 passes
unsigned int f2ui = *reinterpret_cast(&data_p[i]);
++counters[0 + ((f2ui & 0x000000ff) >> 0)];
++counters[256 + ((f2ui & 0x0000ff00) >> 8)];
++counters[512 + ((f2ui & 0x00ff0000) >> 16)];
++counters[768 + ((f2ui & 0xff000000) >> 24)];
}
if(already_sorted)
return *this;
std::vector<unsigned int> new_positions(positions.size());
for(int pass = 0; pass < 4; ++pass)
{
if(pass < 3)
{
// compute offsets
offsets[0] = 0;
for(int i = 1; i < 256; ++i)
offsets[i] = offsets[i - 1] + counters[(pass << 8) + i - 1];
// sort positions
for(unsigned int i = 0; i < size; ++i)
{
unsigned int pos = positions[i];
unsigned int bval = (*reinterpret_cast(&data_p[pos]) >> (8 * pass)) & 0xff;
new_positions[offsets[bval]++] = pos;
}
}
else
{
// positive values' offsets are biased to be
// sorted in positions after negative values
offsets[0] = negvals;
for(int i = 1; i < 128; ++i)
offsets[i] = offsets[i - 1] + counters[768 + i - 1];
// negative values must have a reversed sorting order
// (higher the exponent lower the position)
offsets[255] = 0;
for(int i = 254; i >= 128; --i)
offsets[i] = offsets[i + 1] + counters[768 + i + 1];
// radix sort is stable
for(int i = 128; i < 256; ++i)
offsets[i] += counters[768 + i];
// sort positions
for(unsigned int i = 0; i < size; ++i)
{
unsigned int pos = positions[i];
unsigned int bval = *reinterpret_cast(&data_p[pos]) >> 24;
if(bval < 128) // positive/negative
new_positions[offsets[bval]++] = pos;
else
new_positions[--offsets[bval]] = pos;
}
}
// save new positions for the next pass
positions.swap(new_positions);
}
return *this;
}
© 2002-4 Marek Trefny