Golfed+Fast sorting in C

11

4

[Latest update: benchmark program and preliminary resuls available, see below]

So I want to test the speed/complexity tradeoff with a classic application: sorting.

Write an ANSI C function that sorts an array of floating point numbers in increasing order.

You can't use any libraries, system calls, multithreading or inline ASM.

Entries judged on two components: code length and performance. Scoring as follows: entries will be sorted by length (log of #characters without whitespace, so you can keep some formatting) and by performance (log of #seconds over a benchmark), and each interval [best,worst] linearly normalised to [0,1]. The total score of a program will be the average of the two normalised scores. Lowest score wins. One entry per user.

Sorting will have to (eventually) be in place (i.e. the input array will have to contain sorted values at return time), and you must use the following signature, including names:

void sort(float* v, int n) {

}

Characters to be counted: those in the sort function, signature included, plus additional functions called by it (but not including testing code).

The program must handle any numeric value of float and arrays of length >=0, up to 2^20.

I'll plug sort and its dependencies into a testing program and compile on GCC (no fancy options). I'll feed a bunch of arrays into it, verify correctness of results and total run time. Tests will be run on an Intel Core i7 740QM (Clarksfield) under Ubuntu 13.
Array lengths will span the whole allowed range, with a higher density of short arrays. Values will be random, with a fat-tail distribution (both in the positive and negative ranges). Duplicated elements will be included in some tests.
The test program is available here: https://gist.github.com/anonymous/82386fa028f6534af263
It imports the submission as user.c. The number of test cases (TEST_COUNT) in the actual benchmark will be 3000. Please provide any feedback in the question comments.

Deadline: 3 weeks (7 April 2014, 16:00 GMT). I will post the benchmark in 2 weeks.
It may be advisable to post close to the deadline to avoid giving away your code to competitors.

Preliminary results, as of benchmark publication:
Here are some results. The last column shows the score as a percentage, the higher the better, putting Johnny Cage in first place. Algorithms that were orders of magnitude slower than the rest were run on a subset of tests, and time extrapolated. C's own qsort is included for comparison (Johnny's is faster!). I'll perform a final comparison at closing time.

enter image description here

Mau

Posted 2014-03-14T17:11:54.770

Reputation: 1 654

3Can you provide the benchmark? Different sorting functions perform differently based on the nature of the data. E.g. bubble sort is faster than the stdlib quicksort for tiny arrays. We might like to optimize for your benchmark. – Claudiu – 2014-03-14T17:20:57.793

@Claudiu I once saw a lovely short version of quicksort, that ran just as well as any other on data where every element was different. But if some elements were the same, it ran at an absolute snail's pace. I'm not talking about the known issue of bad choice of pivot in sorted / partially sorted arrays. My test data was completely randomly shuffled. This particular version just didn't like duplicates. Weird, but true. – Level River St – 2014-03-14T17:37:14.583

I haven't written it yet :-) See edit though. – Mau – 2014-03-14T17:37:54.617

Ok if you want to have a metric that considers both length and runtime, but it's not clear how much weight you're putting on each. length * runtime might be clearer than xlength + yruntime, where x and y are unknown to us. – Level River St – 2014-03-14T17:42:17.937

@steveverrill: x and y are 1 (same weight). length and runtime are normalised based on best and worst entries in each category. Is there any unfairness in this? – Mau – 2014-03-14T17:45:37.147

3Welcome to PPCG! While we don't prohibit language-specific challenges, we do strongly encourage formulating questions in a language-agnostic manner whenever possible. Consider it for your next question, and have fun with this one! – Jonathan Van Matre – 2014-03-14T17:55:35.113

X in characters? ok. Y in milliseconds? seconds? hours? weeks? On your machine or on mine? A short slow program will do well if you measure in hours, and a long fast one if you measure in milliseconds. Hence my suggested metric of length*time which if you log it becomes log(length)+log(time) so your units of time and the speed of your machine become irrelevant. – Level River St – 2014-03-14T17:55:53.837

@JonathanVanMatre: thank you! steveverrill: normalisation makes it machine independent already, but you have a point about the possibility of a large range of different values. Changing the scoring. – Mau – 2014-03-14T18:02:55.927

@Mau It doesn't make it machine independent. It just makes it a little less dependent on processor speed. It does not take into account different amounts of registers, caches, out-of-order execution, ... – Howard – 2014-03-14T18:45:39.280

1@steveverrill: I don't follow. It doesn't matter what your unit is because you scale it from 0 to 1 anyway. If min is 1 hour and max is 3 hours, something that takes 1.5 hours will be 0.25 regardless of whether min is 60 minutes, max is 180 minutes, and it takes 90 minutes – Claudiu – 2014-03-14T19:13:33.900

@Howard: fair enough, but all programs will be run on the same machine. – Mau – 2014-03-14T22:10:50.807

Can we use SSE instructions ? – Michael M. – 2014-03-14T23:57:33.530

@Michael I'm sure OP will compile with -march=native, but, as stated in the rules, you cannot use inline assembly – mniip – 2014-03-15T05:12:09.860

No inline assembly :) – Mau – 2014-03-15T11:52:34.637

@Mau Can I use void sort(float values[],int n) ? I feel more comfortable in that and I guess that both are same BTW. – Mukul Kumar – 2014-03-16T03:01:14.440

1OP only said no inline assembly - he didn't say anything about intrinsics. – Paul R – 2014-03-16T09:11:10.220

Any minimum size? Can it fail if n=0? – Florian F – 2014-03-16T18:11:41.667

Well I'd say n=0 should be covered, like in any well-behaved algorithm :) – Mau – 2014-03-16T22:06:57.910

You should clarify whether the mandatory function signature is included in the count of "those in the sort function". There are entries counting each way. – Jonathan Van Matre – 2014-03-19T11:51:17.820

@JonathanVanMatre: thanks, edited. – Mau – 2014-03-19T13:48:34.610

It's probably not a big deal, but which Ubuntu 13? – Kendall Frey – 2014-03-20T13:09:00.477

13.10. Stock. With the yellow salamander as background. – Mau – 2014-03-20T13:57:20.660

Really looking forward to seeing how these perform! – Claudiu – 2014-03-26T22:03:33.253

So any Whitespace program will have a score of −∞, because the logarithm of zero tends to negative infinity? – wchargin – 2014-03-27T23:23:54.090

@WChargin any Whitespace program would not make it to the test bench :) – Mau – 2014-03-27T23:26:55.843

Your benchmark should not allow this: void sort(float*v,int n){ while(n--) *v++=0; } – Florian F – 2014-04-05T19:29:36.717

O(n) performance would stand out too much :) – Mau – 2014-04-05T19:59:26.127

So? No final results? – Florian F – 2014-05-11T12:08:54.947

Sorry guys, Linux box died :( One on its way soon. I took a snapshot of submission as of deadline. Will be up soon! – Mau – 2014-05-11T13:26:34.513

Answers

6

150 character

Quicksort.

/* 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
     }
}

Compressed.

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;}
}

Johnny Cage

Posted 2014-03-14T17:11:54.770

Reputation: 71

Leading the race! – Mau – 2014-03-31T09:49:30.410

3

150 chars (without whitespaces)

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);
    }
}

Michael M.

Posted 2014-03-14T17:11:54.770

Reputation: 12 173

Awesome, first entry! – Mau – 2014-03-15T15:39:45.817

Feel free to post an answer with SSE and I'll list it in the scoreboard, though I'm interested in 'portable' solutions for the challenge. – Mau – 2014-03-15T21:10:48.307

if(*w<*v) { t=v[++l]; v[l]=*w; *w=t; } can be if(*w<*v) t=v[++l], v[l]=*w, *w=t; – ASKASK – 2014-03-17T01:43:57.993

3

67 70 69 chars

Not fast at all, but incredibly small. It's a hybrid between a selection sort and bubble sort algorithm I guess. If you are actually trying to read this, then you should know that ++i-v-n is the same as ++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;
    }
}

ASKASK

Posted 2014-03-14T17:11:54.770

Reputation: 291

if(a)b -> a?b:0 saves a char. – ugoren – 2014-03-27T20:16:46.683

Well, ++i-v-n is the same as ++i != v+n only in a conditional, of course. – wchargin – 2014-03-27T23:25:05.840

@ugoren i think you posted that comment on the wrong answer – ASKASK – 2014-03-28T01:06:54.227

@ASKASK, if(*i>v[n])... -> *i>v[n]?...:0 – ugoren – 2014-03-29T12:52:22.610

are you sure that is how the prescedence works? – ASKASK – 2014-03-29T18:36:15.300

would it be seen as (*i<v[n])?...:0 or as *i<(v[n]?...:0) – ASKASK – 2014-03-29T18:36:56.267

@ASKASK: declaring variables inside the loop is not ANSI-compliant, so it won't compile on GCC without special options. Could you fix it? Ta. – Mau – 2014-03-29T22:18:44.790

@mau i just fixed it – ASKASK – 2014-03-30T04:30:25.340

@Mau doesn't everyone have to deal with floating point operations? – ASKASK – 2014-03-30T18:48:17.310

I'm still confused... why would it? Also, what indicies are you reffering to? – ASKASK – 2014-03-30T18:55:16.410

Sorry, i was talking rubbish :o I read a float* as float I'll delete my comment – Mau – 2014-03-30T19:01:37.140

@ASKASK This case doesn't seem to terminate: https://gist.github.com/anonymous/d6b9b4b2fa6aa4148777

– Mau – 2014-03-30T19:20:59.703

To be honest I think it is just taking a really really long time, after all this is a very inefficient algorithm – ASKASK – 2014-03-30T21:44:55.667

Yep, that's right... – Mau – 2014-03-30T22:39:51.997

2

123 chars (+3 newlines)

A standard Shell sort, compressed.

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];
}  

PS: discovered it is still 10x slower than quicksort. You might as well ignore this entry.

Florian F

Posted 2014-03-14T17:11:54.770

Reputation: 591

Your choice of gaps could be better. Thats probably why this is a lot slower than quicksort. http://en.wikipedia.org/wiki/Shellsort#Gap_sequences

– FDinoff – 2014-03-16T17:18:48.287

I was amazed to discover how much the gap sequence affects the speed. With a good sequence it comes close to quicksort but remains slower in my experience. – Florian F – 2014-03-19T09:55:17.257

Don't be too hard on yourself. You're in third place. – Kevin – 2014-04-03T20:27:37.610

2

511 424 character

Inplace radixsort

Update: Switches to insertion sort for smaller array sizes (increases benchmark performance by a factor of 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);}

Formatted.

/* 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]);
}

MojoJojoBojoHojo

Posted 2014-03-14T17:11:54.770

Reputation: 23

Nice! Try flagging the original answer. – Mau – 2014-03-31T16:48:50.500

@Mau: Thanks and will do. Wanted to mention an error in the benchmarking code. The cast to void* in qsort (line 88) is throwing off the pointer arithmetic. – MojoJojoBojoHojo – 2014-03-31T16:57:52.397

2

395 character

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++;}}}

Formatted.

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);
     }
}

Knucklesandwich

Posted 2014-03-14T17:11:54.770

Reputation: 21

2

331 326 327 312 chars

Does radix sort 8 bits at a time. Uses a fancy bithack to get negative floats to sort correctly (stolen from http://stereopsis.com/radix.html). It's not that compact, but it is really fast (~8x faster than the fastest prelim entry). I'm hoping for speed trumping code size...

#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);
}

Keith Randall

Posted 2014-03-14T17:11:54.770

Reputation: 19 865

1

154 166 characters

OK, here is a longer but faster quicksort.

void sort(float*v,int n){while(n>1){float*j=v,*k=v+n-1,t=*j;while(j<k){while(j<k&&*k>=t)k--;*j=*k;while(j<k&&*j<t)j++;*k=*j;}*k++=t;sort(k,v+n-k);n=j-v;}}

Here is a correction to survive sorted inputs. And formatted since white space doesn't count.

void sort(float*v, int n){
    while(n>1){
        float*j=v, *k=j+n/2, t=*k;
        *k = *j;
        k = v+n-1;
        while(j<k){
            while(j<k && *k>=t) k--;
            *j=*k;
            while(j<k && *j<t) j++;
            *k=*j;
        }
        *k++ = t;
        sort(k,v+n-k);
        n = j-v;
    }
}

Florian F

Posted 2014-03-14T17:11:54.770

Reputation: 591

This version seems to write out of bounds in some cases, not terminating in others. – Mau – 2014-03-31T06:48:51.413

PS: OK, it is very slow on a sorted set. But the problem statement says the input is random. – Florian F – 2014-04-02T20:53:20.057

The values are random. I never said anything about what order they'd be in :-) But yes, there are chunks covering about 10% of all values sorted in ascending order and another 10% in descending order. – Mau – 2014-04-03T10:37:27.157

1Fair enough. And a sort() should work on sorted input. I'll update my submission, then... – Florian F – 2014-04-03T20:02:10.820

1

121 114 111 characters

Just a quick-and-dirty bubblesort, with recursion. Probably not very efficient.

void sort(float*v,int n){int i=1;float t;for(;i<n;i++)v[i-1]>(t=v[i])&&(v[i]=v[i-1],v[i-1]=t);n--?sort(v,n):0;}

Or, the long version

void sort(float* values, int n) {
  int i=1;  // Start at 1, because we check v[i] vs v[i-1]
  float temp;
  for(; i < n; i++) {
    // If v[i-1] > v[i] is true (!= 0), then swap.
    // Note I am assigning values[i] to temp here. Below I want to use commas
    // so the whole thing fits into one statement, but if you assign temp there you will get sequencing issues (i.e unpredictable swap results)
    values[i - 1] > (temp = values[i]) && (
    // I tried the x=x+y,y=x-y,x=x-y trick, but using a temp
    // turns out to be shorter even if we have to declare the t variable.
      values[i] = values[i - 1], 
      values[i - 1] = temp);
  }

  // If n == 1, we are done. Otherwise, sort the first n - 1 elements recursively. 
  // The 0 is just because the third statement cannot be empty.
  n-- ? sort(values, n) : 0;
}

CompuChip

Posted 2014-03-14T17:11:54.770

Reputation: 439

As an aside, I found a really interesting algorithm here: http://rosettacode.org/wiki/Sorting_algorithms/Pancake_sort#C

But I cannot get it compressed enough to beat 114 :)

– CompuChip – 2014-03-17T18:58:39.073

your program seems to fail to complete in some cases and write out of bounds in other cases. – Mau – 2014-03-29T22:46:57.027

@Mau I tested it on some inputs manually and seemed to work ok, but due to lack of time I didn't test it very thouroughly so I am sure that there is some bad behavior somewhere. Could you post a test case where you ran into trouble please? – CompuChip – 2014-03-30T16:10:23.637

test program available above :) – Mau – 2014-03-30T16:26:18.287

Hmm I tried running it, I am getting some munmap_chunk(): invalid pointer errors in the cleanup part, but nothing about the test failing. However you are right that there is an off-by-one error, and I seem to have some sequencing issues (the comma-separated list of statements does not do what I expect it to). I'll try to fix it. – CompuChip – 2014-03-30T19:47:07.357

I get errors in deletion when a program write outside the bounds of the array (corrupting heap record?)... – Mau – 2014-03-30T19:54:19.107

Yeah, they are gone now. Updated the code. Thanks for reporting, hopefully it all works now! – CompuChip – 2014-03-30T19:56:41.897

That's right. Pretty slow though! :) – Mau – 2014-03-30T21:32:21.160

Yeah it's O(n^2). Pretty short as well, though :-) Maybe if I get inspiration I will write something faster. Still 7 days to go, right? – CompuChip – 2014-03-31T05:26:26.883

1

221 193 172 characters

Heapsort - Not the smallest, but in-place and guarantees O(n*log(n)) behavior.

static void sink(float* a, int i, int n, float t)
{
    float* b = a+i;

    for ( ; (i = i*2+2) <= n; b = a+i )
     {
       i -= (i == n || a[i] < a[i-1]) ? 1 : 0;

       if (t < a[i])
          *b = a[i];
       else
          break;
     }
    *b = t;
}

void sort(float* a, int n)
{
    int i;
    /* make. */
    for ( i = n/2-1; i >= 0; i-- )
       sink(a, i, n, a[i]);
    /* sort. */
    for ( i = n-1; i > 0; i-- )
     {
       float t = a[i]; a[i] = a[0];
       sink(a, 0, i, t);
     }
}

Compressed.

void sort(float* a,int n){
#define F(p,q,r,x,y) for(i=n/p;q>0;){t=a[i];r;for(j=x;(b=a+j,j=j*2+2)<=y&&(j-=(j==y||a[j]<a[j-1]),t<a[j]);*b=a[j]);*b=t;}
float*b,t;int i,j;F(2,i--,,i,n)F(1,--i,a[i]=*a,0,i)
}

user19425

Posted 2014-03-14T17:11:54.770

Reputation: 11

You can save some characters by deducting the whitespace. And possibly also the mandatory function signature, but since there are some entries that counted that I've asked questioner to clarify whether it should be counted. – Jonathan Van Matre – 2014-03-19T11:53:08.693

@user19425: If you run the test program with TEST_COUNT = 3000, it seems to fail at least one test. – Mau – 2014-03-30T19:50:13.740

1

C 270 (golfed)

#define N 1048576
void sort(float*v,int n)
{
float f[N],g;
int m[N],i,j,k,x;
g=v[0];k=0;
for(i=0;i<n;i++){for(j=0;j<n;j++){if(m[j]==1)continue;if(v[j]<g){g=v[j];k=j;}}f[i]=g;m[k]=1;for(x=0;x<n;x++){if(m[x]==0){g=v[x];k=x;break;}}}
for(i=0;i<n;i++){v[i]=f[i];}
}

Explanation: A blank array is used to store each successive minimum number. An int array is a mask with 0 indicating the number has not yet been copied. After getting the minimum value a mask=1 skips already used numbers. Then the array is copied back to original.

I changed the code to eliminate use of library functions.

bacchusbeale

Posted 2014-03-14T17:11:54.770

Reputation: 1 235

1

150 character

Shellsort (w/Knuth gap).

void sort(float* v, int n) {
float*p,x;int i,h=0;while(2*(i=h*3+1)<=n)h=i;for(;h>0;h/=3)for(i=h;i<n;i++){x=v[i];for(p=v+i-h;p>=v&&x<*p;p-=h)p[h]=*p;p[h]=x;}
}

Formatted.

static void hsort(float* v, const int h, const int n)
{
    int i;
    for (i = h; i < n; i++) {
        float* p, x = v[i];
        for (p = v + i-h; p >= v && x < *p; p -= h)
            p[h] = *p;
        p[h] = x;
    }
}

void sort(float* v, int n)
{
    int i, h = 0;
    while (2*(i = h*3+1) <= n)
        h = i;
    for (; h > 0; h /= 3)
        hsort(v, h, n);
}

SineDog

Posted 2014-03-14T17:11:54.770

Reputation: 11

0

144

I shamelessly took Johnny's code, added a tiny optimization and compressed the code in a very dirty way. It should be shorter and faster.

Note that depending on your compiler, sort(q,v+n- ++q) must be replaced by sort(++q,v+n-q).

#define w ;while(
void sort(float*v, int n){
    w n>1){
        float *p=v-1, *q=v+n, x=v[n/2], t
        w p<q){
            w *++p<x )
            w *--q>x );
            if( p<q ) t=*p, *p=*q, *q=t;
        }
        sort(q,v+n- ++q);
        n = p-v;
    }
}

Well, actually, I started form my code and optimized it, but it seems Johnny already made all the right choices. So I ended up with quasi his code. I didn't think of the goto trick, but I could do without.

Florian F

Posted 2014-03-14T17:11:54.770

Reputation: 591

0

228 character

Radixsort.

void sort(float* v, int n) {
#define A(x,y,z) for(x=y;x<z;x++)
#define B h[(a[i]^(a[i]>>31|1<<31))>>j*8&255]
    int m[1<<20],*a=v,*b=m,*t,i,j;
    A(j,0,4) {
        int h[256] = {};
        A(i,0,n) B++;
        A(i,1,256) h[i] += h[i-1];
        for (i = n-1; i >= 0; i--)
            b[--B] = a[i];
        t = a, a = b, b = t;
    }
}

Makarov

Posted 2014-03-14T17:11:54.770

Reputation: 1