SURFEX v8.1
General documentation of Surfex
ecqsort.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <limits.h>
4 #include <signal.h>
5 #include "intercept_alloc.h"
6 #include "raise.h"
7 
8 /* ecqsort_() : Fortran-callable quick-sort */
9 
10 /*
11  by Sami Saarinen, ECMWF, 7/07/2005 : Interface derived from rsort32.c & rsort64.c
12  - " - 4/09/2006 : Dr.Hook call for kwiksort_u64_index
13  - " - 7/02/2007 : Intercepting alloc (IBM & NEC SX) + NEC SX vectorization
14  - " - 3/07/2007 : Rewritten to use qsort() standard library routine
15  - " - 15/10/2007 : Fast qsort() added for simple 1-dim cases (see ../include/ecsort_shared.h)
16  - " - 16/10/2007 : Reverse-flag added to avoid explicit negation of the array (cheaper)
17  - " - 03/12/2007 : Dr.Hook calls removed; disturbs when in OMP-region on IBM ; a compiler bug ?
18 */
19 
20 /*
21  Methods:
22 
23  0 : Unsigned 32-bit ints
24  1 : Signed 32-bit ints
25  2 : 64-bit doubles (IEEE) : signbit + 11-bit exp + 52-bits mantissa
26  3 : 32-bit floats (IEEE) : signbit + 8-bit exp + 23-bits mantissa
27  4 : Signed 64-bit ints
28  5 : Unsigned 64-bit ints
29 
30 */
31 
32 typedef unsigned long long int Uint64;
33 typedef long long int Sint64;
34 typedef unsigned int Uint32;
35 typedef int Sint32;
36 
37 typedef short int Sint16;
38 typedef signed char Sint8;
39 
40 #ifdef __uxppx__
41 #ifndef VPP
42 #define VPP
43 #endif
44 #endif
45 
46 #ifdef VPP
47 #pragma global noalias
48 #pragma global novrec
49 #elif defined(NECSX)
50 #pragma cdir options -pvctl,nodep
51 #elif defined(NECSX)
52 #pragma cdir options -pvctl,nodep
53 #endif
54 
55 typedef long long int ll_t;
56 
57 #define ALLOC(x,size) \
58  { ll_t bytes = (ll_t)sizeof(*x) * (size); \
59  bytes = (bytes < 1) ? 1 : bytes; \
60  x = THEmalloc(bytes); \
61  if (!x) { fprintf(stderr, \
62  "malloc() of %s (%lld bytes) failed in file=%s, line=%d\n", \
63  #x, bytes, __FILE__, __LINE__); RAISE(SIGABRT); } }
64 
65 #define FREE(x) if (x) { THEfree(x); x = NULL; }
66 
67 #if defined(NO_TRUNC) || defined(VPP) || defined(NECSX)
68 /* For systems without trunc() -function [an extension of ANSI-C, but usually available] */
69 #define trunc(x) ((x) - fmod((x),1))
70 #else
71 extern double trunc(double d);
72 #endif
73 
74 #define MakeKwikSort(T) \
75 typedef struct { \
76  const T *valueptr; \
77  int j; \
78  int idx; \
79 } T##Str_t; \
80 \
81 static int \
82 T##cmp(const T##Str_t *a, const T##Str_t *b) { \
83  if ( *a->valueptr > *b->valueptr ) return 1; \
84  else if ( *a->valueptr < *b->valueptr ) return -1; \
85  else { /* *a->valueptr == *b->valueptr */ \
86  /* the next line is essential for the stable qsort() */ \
87  return (a->j > b->j) ? 1 : -1; \
88  } \
89 } \
90 static int \
91 T##cmp_rev(const T##Str_t *a, const T##Str_t *b) { \
92  if ( *a->valueptr < *b->valueptr ) return 1; \
93  else if ( *a->valueptr > *b->valueptr ) return -1; \
94  else { /* a->valueptr == b->valueptr */ \
95  /* the next line is essential for the stable qsort() */ \
96  return (a->j > b->j) ? 1 : -1; \
97  } \
98 } \
99 \
100 static void \
101 kwiksort_##T(const T v[], int n, int index[], int inc, \
102  int index_adj, int mode, int irev) \
103 { \
104  int j; \
105  T##Str_t *x = NULL; \
106  ALLOC(x, n); \
107  if (mode < 10) { \
108  /* index[] needs to be initialized */ \
109  if (inc == 1) { \
110  for (j=0; j<n; j++) { x[j].valueptr = &v[j]; \
111  x[j].j = j; \
112  x[j].idx = j + index_adj; /* C -> Fortran */ \
113  } \
114  } \
115  else { \
116  for (j=0; j<n; j++) { x[j].valueptr = &v[j * inc]; \
117  x[j].j = j; \
118  x[j].idx = j + index_adj; /* C -> Fortran */ \
119  } \
120  } \
121  } \
122  else { \
123  if (inc == 1) { \
124  for (j=0; j<n; j++) { \
125  int tmpidx = index[j] - index_adj; /* Fortran -> C */ \
126  x[j].valueptr = &v[tmpidx]; \
127  x[j].j = j; \
128  x[j].idx = index[j]; \
129  } \
130  } \
131  else { \
132  for (j=0; j<n; j++) { \
133  int tmpidx = index[j] - index_adj; /* Fortran -> C */ \
134  x[j].valueptr = &v[tmpidx * inc]; \
135  x[j].j = j; \
136  x[j].idx = index[j]; \
137  } \
138  } \
139  } \
140  qsort(x, n, sizeof(*x), \
141  irev ? \
142  (int (*)(const void *, const void *))T##cmp_rev : \
143  (int (*)(const void *, const void *))T##cmp); \
144  for (j=0; j<n; j++) index[j] = x[j].idx; /* Re-arranged indices */ \
145  FREE(x); \
146 }
147 
148 #define MakeFastSort(T) \
149 static int \
150 T##fcmp(const T *a, const T *b) { \
151  if ( *a > *b ) return 1; \
152  else if ( *a < *b ) return -1; \
153  else return 0; \
154 } \
155 static int \
156 T##fcmp_rev(const T *a, const T *b) { \
157  if ( *a < *b ) return 1; \
158  else if ( *a > *b ) return -1; \
159  else return 0; \
160 } \
161 \
162 static void \
163 FastSort_##T(T v[], int n, int irev) \
164 { \
165  qsort(v, n, sizeof(*v), \
166  irev ? \
167  (int (*)(const void *, const void *))T##fcmp_rev : \
168  (int (*)(const void *, const void *))T##fcmp); \
169 }
170 
171 #define kwiksort(T) \
172 MakeKwikSort(T) \
173 MakeFastSort(T)
174 
175 #define SORT_UINT 0
177 
178 #define SORT_INT 1
180 
181 #define SORT_R64 2
182 kwiksort(double)
183 
184 #define SORT_R32 3
185 kwiksort(float)
186 
187 #define SORT_I64 4
189 
190 #define SORT_U64 5
192 
193 #define DoSort(T) { \
194  T *data = Data; \
195  { \
196  kwiksort_##T(&data[addr], n, index, inc, index_adj, mode, irev); \
197  } \
198 }
199 
200 #define DoFastSort(T) { \
201  T *data = Data; \
202  { \
203  FastSort_##T(data, n, irev); \
204  } \
205 }
206 
207 void
208 ecqsort_(const int *Mode,
209  const int *N,
210  const int *Inc,
211  const int *Start_addr,
212  void *Data,
213  int index[],
214  const int *Index_adj,
215  const int *Reverse,
216  int *retc)
217 {
218  int mode = *Mode;
219  int method = mode%10;
220  int n = *N;
221  int rc = n;
222  int inc = *Inc;
223  int index_adj = *Index_adj;
224  int irev = *Reverse;
225  int addr = (*Start_addr) - 1; /* Fortran to C */
226 
227  if (method != SORT_UINT &&
228  method != SORT_INT &&
229  method != SORT_R64 &&
230  method != SORT_R32 &&
231  method != SORT_I64 &&
232  method != SORT_U64 ) {
233  rc = -1;
234  goto finish;
235  }
236 
237  if (n <= 0) {
238  if (n < 0) rc = -2;
239  goto finish;
240  }
241 
242  if (inc < 1) {
243  rc = -3;
244  goto finish;
245  }
246 
247  switch (method) {
248  case SORT_UINT:
249  DoSort(Uint32);
250  break;
251  case SORT_INT:
252  DoSort(Sint32);
253  break;
254  case SORT_R64:
255  DoSort(double);
256  break;
257  case SORT_R32:
258  DoSort(float);
259  break;
260  case SORT_I64:
261  DoSort(Sint64);
262  break;
263  case SORT_U64:
264  DoSort(Uint64);
265  break;
266  }
267 
268  finish:
269 
270  *retc = rc;
271 }
272 
273 void
274 ecqsortfast_(const int *Mode,
275  const int *N,
276  void *Data,
277  const int *Reverse,
278  int *retc)
279 {
280  int mode = *Mode;
281  int method = mode%10;
282  int n = *N;
283  int rc = n;
284  int irev = *Reverse;
285 
286  if (method != SORT_UINT &&
287  method != SORT_INT &&
288  method != SORT_R64 &&
289  method != SORT_R32 &&
290  method != SORT_I64 &&
291  method != SORT_U64 ) {
292  rc = -1;
293  goto finish;
294  }
295 
296  if (n <= 0) {
297  if (n < 0) rc = -2;
298  goto finish;
299  }
300 
301  switch (method) {
302  case SORT_UINT:
303  DoFastSort(Uint32);
304  break;
305  case SORT_INT:
306  DoFastSort(Sint32);
307  break;
308  case SORT_R64:
309  DoFastSort(double);
310  break;
311  case SORT_R32:
312  DoFastSort(float);
313  break;
314  case SORT_I64:
315  DoFastSort(Sint64);
316  break;
317  case SORT_U64:
318  DoFastSort(Uint64);
319  break;
320  }
321 
322  finish:
323 
324  *retc = rc;
325 }
326 
327 #define MakeMergeFuncs(T) \
328 static int \
329 T##_Merge(T data[], int amax, int bmax) \
330 { \
331  int i, j, N = amax + bmax; \
332  T *a = data; \
333  T *b = &data[amax]; \
334  i=amax-1; j=N-1; \
335  if (a[i] > b[0]) { \
336  int k; \
337  T *c = NULL; \
338  ALLOC(c, bmax); \
339  memcpy(c, b, bmax * sizeof(T)); \
340  k=bmax-1; \
341  while ((i >= 0) && (k >= 0)) { \
342  if (a[i] >= c[k]) data[j--] = a[i--]; else data[j--] = c[k--]; \
343  } \
344  while (k >= 0) data[j--] = c[k--]; \
345  FREE(c); \
346  } \
347  return N; \
348 } \
349 static int \
350 T##_MergeIdx(const T data[], int amax, int bmax, int index[], const int rank[]) \
351 { \
352  int i, j, N = amax + bmax; \
353  int *a = index; \
354  int *b = &index[amax]; \
355  i=amax-1; j=N-1; \
356  if (data[a[i]] > data[b[0]]) { \
357  int k; \
358  int *c = NULL; \
359  ALLOC(c, bmax); \
360  memcpy(c, b, bmax * sizeof(int)); \
361  k=bmax-1; \
362  while ((i >= 0) && (k >= 0)) { \
363  T dai = data[a[i]]; \
364  T dck = data[c[k]]; \
365  if (dai > dck) index[j--] = a[i--]; \
366  else if (dai < dck) index[j--] = c[k--]; \
367  else { /* dai == dck : the rank[] decides */ \
368  if (rank[a[i]] > rank[c[k]]) index[j--] = a[i--]; else index[j--] = c[k--]; \
369  } \
370  } \
371  while (k >= 0) index[j--] = c[k--]; \
372  FREE(c); \
373  } \
374  return N; \
375 } \
376 static int \
377 T##_Merge_rev(T data[], int amax, int bmax) \
378 { \
379  int i, j, N = amax + bmax; \
380  T *a = data; \
381  T *b = &data[amax]; \
382  i=amax-1; j=N-1; \
383  if (a[i] < b[0]) { \
384  int k; \
385  T *c = NULL; \
386  ALLOC(c, bmax); \
387  memcpy(c, b, bmax * sizeof(T)); \
388  k=bmax-1; \
389  while ((i >= 0) && (k >= 0)) { \
390  if (a[i] <= c[k]) data[j--] = a[i--]; else data[j--] = c[k--]; \
391  } \
392  while (k >= 0) data[j--] = c[k--]; \
393  FREE(c); \
394  } \
395  return N; \
396 } \
397 static int \
398 T##_MergeIdx_rev(const T data[], int amax, int bmax, int index[], const int rank[]) \
399 { \
400  int i, j, N = amax + bmax; \
401  int *a = index; \
402  int *b = &index[amax]; \
403  i=amax-1; j=N-1; \
404  if (data[a[i]] < data[b[0]]) { \
405  int k; \
406  int *c = NULL; \
407  ALLOC(c, bmax); \
408  memcpy(c, b, bmax * sizeof(int)); \
409  k=bmax-1; \
410  while ((i >= 0) && (k >= 0)) { \
411  T dai = data[a[i]]; \
412  T dck = data[c[k]]; \
413  if (dai < dck) index[j--] = a[i--]; \
414  else if (dai > dck) index[j--] = c[k--]; \
415  else { /* dai == dck : the rank[] decides */ \
416  if (rank[a[i]] > rank[c[k]]) index[j--] = a[i--]; else index[j--] = c[k--]; \
417  } \
418  } \
419  while (k >= 0) index[j--] = c[k--]; \
420  FREE(c); \
421  } \
422  return N; \
423 }
424 
427 MakeMergeFuncs(double)
428 MakeMergeFuncs(float)
431 
432 #define DoMerge(T) { \
433  T *X = Data; \
434  X += addr; \
435  if (index && nidx >= n) { \
436  int j; \
437  if (index_adj) for (j=0; j<n; j++) index[j] -= index_adj; /* Fortran -> C */ \
438  rc = irev ? \
439  T##_MergeIdx_rev(X, amax, bmax, index, rank) : \
440  T##_MergeIdx(X, amax, bmax, index, rank); \
441  if (index_adj) for (j=0; j<n; j++) index[j] += index_adj; /* C -> Fortran */ \
442  } \
443  else { \
444  rc = irev ? T##_Merge_rev(X, amax, bmax) : T##_Merge(X, amax, bmax); \
445  } \
446 }
447 
448 void ecmerge2_(const int *Mode,
449  const int *Start_addr,
450  const int *Amax,
451  const int *Bmax,
452  void *Data,
453  int *index,
454  const int *Nidx,
455  const int *Index_adj,
456  const int *Reverse,
457  const int rank[],
458  int *retc)
459 {
460  int mode = *Mode;
461  int method = mode%10;
462  int addr = (*Start_addr) - 1; /* Fortran to C */
463  int amax = *Amax;
464  int bmax = *Bmax;
465  int n = amax + bmax;
466  int nidx = *Nidx;
467  int index_adj = *Index_adj;
468  int irev = *Reverse;
469  int rc = 0;
470 
471  if (method != SORT_UINT &&
472  method != SORT_INT &&
473  method != SORT_R64 &&
474  method != SORT_R32 &&
475  method != SORT_I64 &&
476  method != SORT_U64 ) {
477  rc = -1;
478  goto finish;
479  }
480 
481  if (n <= 0) {
482  if (n < 0) rc = -2;
483  goto finish;
484  }
485 
486  switch (method) {
487  case SORT_UINT:
488  DoMerge(Uint32);
489  break;
490  case SORT_INT:
491  DoMerge(Sint32);
492  break;
493  case SORT_R64:
494  DoMerge(double);
495  break;
496  case SORT_R32:
497  DoMerge(float);
498  break;
499  case SORT_I64:
500  DoMerge(Sint64);
501  break;
502  case SORT_U64:
503  DoMerge(Uint64);
504  break;
505  }
506 
507  finish:
508  *retc = rc;
509 }
void ecqsort_(const int *Mode, const int *N, const int *Inc, const int *Start_addr, void *Data, int index[], const int *Index_adj, const int *Reverse, int *retc)
Definition: ecqsort.c:208
signed char Sint8
Definition: ecqsort.c:38
ERROR in method
Definition: ecsort_shared.h:90
MakeMergeFuncs(Uint32)
Definition: ecqsort.c:425
long long int Sint64
Definition: countingsort.c:42
unsigned long long int Uint64
Definition: countingsort.c:41
kwiksort(Uint32)
Definition: ecqsort.c:176
void ecmerge2_(const int *Mode, const int *Start_addr, const int *Amax, const int *Bmax, void *Data, int *index, const int *Nidx, const int *Index_adj, const int *Reverse, const int rank[], int *retc)
Definition: ecqsort.c:448
integer(kind=kindofint) nidx
int Sint32
Definition: countingsort.c:44
ERROR in n
Definition: ecsort_shared.h:90
long long int ll_t
Definition: ecqsort.c:55
int Sint32
Definition: ecqsort.c:35
short int Sint16
Definition: ecqsort.c:37
unsigned int Uint32
Definition: countingsort.c:43
void ecqsortfast_(const int *Mode, const int *N, void *Data, const int *Reverse, int *retc)
Definition: ecqsort.c:274
unsigned long long int Uint64
Definition: ecqsort.c:32
double trunc(double d)
long long int Sint64
Definition: ecqsort.c:33
ERROR in index
Definition: ecsort_shared.h:90
int rank
Definition: opfla_perfmon.c:19
unsigned int Uint32
Definition: ecqsort.c:34