[ 최신 업데이트 : 벤치 마크 프로그램 및 예비 자료 제공, 아래 참조]
따라서 고전적인 응용 프로그램 인 정렬과 함께 속도 / 복잡성 트레이드 오프를 테스트하고 싶습니다.
부동 소수점 숫자의 배열을 오름차순으로 정렬하는 ANSI C 함수를 작성하십시오 .
당신이 사용할 수 있는 라이브러리, 시스템 호출, 멀티 스레딩 또는 인라인 ASM을.
출품작은 코드 길이 와 성능 이라는 두 가지 구성 요소로 판단됩니다 . 다음과 같이 점수가 매겨집니다. 항목은 길이 (공백이없는 # 문자 로그이므로 일부 서식을 유지할 수 있음) 및 성능 (벤치 마크에서 # 초 로그) 및 각 간격 [최고, 최악]에 따라 선형으로 [ 0,1]. 프로그램의 총점은 정규화 된 두 점수의 평균입니다. 최저 점수가 이깁니다. 사용자 당 하나의 항목.
정렬은 (결과적으로) 제자리에 있어야하며 (즉, 입력 배열은 반환 시간에 정렬 된 값을 포함해야 함) 이름을 포함하여 다음 서명을 사용해야합니다.
void sort(float* v, int n) {
}
계산할 문자 : sort
함수의 문자 , 서명 포함 및 추가 함수 (테스트 코드는 포함되지 않음)
프로그램은 float
2 ^ 20까지의 길이가 0보다 큰 숫자 값 과 배열을 처리해야합니다 .
sort
테스트 프로그램에 플러그인 과 그 의존성을 연결 하고 GCC를 컴파일합니다 (공상 옵션 없음). 여기에 여러 배열을 공급하고 결과의 정확성과 총 런타임을 확인합니다. 테스트는 Ubuntu 13에서 Intel Core i7 740QM (Clarksfield)에서 실행됩니다.
어레이 길이는 허용되는 전체 범위에 걸쳐 있으며 밀도가 높은 짧은 어레이입니다. 팻 테일 분포 (양수 및 음수 범위 모두)로 값이 임의적입니다. 일부 요소에는 중복 요소가 포함됩니다.
테스트 프로그램은 여기 ( https://gist.github.com/anonymous/82386fa028f6534af263 )에서 제공
됩니다 user.c
. TEST_COUNT
실제 벤치 마크에서 테스트 사례 수 ( )는 3000입니다. 질문 의견에 의견을 보내주십시오.
마감일 : 3 주 (2014 년 4 월 7 일 16:00 GMT). 2 주 후에 벤치 마크를 게시하겠습니다.
경쟁 업체에 코드를 제공하지 않으려면 마감일 가까이에 게시하는 것이 좋습니다.
벤치 마크 게시 시점의 예비 결과 :
다음과 같은 결과가 있습니다. 마지막 열에는 점수가 백분율로 표시되며, Johnny Cage가 우선 순위가 높아질수록 좋습니다. 나머지보다 훨씬 느린 알고리즘은 테스트의 하위 세트에서 실행되었고 시간은 외삽되었습니다. C는 자신의 qsort
비교를 위해 포함되었습니다 (Johnny는 빠릅니다!). 마감 시간에 최종 비교를 수행하겠습니다.
답변
150 자
퀵 정렬.
/* 146 character.
* sizeup 1.000; speedup 1.000; */
#define REC_SIZE \
sort(l, v+n-l); \
n = l-v;
/* 150 character.
* sizeup 1.027; speedup 1.038; */
#define REC_FAST \
sort(v, l-v); \
n = v+n-l; \
v = l;
void sort(float* v, int n)
{
while ( n > 1 )
{
float* l = v-1, * r = v+n, x = v[n/2], t;
L:
while ( *++l < x );
while ( x < (t = *--r) );
if (l < r)
{
*r = *l; *l = t;
goto L;
}
REC_FAST
}
}
압축.
void sort(float* v, int n) {
while(n>1){float*l=v-1,*r=v+n,x=v[n/2],t;L:while(*++l<x);while(x<(t=*--r));if(l<r){*r=*l;*l=t;goto L;}sort(v,l-v);n=v+n-l;v=l;}
}
답변
150 자 (공백 제외)
void sort(float *v, int n) {
int l=0;
float t, *w=v, *z=v+(n-1)/2;
if (n>0) {
t=*v; *v=*z; *z=t;
for(;++w<v+n;)
if(*w<*v)
{
t=v[++l]; v[l]=*w; *w=t;
}
t=*v; *v=v[l]; v[l]=t;
sort(v, l++);
sort(v+l, n-l);
}
}
답변
67 70 69 자
전혀 빠르지는 않지만 엄청나게 작습니다. 선택 정렬과 거품 정렬 알고리즘 사이의 하이브리드입니다. 실제로이 내용을 읽으려고하는 ++i-v-n
경우와 동일 하다는 것을 알아야합니다 ++i != v+n
.
void sort(float*v,int n){
while(n--){
float*i=v-1,t;
while(++i-v-n)
*i>v[n]?t=*i,*i=v[n],v[n]=t:0;
}
}
답변
123 자 (+3 줄 바꿈)
압축 된 표준 셸 정렬입니다.
d,i,j;float t;
void sort(float*v,int n){
for(d=1<<20;i=d/=2;)for(;i<n;v[j]=t)for(t=v[j=i++];j>=d&&v[j-d]>t;j-=d)v[j]=v[j-d];
}
추신 : 여전히 퀵 정렬보다 10 배 느립니다. 이 항목을 무시해도됩니다.
답변
395 자
Mergesort.
void sort(float* v,int n){static float t[16384];float*l,*r,*p,*q,*a=v,*b=v+n/2,
*c=v+n,x;if(n>1){sort(v,n/2);sort(v+n/2,n-n/2);while(a!=b&&b!=c)if(b-a<=c-b&&b-
a<=16384){for(p=t,q=a;q!=b;)*p++=*q++;for(p=t,q=t+(b-a);p!=q&&b!=c;)*a++=(*p<=
*b)?*p++:*b++;while(p!=q)*a++=*p++;}else{for(l=a,r=b,p=t,q=t+16384;l!=b&&r!=c&&
p!=q;)*p++=(*l<=*r)?*l++:*r++;for(q=b,b=r;l!=q;)*--r=*--q;for(q=t;p!=q;)*a++=
*q++;}}}
포맷되었습니다.
static float* copy(const float* a, const float* b, float* out)
{ while ( a != b ) *out++ = *a++; return out;
}
static float* copy_backward(const float* a, const float* b, float* out)
{ while ( a != b ) *--out = *--b; return out;
}
static void ip_merge(float* a, float* b, float* c)
{
/* 64K (the more memory, the better this performs). */
#define BSIZE (1024*64/sizeof(float))
static float t[BSIZE];
while ( a != b && b != c )
{
int n1 = b - a;
int n2 = c - b;
if (n1 <= n2 && n1 <= BSIZE)
{
float* p = t, * q = t + n1;
/* copy [a,b] sequence. */
copy(a, b, t);
/* merge. */
while ( p != q && b != c )
*a++ = (*p <= *b) ? *p++ : *b++;
/* copy remaining. */
a = copy(p, q, a);
}
/* backward merge omitted. */
else
{
/* there are slicker ways to do this; all require more support
* code. */
float* l = a, * r = b, * p = t, * q = t + BSIZE;
/* merge until sequence end or buffer end is reached. */
while ( l != b && r != c && p != q )
*p++ = (*l <= *r) ? *l++ : *r++;
/* compact remaining. */
copy_backward(l, b, r);
/* copy buffer. */
a = copy(t, p, a);
b = r;
}
}
}
void sort(float* v, int n)
{
if (n > 1)
{
int h = n/2;
sort(v, h); sort(v+h, n-h); ip_merge(v, v+h, v+n);
}
}
답변
331 326 327 자
기수가 한 번에 8 비트를 정렬합니다. 멋진 비트 핵을 사용하여 음수 부동 소수점을 올바르게 정렬합니다 ( http://stereopsis.com/radix.html 에서 도난 당함 ). 그렇게 컴팩트하지는 않지만 실제로 빠릅니다 (가장 빠른 예비 엔트리보다 ~ 8 배 빠름). 코드 크기가 빠른 코드 크기를 기대하고 있습니다 …
#define I for(i=n-1;i>=0;i--)
#define J for(i=0;i<256;i++)
#define R for(r=0;r<4;r++)
#define F(p,q,k) I p[--c[k][q[i]>>8*k&255]]=q[i]
void sort(float *a, int n) {
int *A = a,i,r,x,c[4][257],B[1<<20];
R J c[r][i]=0;
I {
x=A[i]^=A[i]>>31|1<<31;
R c[r][x>>8*r&255]++;
}
J R c[r][i+1]+=c[r][i];
F(B,A,0);
F(A,B,1);
F(B,A,2);
F(A,B,3)^(~B[i]>>31|1<<31);
}
답변
511 424 문자
기수 정렬
업데이트 : 더 작은 어레이 크기에 대해 삽입 정렬로 전환합니다 (벤치 마크 성능이 4.0 배 증가).
#define H p[(x^(x>>31|1<<31))>>s&255]
#define L(m) for(i=0;i<m;i++)
void R(int*a,int n,int s){if(n<64){float*i,*j,x;for(i=a+1;i<a+n;i++){x=*i;for(
j=i;a<j&&x<j[-1];j--)*j=j[-1];*j=x;}}else{int p[513]={},*q=p+257,z=255,i,j,x,t
;L(n)x=a[i],H++;L(256)p[i+1]+=q[i]=p[i];for(z=255;(i=p[z]-1)>=0;){x=a[i];while
((j=--H)!=i)t=x,x=a[j],a[j]=t;a[i]=x;while(q[z-1]==p[z])z--;}if(s)L(256)R(a+p[
i],q[i]-p[i],s-8);}}void sort(float* v,int n){R(v,n,24);}
포맷되었습니다.
/* XXX, BITS is a power of two. */
#define BITS 8
#define BINS (1U << BITS)
#define TINY 64
#define SWAP(type, a, b) \
do { type t=(a);(a)=(b);(b)=t; } while (0)
static inline unsigned int floatbit_to_sortable_(const unsigned int x)
{ return x ^ ((0 - (x >> 31)) | 0x80000000);
}
static inline unsigned int sortable_to_floatbit_(const unsigned int x)
{ return x ^ (((x >> 31) - 1) | 0x80000000);
}
static void insertsort_(unsigned int* a, unsigned int* last)
{
unsigned int* i;
for ( i = a+1; i < last; i++ )
{
unsigned int* j, x = *i;
for ( j = i; a < j && x < *(j-1); j-- )
*j = *(j-1);
*j = x;
}
}
static void radixsort_lower_(unsigned int* a, const unsigned int size,
const unsigned int shift)
{
/* @note setup cost can be prohibitive for smaller arrays, switch to
* something that performs better in these cases. */
if (size < TINY)
{
insertsort_(a, a+size);
return;
}
unsigned int h0[BINS*2+1] = {}, * h1 = h0+BINS+1;
unsigned int i, next;
/* generate histogram. */
for ( i = 0; i < size; i++ )
h0[(a[i] >> shift) % BINS]++;
/* unsigned distribution.
* @note h0[BINS] == h1[-1] == @p size; sentinal for bin advance. */
for ( i = 0; i < BINS; i++ )
h0[i+1] += (h1[i] = h0[i]);
next = BINS-1;
while ( (i = h0[next]-1) != (unsigned int) -1 )
{
unsigned int x = a[i];
unsigned int j;
while ( (j = --h0[(x >> shift) % BINS]) != i )
SWAP(unsigned int, x, a[j]);
a[i] = x;
/* advance bins.
* @note skip full bins (zero sized bins are full by default). */
while ( h1[(int) next-1] == h0[next] )
next--;
}
/* @note bins are sorted relative to one another at this point but
* are not sorted internally. recurse on each bin using successive
* radii as ordering criteria. */
if (shift != 0)
for ( i = 0; i < BINS; i++ )
radixsort_lower_(a + h0[i], h1[i] - h0[i], shift-BITS);
}
void sort(float* v, int n)
{
unsigned int* a = (unsigned int*) v;
int i;
for ( i = 0; i < n; i++ )
a[i] = floatbit_to_sortable_(a[i]);
radixsort_lower_(a, n, sizeof(int)*8-BITS);
for ( i = 0; i < n; i++ )
a[i] = sortable_to_floatbit_(a[i]);
}