home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume34 / flogger / part01 / flogger.c next >
C/C++ Source or Header  |  1992-12-18  |  16KB  |  535 lines

  1.  
  2. /* 
  3.  
  4. NAME
  5.   flogger
  6.  
  7. DESCRIPTION
  8.  
  9.   Put the sort routines through the paces.  Verify that they actually
  10.   order data properly and that they don't molest the memory locations
  11.   immediately above or below the array.  Tries some common worst-case
  12.   situations like already-ordered data and comparison functions which
  13.   are defective.
  14.  
  15.   Prints out estimates for each sort algorithm for usage of heap space,
  16.   stack space, and run time and also for the number of calls to the
  17.   comparison function.
  18.  
  19.   Takes one command line argument which specifies the number of items
  20.   to put in the array.  Larger values take longer to run.
  21.  
  22. AUTHORSHIP
  23.  
  24.   Mike Lee, currently mikey@ontek.com
  25.  
  26. REFERENCES
  27.  
  28.   Knuth, Art of Computer Programming Vol 3: Searching and Sorting
  29.   Kernighan & Richtie, The C Programming Language, Second Edition
  30.  
  31. WORK REMAINING
  32.  
  33.   The main loop is hopeless.
  34.   See the TODO document (which should accompany this program.)
  35.  
  36. COPYRIGHT
  37.  
  38.   Copyright 1992 Michael Lee.
  39.  
  40.   (1) Permission to use, copy, distribute, and make changes is granted
  41.   providing that (a) that you do so without charging anyone a fee and
  42.   (b) this copyright notice must be included verbatim in all copies and 
  43.   distributions.  
  44.  
  45.   (2) There is no warranty for this program, to the extent permitted by
  46.   applicable law.  This program is provided "AS IS" without warranty of
  47.   any kind, either expressed or implied, including, but not limited to,
  48.   the implied warranties of merchantability and fitness for a particular 
  49.   purpose.  The entire risk as to the quality and performance of this 
  50.   program is with the user.  Should this program prove defective, the 
  51.   user assumes the cost of all necessary servicing, repair or correction.
  52.  
  53.   (3) In no event unless required by applicable law will the copyright
  54.   holder be liable to the user for damages, including any general,
  55.   special, incidental or consequential damages arising out of the use
  56.   or inability to use this program (including but not limited to loss of
  57.   data or data being rendered inaccurate or losses sustained by the
  58.   user or third parties or a failure of this program to operate with any
  59.   other programs), even if such holder or third party has been advised
  60.   of the possibility of such damages.
  61.  
  62.   (4) Object code produced by a compiler from this code may be 
  63.   incorporated into commercial products without being subject to 
  64.   restrictions (1)(a) or (1)(b).
  65.  
  66. */
  67.  
  68. #include <stdio.h>
  69. #include <malloc.h>
  70. #include <memory.h>
  71. #include <string.h>
  72. #include <signal.h>
  73. #include <setjmp.h>
  74.  
  75. #include <sys/types.h>
  76. #include <sys/times.h>
  77. #include <sys/param.h>
  78.  
  79. #include "sorting.h"
  80.  
  81. #define TEST_TYPE double
  82. #define TEST_FUNC double_compare
  83. #define DEFAULT_COUNT 2220 /* product of 4 and several primes */
  84.  
  85. #define CANARY_LOW -77.0
  86. #define CANARY_HIGH -88.0
  87.  
  88. #define TEST_RANDOM 1
  89. #define TEST_ASCEND 2
  90. #define TEST_DESCEND 3
  91. #define TEST_FIB_ASC 4
  92. #define TEST_FIB_DESC 5
  93. #define TEST_SURPRISE 6
  94. #define TEST_MOSTLY 7
  95. #define TEST_EQUIV 8
  96.  
  97. static int compare_count;
  98. static int s_heap;
  99. static char * s_low, * s_high;
  100.  
  101. #define CHECK_CANARIES \
  102.   { \
  103.     if (*(TEST_TYPE *) a == CANARY_LOW || *(TEST_TYPE *) b == CANARY_LOW)\
  104.     { \
  105.       printf("ran off the bottom of the array!\n"); \
  106.       fflush(stdout); \
  107.       longjmp(next, 1); \
  108.     } \
  109.     if (*(TEST_TYPE *) a == CANARY_HIGH || *(TEST_TYPE *) b == CANARY_HIGH)\
  110.     { \
  111.       printf("ran off the top of the array!\n"); \
  112.       fflush(stdout); \
  113.       longjmp(next, 1); \
  114.     } \
  115.   }
  116.  
  117. #define UPDATE_S_HEAP \
  118.   { struct mallinfo mi; \
  119.     mi = mallinfo();  \
  120.     if (s_heap < mi.uordblks) s_heap = mi.uordblks;  \
  121.     if (s_low == NULL || where < s_low) s_low = where; \
  122.     if (s_high == NULL || where > s_high) s_high = where; \
  123.     compare_count ++; }
  124.  
  125. static jmp_buf next;
  126.  
  127. void catch_quit()
  128. {
  129.   printf("\n");
  130.   fflush(stdout);
  131.   longjmp(next, 1);
  132. }
  133.  
  134. void test_sort_func();
  135.  
  136. int int_compare(a, b) int * a, *b; 
  137.   char foo;
  138.   char * where = &foo;
  139.  
  140.   CHECK_CANARIES;
  141.   UPDATE_S_HEAP;
  142.  
  143.   if (*a > *b) return 1;
  144.   if (*a < *b) return -1;
  145.   return 0;
  146. }
  147.  
  148. int double_compare(a, b) double * a, *b; 
  149.   char foo;
  150.   char * where = &foo;
  151.  
  152.   CHECK_CANARIES;
  153.   UPDATE_S_HEAP;
  154.  
  155.   if (*a > *b) return 1;
  156.   if (*a < *b) return -1;
  157.   return 0;
  158. }
  159.  
  160. /*ARGSUSED*/
  161. int lie_ascending(a, b) char * a, *b; 
  162.   char foo;
  163.   char * where = &foo;
  164.  
  165.   CHECK_CANARIES;
  166.   UPDATE_S_HEAP;
  167.  
  168.   return -1;
  169. }
  170.  
  171. /*ARGSUSED*/
  172. int lie_descending(a, b) char * a, *b; 
  173.   char foo;
  174.   char * where = &foo;
  175.  
  176.   CHECK_CANARIES;
  177.   UPDATE_S_HEAP;
  178.  
  179.   return 1;
  180. }
  181.  
  182. /*ARGSUSED*/
  183. int lie_equal(a, b) char * a, *b; 
  184.   char foo;
  185.   char * where = &foo;
  186.  
  187.   CHECK_CANARIES;
  188.   UPDATE_S_HEAP;
  189.  
  190.   return 0;
  191. }
  192.  
  193. /*ARGSUSED*/
  194. int surprise(a, b) char * a, *b; 
  195.   char foo;
  196.   char * where = &foo;
  197.  
  198.   CHECK_CANARIES;
  199.   UPDATE_S_HEAP;
  200.  
  201.   foo = rand() >> 23;
  202.   if ((unsigned char) foo < 85) return -1;
  203.   if ((unsigned char) foo < 171) return 0;
  204.   return 1;
  205. }
  206.  
  207. int main(argc, argv) int argc; char * argv[];
  208. {
  209.   int n;
  210.   int stage = 0;
  211.   int done = 0;
  212.  
  213.   printf("sort flogger version %d patch level %d.\n",
  214.     FLOGGER_VERSION, FLOGGER_PATCHLEVEL);
  215.   if (argc > 1) 
  216.     n = atoi(argv[1]);
  217.   else
  218.     n = DEFAULT_COUNT;
  219.   if (n < 0) n = -n;
  220.  
  221.   printf("timer resolution = %1.6f\n", 1.0/(double)HZ);
  222.   printf("element size = %d\n", sizeof(TEST_TYPE));
  223.   printf("number of elements = %d", n);
  224.   fflush(stdout);
  225.  
  226.   setjmp(next);
  227.   signal(SIGINT, catch_quit);
  228.  
  229.   /* apologies for the bizarre code layout */
  230.  
  231.   while (! done) switch (stage)
  232.   {
  233.     case 0: printf("\n*** qsort ***\n");
  234.             printf("data         compares      stack       ");
  235.             printf("heap       user       system\n");
  236.             fflush(stdout);
  237.             stage ++; test_sort_func(qsort, n, 1); break;
  238.     case 1: stage ++; test_sort_func(qsort, n, 2); break;
  239.     case 2: stage ++; test_sort_func(qsort, n, 3); break;
  240.     case 3: stage ++; test_sort_func(qsort, n, 4); break;
  241.     case 4: stage ++; test_sort_func(qsort, n, 5); break;
  242.     case 5: stage ++; test_sort_func(qsort, n, 6); break;
  243.     case 6: stage ++; test_sort_func(qsort, n, 7); break;
  244.     case 7: stage ++; test_sort_func(qsort, n, 8); break;
  245.  
  246.     case 10: _maybe_sorted = 0;
  247.              printf("\n*** merge_sort ***\n");
  248.              printf("data         compares      stack       ");
  249.              printf("heap       user       system\n");
  250.              fflush(stdout);
  251.              stage ++; test_sort_func(merge_sort, n, 1); break;
  252.     case 11: stage ++; test_sort_func(merge_sort, n, 2); break;
  253.     case 12: stage ++; test_sort_func(merge_sort, n, 3); break;
  254.     case 13: stage ++; test_sort_func(merge_sort, n, 4); break;
  255.     case 14: stage ++; test_sort_func(merge_sort, n, 5); break;
  256.     case 15: stage ++; test_sort_func(merge_sort, n, 6); break;
  257.     case 16: stage ++; test_sort_func(merge_sort, n, 7); break;
  258.     case 17: stage ++; test_sort_func(merge_sort, n, 8); break;
  259.  
  260.     case 20: _maybe_sorted = 1;
  261.              printf("\n*** merge_sort(_maybe_sorted) ***\n");
  262.              printf("data         compares      stack       ");
  263.              printf("heap       user       system\n");
  264.              fflush(stdout);
  265.              stage ++; test_sort_func(merge_sort, n, 1); break;
  266.     case 21: stage ++; test_sort_func(merge_sort, n, 2); break;
  267.     case 22: stage ++; test_sort_func(merge_sort, n, 3); break;
  268.     case 23: stage ++; test_sort_func(merge_sort, n, 4); break;
  269.     case 24: stage ++; test_sort_func(merge_sort, n, 5); break;
  270.     case 25: stage ++; test_sort_func(merge_sort, n, 6); break;
  271.     case 26: stage ++; test_sort_func(merge_sort, n, 7); break;
  272.     case 27: stage ++; test_sort_func(merge_sort, n, 8); break;
  273.  
  274.     case 30: printf("\n*** heap_sort ***\n");
  275.              printf("data         compares      stack       ");
  276.              printf("heap       user       system\n");
  277.              fflush(stdout);
  278.              stage ++; test_sort_func(heap_sort, n, 1); break;
  279.     case 31: stage ++; test_sort_func(heap_sort, n, 2); break;
  280.     case 32: stage ++; test_sort_func(heap_sort, n, 3); break;
  281.     case 33: stage ++; test_sort_func(heap_sort, n, 4); break;
  282.     case 34: stage ++; test_sort_func(heap_sort, n, 5); break;
  283.     case 35: stage ++; test_sort_func(heap_sort, n, 6); break;
  284.     case 36: stage ++; test_sort_func(heap_sort, n, 7); break;
  285.     case 37: stage ++; test_sort_func(heap_sort, n, 8); break;
  286.  
  287.     case 40: printf("\n*** shell_sort ***\n");
  288.              printf("data         compares      stack       ");
  289.              printf("heap       user       system\n");
  290.              fflush(stdout);
  291.              stage ++; test_sort_func(shell_sort, n, 1); break;
  292.     case 41: stage ++; test_sort_func(shell_sort, n, 2); break;
  293.     case 42: stage ++; test_sort_func(shell_sort, n, 3); break;
  294.     case 43: stage ++; test_sort_func(shell_sort, n, 4); break;
  295.     case 44: stage ++; test_sort_func(shell_sort, n, 5); break;
  296.     case 45: stage ++; test_sort_func(shell_sort, n, 6); break;
  297.     case 46: stage ++; test_sort_func(shell_sort, n, 7); break;
  298.     case 47: stage ++; test_sort_func(shell_sort, n, 8); break;
  299.  
  300.     case 50: printf("\n*** quick_sort ***\n");
  301.              printf("data         compares      stack       ");
  302.              printf("heap       user       system\n");
  303.              fflush(stdout);
  304.              stage ++; test_sort_func(quick_sort, n, 1); break;
  305.     case 51: stage ++; test_sort_func(quick_sort, n, 2); break;
  306.     case 52: stage ++; test_sort_func(quick_sort, n, 3); break;
  307.     case 53: stage ++; test_sort_func(quick_sort, n, 4); break;
  308.     case 54: stage ++; test_sort_func(quick_sort, n, 5); break;
  309.     case 55: stage ++; test_sort_func(quick_sort, n, 6); break;
  310.     case 56: stage ++; test_sort_func(quick_sort, n, 7); break;
  311.     case 57: stage ++; test_sort_func(quick_sort, n, 8); break;
  312.  
  313.     case 60: printf("\n*** insertion_sort ***\n");
  314.              printf("data         compares      stack       ");
  315.              printf("heap       user       system\n");
  316.              fflush(stdout);
  317.              stage ++; test_sort_func(insertion_sort, n, 1); break;
  318.     case 61: stage ++; test_sort_func(insertion_sort, n, 2); break;
  319.     case 62: stage ++; test_sort_func(insertion_sort, n, 3); break;
  320.     case 63: stage ++; test_sort_func(insertion_sort, n, 4); break;
  321.     case 64: stage ++; test_sort_func(insertion_sort, n, 5); break;
  322.     case 65: stage ++; test_sort_func(insertion_sort, n, 6); break;
  323.     case 66: stage ++; test_sort_func(insertion_sort, n, 7); break;
  324.     case 67: stage ++; test_sort_func(insertion_sort, n, 8); break;
  325.  
  326.     case 70: printf("\n*** bubble_sort ***\n");
  327.              printf("data         compares      stack       ");
  328.              printf("heap       user       system\n");
  329.              fflush(stdout);
  330.              stage ++; test_sort_func(bubble_sort, n, 1); break;
  331.     case 71: stage ++; test_sort_func(bubble_sort, n, 2); break;
  332.     case 72: stage ++; test_sort_func(bubble_sort, n, 3); break;
  333.     case 73: stage ++; test_sort_func(bubble_sort, n, 4); break;
  334.     case 74: stage ++; test_sort_func(bubble_sort, n, 5); break;
  335.     case 75: stage ++; test_sort_func(bubble_sort, n, 6); break;
  336.     case 76: stage ++; test_sort_func(bubble_sort, n, 7); break;
  337.     case 77: stage ++; test_sort_func(bubble_sort, n, 8); break;
  338.  
  339.     case 80: if (n >= 15)
  340.              {
  341.                stage += 10;   
  342.                break;        /* algorithm is factorial!  give up! */
  343.              }
  344.              printf("\n*** bogo_sort ***\n");
  345.              printf("data         compares      stack       ");
  346.              printf("heap       user       system\n");
  347.              fflush(stdout);
  348.              stage ++; test_sort_func(bogo_sort, n, 1); break;
  349.     case 81: stage ++; test_sort_func(bogo_sort, n, 2); break;
  350.     case 82: stage ++; test_sort_func(bogo_sort, n, 3); break;
  351.     case 83: stage ++; test_sort_func(bogo_sort, n, 4); break;
  352.     case 84: stage ++; test_sort_func(bogo_sort, n, 5); break;
  353.     case 85: stage ++; test_sort_func(bogo_sort, n, 6); break;
  354.     case 86: stage ++; test_sort_func(bogo_sort, n, 7); break;
  355.     case 87: stage ++; test_sort_func(bogo_sort, n, 8); break;
  356.  
  357.     case 90: done = 1;
  358.  
  359.     default: stage++;
  360.   }
  361.  
  362.   return 0;
  363. }
  364.  
  365. void test_sort_func(func, n, situation)
  366.   int             (*func)();
  367.   int             n;
  368.   int             situation;
  369. {
  370.   unsigned int i;
  371.   static TEST_TYPE * foo = NULL;
  372.   TEST_TYPE temp;
  373.   int (*fp)();
  374.   int old_heap;
  375.   struct tms start, finish;
  376.  
  377.   /* in case of ctrl-c */
  378.   if (foo != NULL) free((char *) foo);
  379.  
  380.   foo = (TEST_TYPE *) malloc((n+2) * sizeof(TEST_TYPE));
  381.   if (foo == NULL)
  382.   {
  383.     printf("insufficient memory to conduct test.\n");
  384.     exit(1);
  385.   }
  386.  
  387.   /* store magic values above and below the array so that we
  388.      can verify the the sort didn't run off either end */
  389.  
  390.   foo[0] = (TEST_TYPE) CANARY_LOW;
  391.   foo[n+1] = (TEST_TYPE) CANARY_HIGH;
  392.  
  393.   srand((int) n);
  394.  
  395.   /* initialize the contents of the array appropriately for
  396.      the situation we are presenting to the sort function */
  397.  
  398.   for (i = 1; i <= n; i ++) 
  399.   {
  400.     switch(situation)
  401.     {
  402.       case TEST_RANDOM:
  403.       case TEST_FIB_ASC:
  404.       case TEST_FIB_DESC:
  405.       case TEST_SURPRISE:
  406.         do {
  407.           foo[i] = rand();
  408.         } while (foo[i] == CANARY_LOW || foo[i] == CANARY_HIGH);
  409.       break;
  410.  
  411.       case TEST_ASCEND:
  412.       case TEST_MOSTLY: 
  413.       case TEST_EQUIV: 
  414.         foo[i] = i;
  415.       break;
  416.  
  417.       case TEST_DESCEND: 
  418.         foo[i] = n - i;
  419.       break;
  420.     }
  421.   }
  422.  
  423.   if (situation == TEST_MOSTLY && n > 0)
  424.   {
  425.     temp = foo[1];
  426.     foo[1] = foo[n];
  427.     foo[n] = temp;
  428.   }
  429.  
  430.   compare_count = 0;
  431.   s_low = NULL;
  432.   s_high = NULL;
  433.   old_heap = mallinfo().uordblks;
  434.   s_heap = old_heap;
  435.  
  436.   switch(situation)
  437.   {
  438.     case TEST_RANDOM:   printf("random:   "); fp = TEST_FUNC; break;
  439.     case TEST_ASCEND:   printf("ascend:   "); fp = TEST_FUNC; break;
  440.     case TEST_DESCEND:  printf("descend:  "); fp = TEST_FUNC; break;
  441.     case TEST_FIB_ASC:  printf("fib asc:  "); fp = lie_ascending; break;
  442.     case TEST_FIB_DESC: printf("fib desc: "); fp = lie_descending; break;
  443.     case TEST_SURPRISE: printf("surprise: "); fp = surprise;  break;
  444.     case TEST_MOSTLY:   printf("mostly:   "); fp = TEST_FUNC;  break;
  445.     case TEST_EQUIV:    printf("equiv:    "); fp = lie_equal;  break;
  446.     default: fp = NULL; break;
  447.   }
  448.  
  449.   fflush(stdout);
  450.  
  451.   times(&start);
  452.  
  453.   /* actually call the sort function */
  454.   (*func)((char *) &foo[1], (int) n, sizeof(TEST_TYPE), fp);
  455.  
  456.   times(&finish);
  457.  
  458. /*
  459.   printf("\n");
  460.   for (i = 0; i < n; i ++) printf(i % 5 == 4 ? "%11d\n" : "%11d ", foo[i]);
  461.   printf("\n");
  462. */
  463.  
  464.   /* print out one row of data */
  465.  
  466.   printf("%11d", compare_count);
  467.   printf("%11ld", (long) (s_high - s_low));
  468.   printf("%11d", s_heap - old_heap);
  469.   printf("%11.2f", 
  470.     (double) (finish.tms_utime - start.tms_utime) / (double) HZ);
  471.   printf("%11.2f", 
  472.     (double) (finish.tms_stime - start.tms_stime) / (double) HZ);
  473.   fflush(stdout);
  474.  
  475.   if (mallinfo().uordblks - old_heap != 0)
  476.     printf(" (%d leak!)", mallinfo().uordblks - old_heap);
  477.   printf("\n");
  478.  
  479.   /* check the areas immediately above and immediately below
  480.      the array for contamination */
  481.  
  482.   if (foo[0] != CANARY_LOW)
  483.     printf("wrote before beginning of array!\n");
  484.  
  485.   if (foo[n+1] != CANARY_HIGH)
  486.     printf("wrote past end of array!\n");
  487.  
  488.   /* if appropriate, make sure the data was actually sorted */
  489.  
  490.   if (situation == TEST_RANDOM || situation == TEST_ASCEND ||
  491.       situation == TEST_DESCEND || situation == TEST_MOSTLY)
  492.     for (i = 2; i <= n; i ++)
  493.     {
  494.       if ((*TEST_FUNC)(&foo[i], &foo[i-1]) < 0) 
  495.       {
  496.         printf("out of order at position %d\n", i);
  497.         break;
  498.       }
  499.     }
  500.   
  501.   /* check for sortedness, but for this case it's not an error
  502.      just the normal behavior of the algorithm */
  503.  
  504.   if (situation == TEST_EQUIV)
  505.   {
  506.     int stable = 1;
  507.  
  508.     for (i = 2; i <= n && stable; i ++)
  509.     {
  510.       if ((*TEST_FUNC)(&foo[i], &foo[i-1]) < 0) stable = 0;
  511.     }
  512.  
  513.     if (stable)
  514.       printf("algorithm appears to be stable.\n");
  515.     else
  516.       printf("algorithm is not stable.\n");
  517.   }
  518.   
  519.  
  520.   if (foo != NULL) 
  521.   {
  522.     free((char *) foo);
  523.     foo = NULL;
  524.   }
  525.  
  526.   return;
  527. }
  528.  
  529.