[ create a new paste ] login | about

Link: http://codepad.org/rNFwZF8E    [ raw code | output | fork ]

C++, pasted on Oct 21:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>

struct Photon {
	float pos[3];
};

int nswap;
#define	swap(ph, a, b) { Photon *ph2=ph[a]; ph[a]=ph[b]; ph[b]=ph2; ++nswap; }

void median_split(Photon** p, int start, int end, int median, int axis) {
	int left = start;
	int right = end;

	while (right > left) {
		const float v = p[(left+right)/2]->pos[axis];
		int i = left-1;
		int j = right;
		for (;;) {
			while (p[++i]->pos[axis] < v);
			while (p[--j]->pos[axis] > v);
			if (i >= j) break;
			swap(p, i, j);
		}

		if (i >= median)	right = i-1;
		if (i <= median)	left = i+1;
	}
}

void median_split_using_qsort(Photon** p, int start, int end, int axis) {
	int i, j;
	float x;

	x = p[(start + end) / 2]->pos[axis];
	i = start; j = end;
	for (;;) {
		while (p[i]->pos[axis] < x) ++i;
		while (x < p[j]->pos[axis]) --j;
		if (i >= j) break;
		Photon* t = p[i]; p[i] = p[j]; p[j] = t;
		++i; --j;
	}
	if (start < i-1) median_split_using_qsort(p, start, i-1, axis);
	if (j+1 < end)   median_split_using_qsort(p, j+1, end, axis);
}

void balance_segment(Photon** pbal, Photon** porg, int index, int start, int end) {
	//--------------------
	// compute new median
	//--------------------

	int median = 1;
	while ((4*median) <= (end-start+1))
		median += median;

	if ((3*median) <= (end-start+1))
		median = median * 2 + start-1;
	else
		median = end-median+1;

	//--------------------------
	// find axis to split along
	//--------------------------

	int axis = (rand() >> 8) % 3;

	//------------------------------------------
	// partition photon block around the median
	//------------------------------------------

	median_split(porg, start, end, median, axis);
//	median_split_using_qsort(porg, start, end, axis);

	pbal[index] = porg[median];

	//----------------------------------------------
	// recursively balance the left and right block
	//----------------------------------------------

	if (median > start) {
		// balance left segment
		if (start < median-1) {
			balance_segment(pbal, porg, 2*index, start, median-1);
		} else {
			pbal[2*index] = porg[start];
		}
	}

	if (median < end) {
		// balance right segment
		if (median+1 < end) {
			balance_segment(pbal, porg, 2*index+1, median+1, end);
		} else {
			pbal[2*index+1] = porg[end];
		}
	}
}

float randf() {
	return rand() / ((float)RAND_MAX+1);
}

#ifdef _MSC_VER
const double log_2 = log(2.0);
double log2(double x) {
	return log(x) / log_2;
}
#endif

int main(int argc, char* argv[]) {
	srand(time(NULL));
	int N = 100;

	if (argc > 1) {
		N = atoi(argv[1]);
	}

	Photon* buf = new Photon[N+1];
	Photon** porg = new Photon*[N+1];
	Photon** pbal = new Photon*[N+1];
	for (int i=1; i<=N; ++i) {
		Photon* p = &buf[i];
		p->pos[0] = randf();
		p->pos[1] = randf();
		p->pos[2] = randf();

		porg[i] = p;
	}

	balance_segment(pbal, porg, 1, 1, N);

	double r = N * log2((double)N) / 2;
	printf("#photon:%d, #swap:%d, n.log2(n)/2:%d\n", N, nswap, (int)r);

	delete[] buf;
	delete[] porg;
	delete[] pbal;
}


Output:
1
#photon:100, #swap:181, n.log2(n)/2:332


Create a new paste based on this one


Comments: