home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / bytewarp.zip / NBENCH1.C < prev    next >
C/C++ Source or Header  |  1995-11-30  |  106KB  |  4,307 lines

  1.  
  2. /*
  3. ** nbench1.c
  4. */
  5.  
  6. /********************************
  7. **       BYTEmark (tm)         **
  8. ** BYTE NATIVE MODE BENCHMARKS **
  9. **       VERSION 2             **
  10. **                             **
  11. ** Included in this source     **
  12. ** file:                       **
  13. **  Numeric Heapsort           **
  14. **  String Heapsort            **
  15. **  Bitfield test              **
  16. **  Floating point emulation   **
  17. **  Fourier coefficients       **
  18. **  Assignment algorithm       **
  19. **  IDEA Encyption             **
  20. **  Huffman compression        **
  21. **  Back prop. neural net      **
  22. **  LU Decomposition           **
  23. **    (linear equations)       **
  24. ** ----------                  **
  25. ** Rick Grehan, BYTE Magazine  **
  26. *********************************
  27. **
  28. ** BYTEmark (tm)
  29. ** BYTE's Native Mode Benchmarks
  30. ** Rick Grehan, BYTE Magazine
  31. **
  32. ** Creation:
  33. ** Revision: 3/95;10/95
  34. **  10/95 - Removed allocation that was taking place inside
  35. **   the LU Decomposition benchmark. Though it didn't seem to
  36. **   make a difference on systems we ran it on, it nonetheless
  37. **   removes an operating system dependency that probably should
  38. **   not have been there.
  39. **
  40. ** DISCLAIMER
  41. ** The source, executable, and documentation files that comprise
  42. ** the BYTEmark benchmarks are made available on an "as is" basis.
  43. ** This means that we at BYTE Magazine have made every reasonable
  44. ** effort to verify that the there are no errors in the source and
  45. ** executable code.  We cannot, however, guarantee that the programs
  46. ** are error-free.  Consequently, McGraw-HIll and BYTE Magazine make
  47. ** no claims in regard to the fitness of the source code, executable
  48. ** code, and documentation of the BYTEmark.
  49. **  Furthermore, BYTE Magazine, McGraw-Hill, and all employees
  50. ** of McGraw-Hill cannot be held responsible for any damages resulting
  51. ** from the use of this code or the results obtained from using
  52. ** this code.
  53. */
  54.  
  55. /*
  56. ** INCLUDES
  57. */
  58. #include <stdio.h>
  59. #include <stdlib.h>
  60. #include <string.h>
  61. #include <math.h>
  62. #include "nmglobal.h"
  63. #include "nbench1.h"
  64. #include "wordcat.h"
  65.  
  66.  
  67. /*********************
  68. ** NUMERIC HEAPSORT **
  69. **********************
  70. ** This test implements a heapsort algorithm, performed on an
  71. ** array of longs.
  72. */
  73.  
  74. /**************
  75. ** DoNumSort **
  76. ***************
  77. ** This routine performs the CPU numeric sort test.
  78. ** NOTE: Last version incorrectly stated that the routine
  79. **  returned result in # of longword sorted per second.
  80. **  Not so; the routine returns # of iterations per sec.
  81. */
  82.  
  83. void DoNumSort(void)
  84. {
  85. SortStruct *numsortstruct;      /* Local pointer to global struct */
  86. farlong *arraybase;     /* Base pointers of array */
  87. long accumtime;         /* Accumulated time */
  88. double iterations;      /* Iteration counter */
  89. char *errorcontext;     /* Error context string pointer */
  90. int systemerror;        /* For holding error codes */
  91.  
  92. /*
  93. ** Link to global structure
  94. */
  95. numsortstruct=&global_numsortstruct;
  96.  
  97. /*
  98. ** Set the error context string.
  99. */
  100. errorcontext="CPU:Numeric Sort";
  101.  
  102. /*
  103. ** See if we need to do self adjustment code.
  104. */
  105. if(numsortstruct->adjust==0)
  106. {
  107.     /*
  108.     ** Self-adjustment code.  The system begins by sorting 1
  109.     ** array.  If it does that in no time, then two arrays
  110.     ** are built and sorted.  This process continues until
  111.     ** enough arrays are built to handle the tolerance.
  112.     */
  113.     numsortstruct->numarrays=1;
  114.     while(1)
  115.     {
  116.         /*
  117.         ** Allocate space for arrays
  118.         */
  119.         arraybase=(farlong *)AllocateMemory(sizeof(long) *
  120.             numsortstruct->numarrays * numsortstruct->arraysize,
  121.             &systemerror);
  122.         if(systemerror)
  123.         {       ReportError(errorcontext,systemerror);
  124.             FreeMemory((farvoid *)arraybase,
  125.                   &systemerror);
  126.             ErrorExit();
  127.         }
  128.  
  129.         /*
  130.         ** Do an iteration of the numeric sort.  If the
  131.         ** elapsed time is less than or equal to the permitted
  132.         ** minimum, then allocate for more arrays and
  133.         ** try again.
  134.         */
  135.         if(DoNumSortIteration(arraybase,
  136.             numsortstruct->arraysize,
  137.             numsortstruct->numarrays)>global_min_ticks)
  138.             break;          /* We're ok...exit */
  139.  
  140.         FreeMemory((farvoid *)arraybase,&systemerror);
  141.         if(numsortstruct->numarrays++>NUMNUMARRAYS)
  142.         {       printf("CPU:NSORT -- NUMNUMARRAYS hit.\n");
  143.             ErrorExit();
  144.         }
  145.     }
  146. }
  147. else
  148. {       /*
  149.     ** Allocate space for arrays
  150.     */
  151.     arraybase=(farlong *)AllocateMemory(sizeof(long) *
  152.         numsortstruct->numarrays * numsortstruct->arraysize,
  153.         &systemerror);
  154.     if(systemerror)
  155.     {       ReportError(errorcontext,systemerror);
  156.         FreeMemory((farvoid *)arraybase,
  157.               &systemerror);
  158.         ErrorExit();
  159.     }
  160.  
  161. }
  162. /*
  163. ** All's well if we get here.  Repeatedly perform sorts until the
  164. ** accumulated elapsed time is greater than # of seconds requested.
  165. */
  166. accumtime=0L;
  167. iterations=(double)0.0;
  168.  
  169. do {
  170.     accumtime+=DoNumSortIteration(arraybase,
  171.         numsortstruct->arraysize,
  172.         numsortstruct->numarrays);
  173.     iterations+=(double)1.0;
  174. } while(TicksToSecs(accumtime)<numsortstruct->request_secs);
  175.  
  176. /*
  177. ** Clean up, calculate results, and go home.  Be sure to
  178. ** show that we don't have to rerun adjustment code.
  179. */
  180. FreeMemory((farvoid *)arraybase,&systemerror);
  181.  
  182. numsortstruct->sortspersec=iterations *
  183.     (double)numsortstruct->numarrays / TicksToFracSecs(accumtime);
  184.  
  185. if(numsortstruct->adjust==0)
  186.     numsortstruct->adjust=1;
  187.  
  188. return;
  189. }
  190.  
  191. /***********************
  192. ** DoNumSortIteration **
  193. ************************
  194. ** This routine executes one iteration of the numeric
  195. ** sort benchmark.  It returns the number of ticks
  196. ** elapsed for the iteration.
  197. */
  198. static ulong DoNumSortIteration(farlong *arraybase,
  199.         ulong arraysize,
  200.         uint numarrays)
  201. {
  202. ulong elapsed;          /* Elapsed ticks */
  203. ulong i;
  204. /*
  205. ** Load up the array with random numbers
  206. */
  207. LoadNumArrayWithRand(arraybase,arraysize,numarrays);
  208.  
  209. /*
  210. ** Start the stopwatch
  211. */
  212. elapsed=StartStopwatch();
  213.  
  214. /*
  215. ** Execute a heap of heapsorts
  216. */
  217. for(i=0;i<numarrays;i++)
  218.     NumHeapSort(arraybase+i*arraysize,0L,arraysize-1L);
  219.  
  220. /*
  221. ** Get elapsed time
  222. */
  223. elapsed=StopStopwatch(elapsed);
  224. #ifdef DEBUG
  225. {
  226.  
  227.     for(i=0;i<arraysize-1;i++)
  228.     {       /*
  229.         ** Compare to check for proper
  230.         ** sort.
  231.         */
  232.         if(arraybase[i+1]<arraybase[i])
  233.         {       printf("Sort Error\n");
  234.             break;
  235.         }
  236.     }
  237. }
  238. #endif
  239.  
  240. return(elapsed);
  241. }
  242.  
  243. /*************************
  244. ** LoadNumArrayWithRand **
  245. **************************
  246. ** Load up an array with random longs.
  247. */
  248. static void LoadNumArrayWithRand(farlong *array,     /* Pointer to arrays */
  249.         ulong arraysize,
  250.         uint numarrays)         /* # of elements in array */
  251. {
  252. long i;                 /* Used for index */
  253. farlong *darray;        /* Destination array pointer */
  254. /*
  255. ** Initialize the random number generator
  256. */
  257. randnum(13L);
  258.  
  259. /*
  260. ** Load up first array with randoms
  261. */
  262. for(i=0L;i<arraysize;i++)
  263.     array[i]=randnum(0L);
  264.  
  265. /*
  266. ** Now, if there's more than one array to load, copy the
  267. ** first into each of the others.
  268. */
  269. darray=array;
  270. while(--numarrays)
  271. {       darray+=arraysize;
  272.     for(i=0L;i<arraysize;i++)
  273.         darray[i]=array[i];
  274. }
  275.  
  276. return;
  277. }
  278.  
  279. /****************
  280. ** NumHeapSort **
  281. *****************
  282. ** Pass this routine a pointer to an array of long
  283. ** integers.  Also pass in minimum and maximum offsets.
  284. ** This routine performs a heap sort on that array.
  285. */
  286. static void NumHeapSort(farlong *array,
  287.     ulong bottom,           /* Lower bound */
  288.     ulong top)              /* Upper bound */
  289. {
  290. ulong temp;                     /* Used to exchange elements */
  291. ulong i;                        /* Loop index */
  292.  
  293. /*
  294. ** First, build a heap in the array
  295. */
  296. for(i=(top/2L); i>0; --i)
  297.     NumSift(array,i,top);
  298.  
  299. /*
  300. ** Repeatedly extract maximum from heap and place it at the
  301. ** end of the array.  When we get done, we'll have a sorted
  302. ** array.
  303. */
  304. for(i=top; i>0; --i)
  305. {       NumSift(array,bottom,i);
  306.     temp=*array;                    /* Perform exchange */
  307.     *array=*(array+i);
  308.     *(array+i)=temp;
  309. }
  310. return;
  311. }
  312.  
  313. /************
  314. ** NumSift **
  315. *************
  316. ** Peforms the sift operation on a numeric array,
  317. ** constructing a heap in the array.
  318. */
  319. static void NumSift(farlong *array,     /* Array of numbers */
  320.     ulong i,                /* Minimum of array */
  321.     ulong j)                /* Maximum of array */
  322. {
  323. unsigned long k;
  324. long temp;                              /* Used for exchange */
  325.  
  326. while((i+i)<=j)
  327. {
  328.     k=i+i;
  329.     if(k<j)
  330.         if(array[k]<array[k+1L])
  331.             ++k;
  332.     if(array[i]<array[k])
  333.     {
  334.         temp=array[k];
  335.         array[k]=array[i];
  336.         array[i]=temp;
  337.         i=k;
  338.     }
  339.     else
  340.         i=j+1;
  341. }
  342. return;
  343. }
  344.  
  345. /********************
  346. ** STRING HEAPSORT **
  347. ********************/
  348.  
  349. /*****************
  350. ** DoStringSort **
  351. ******************
  352. ** This routine performs the CPU string sort test.
  353. ** Arguments:
  354. **      requested_secs = # of seconds to execute test
  355. **      stringspersec = # of strings per second sorted (RETURNED)
  356. */
  357. void DoStringSort(void)
  358. {
  359.  
  360. SortStruct *strsortstruct;      /* Local for sort structure */
  361. faruchar *arraybase;            /* Base pointer of char array */
  362. long accumtime;                 /* Accumulated time */
  363. double iterations;              /* # of iterations */
  364. char *errorcontext;             /* Error context string pointer */
  365. int systemerror;                /* For holding error code */
  366.  
  367. /*
  368. ** Link to global structure
  369. */
  370. strsortstruct=&global_strsortstruct;
  371.  
  372. /*
  373. ** Set the error context
  374. */
  375. errorcontext="CPU:String Sort";
  376.  
  377. /*
  378. ** See if we have to perform self-adjustment code
  379. */
  380. if(strsortstruct->adjust==0)
  381. {
  382.     /*
  383.     ** Initialize the number of arrays.
  384.     */
  385.     strsortstruct->numarrays=1;
  386.     while(1)
  387.     {
  388.         /*
  389.         ** Allocate space for array.  We'll add an extra 100
  390.         ** bytes to protect memory as strings move around
  391.         ** (this can happen during string adjustment)
  392.         */
  393.         arraybase=(faruchar *)AllocateMemory((strsortstruct->arraysize+100L) *
  394.             (long)strsortstruct->numarrays,&systemerror);
  395.         if(systemerror)
  396.         {       ReportError(errorcontext,systemerror);
  397.             ErrorExit();
  398.         }
  399.  
  400.         /*
  401.         ** Do an iteration of the string sort.  If the
  402.         ** elapsed time is less than or equal to the permitted
  403.         ** minimum, then de-allocate the array, reallocate a
  404.         ** an additional array, and try again.
  405.         */
  406.         if(DoStringSortIteration(arraybase,
  407.             strsortstruct->numarrays,
  408.             strsortstruct->arraysize)>global_min_ticks)
  409.             break;          /* We're ok...exit */
  410.  
  411.         FreeMemory((farvoid *)arraybase,&systemerror);
  412.         strsortstruct->numarrays+=1;
  413.     }
  414. }
  415. else
  416. {
  417.     /*
  418.     ** We don't have to perform self adjustment code.
  419.     ** Simply allocate the space for the array.
  420.     */
  421.     arraybase=(faruchar *)AllocateMemory((strsortstruct->arraysize+100L) *
  422.         (long)strsortstruct->numarrays,&systemerror);
  423.     if(systemerror)
  424.     {       ReportError(errorcontext,systemerror);
  425.         ErrorExit();
  426.     }
  427. }
  428. /*
  429. ** All's well if we get here.  Repeatedly perform sorts until the
  430. ** accumulated elapsed time is greater than # of seconds requested.
  431. */
  432. accumtime=0L;
  433. iterations=(double)0.0;
  434.  
  435. do {
  436.     accumtime+=DoStringSortIteration(arraybase,
  437.                 strsortstruct->numarrays,
  438.                 strsortstruct->arraysize);
  439.     iterations+=(double)strsortstruct->numarrays;
  440. } while(TicksToSecs(accumtime)<strsortstruct->request_secs);
  441.  
  442. /*
  443. ** Clean up, calculate results, and go home.
  444. ** Set flag to show we don't need to rerun adjustment code.
  445. */
  446. FreeMemory((farvoid *)arraybase,&systemerror);
  447. strsortstruct->sortspersec=iterations / (double)TicksToFracSecs(accumtime);
  448. if(strsortstruct->adjust==0)
  449.     strsortstruct->adjust=1;
  450. return;
  451. }
  452.  
  453. /**************************
  454. ** DoStringSortIteration **
  455. ***************************
  456. ** This routine executes one iteration of the string
  457. ** sort benchmark.  It returns the number of ticks
  458. ** Note that this routine also builds the offset pointer
  459. ** array.
  460. */
  461. static ulong DoStringSortIteration(faruchar *arraybase,
  462.         uint numarrays,ulong arraysize)
  463. {
  464. farulong *optrarray;            /* Offset pointer array */
  465. unsigned long elapsed;          /* Elapsed ticks */
  466. unsigned long nstrings;         /* # of strings in array */
  467. int syserror;                   /* System error code */
  468. unsigned int i;                 /* Index */
  469. farulong *tempobase;            /* Temporary offset pointer base */
  470. faruchar *tempsbase;            /* Temporary string base pointer */
  471.  
  472. /*
  473. ** Load up the array(s) with random numbers
  474. */
  475. optrarray=LoadStringArray(arraybase,numarrays,&nstrings,arraysize);
  476.  
  477. /*
  478. ** Set temp base pointers...they will be modified as the
  479. ** benchmark proceeds.
  480. */
  481. tempobase=optrarray;
  482. tempsbase=arraybase;
  483.  
  484. /*
  485. ** Start the stopwatch
  486. */
  487. elapsed=StartStopwatch();
  488.  
  489. /*
  490. ** Execute heapsorts
  491. */
  492. for(i=0;i<numarrays;i++)
  493. {       StrHeapSort(tempobase,tempsbase,nstrings,0L,nstrings-1);
  494.     tempobase+=nstrings;    /* Advance base pointers */
  495.     tempsbase+=arraysize+100;
  496. }
  497.  
  498. /*
  499. ** Record elapsed time
  500. */
  501. elapsed=StopStopwatch(elapsed);
  502.  
  503. #ifdef DEBUG
  504. {
  505.     unsigned long i;
  506.     for(i=0;i<nstrings-1;i++)
  507.     {       /*
  508.         ** Compare strings to check for proper
  509.         ** sort.
  510.         */
  511.         if(str_is_less(optrarray,arraybase,nstrings,i+1,i))
  512.         {       printf("Sort Error\n");
  513.             break;
  514.         }
  515.     }
  516. }
  517. #endif
  518.  
  519. /*
  520. ** Release the offset pointer array built by
  521. ** LoadStringArray()
  522. */
  523. FreeMemory((farvoid *)optrarray,&syserror);
  524.  
  525. /*
  526. ** Return elapsed ticks.
  527. */
  528. return(elapsed);
  529. }
  530.  
  531. /********************
  532. ** LoadStringArray **
  533. *********************
  534. ** Initialize the string array with random strings of
  535. ** varying sizes.
  536. ** Returns the pointer to the offset pointer array.
  537. ** Note that since we're creating a number of arrays, this
  538. ** routine builds one array, then copies it into the others.
  539. */
  540. static farulong *LoadStringArray(faruchar *strarray, /* String array */
  541.     uint numarrays,                 /* # of arrays */
  542.     ulong *nstrings,                /* # of strings */
  543.     ulong arraysize)                /* Size of array */
  544. {
  545. faruchar *tempsbase;            /* Temporary string base pointer */
  546. farulong *optrarray;            /* Local for pointer */
  547. farulong *tempobase;            /* Temporary offset pointer base pointer */
  548. unsigned long curroffset;       /* Current offset */
  549. int fullflag;                   /* Indicates full array */
  550. unsigned char stringlength;     /* Length of string */
  551. unsigned char i;                /* Index */
  552. unsigned long j;                /* Another index */
  553. unsigned int k;                 /* Yet another index */
  554. unsigned int l;                 /* Ans still one more index */
  555. int systemerror;                /* For holding error code */
  556.  
  557. /*
  558. ** Initialize random number generator.
  559. */
  560. randnum(13L);
  561.  
  562. /*
  563. ** Start with no strings.  Initialize our current offset pointer
  564. ** to 0.
  565. */
  566. *nstrings=0L;
  567. curroffset=0L;
  568. fullflag=0;
  569.  
  570. do
  571. {
  572.     /*
  573.     ** Allocate a string with a random length no
  574.     ** shorter than 4 bytes and no longer than
  575.     ** 80 bytes.  Note we have to also make sure
  576.     ** there's room in the array.
  577.     */
  578.     stringlength=(unsigned char)(1+abs_randwc(76L) & 0xFFL);
  579.     if((unsigned long)stringlength+curroffset+1L>=arraysize)
  580.     {       stringlength=(unsigned char)((arraysize-curroffset-1L) &
  581.                 0xFF);
  582.         fullflag=1;     /* Indicates a full */
  583.     }
  584.  
  585.     /*
  586.     ** Store length at curroffset and advance current offset.
  587.     */
  588.     *(strarray+curroffset)=stringlength;
  589.     curroffset++;
  590.  
  591.     /*
  592.     ** Fill up the rest of the string with random bytes.
  593.     */
  594.     for(i=0;i<stringlength;i++)
  595.     {       *(strarray+curroffset)=
  596.             (unsigned char)(abs_randwc((long)0xFE));
  597.         curroffset++;
  598.     }
  599.  
  600.     /*
  601.     ** Increment the # of strings counter.
  602.     */
  603.     *nstrings+=1L;
  604.  
  605. } while(fullflag==0);
  606.  
  607. /*
  608. ** We now have initialized a single full array.  If there
  609. ** is more than one array, copy the original into the
  610. ** others.
  611. */
  612. k=1;
  613. tempsbase=strarray;
  614. while(k<numarrays)
  615. {       tempsbase+=arraysize+100;         /* Set base */
  616.     for(l=0;l<arraysize;l++)
  617.         tempsbase[l]=strarray[l];
  618.     k++;
  619. }
  620.  
  621. /*
  622. ** Now the array is full, allocate enough space for an
  623. ** offset pointer array.
  624. */
  625. optrarray=(farulong *)AllocateMemory(*nstrings * sizeof(unsigned long) *
  626.         numarrays,
  627.         &systemerror);
  628. if(systemerror)
  629. {       ReportError("CPU:Stringsort",systemerror);
  630.     FreeMemory((void *)strarray,&systemerror);
  631.     ErrorExit();
  632. }
  633.  
  634. /*
  635. ** Go through the newly-built string array, building
  636. ** offsets and putting them into the offset pointer
  637. ** array.
  638. */
  639. curroffset=0;
  640. for(j=0;j<*nstrings;j++)
  641. {       *(optrarray+j)=curroffset;
  642.     curroffset+=(unsigned long)(*(strarray+curroffset))+1L;
  643. }
  644.  
  645. /*
  646. ** As above, we've made one copy of the offset pointers,
  647. ** so duplicate this array in the remaining ones.
  648. */
  649. k=1;
  650. tempobase=optrarray;
  651. while(k<numarrays)
  652. {       tempobase+=*nstrings;
  653.     for(l=0;l<*nstrings;l++)
  654.         tempobase[l]=optrarray[l];
  655.     k++;
  656. }
  657.  
  658. /*
  659. ** All done...go home.  Pass local pointer back.
  660. */
  661. return(optrarray);
  662. }
  663.  
  664. /**************
  665. ** stradjust **
  666. ***************
  667. ** Used by the string heap sort.  Call this routine to adjust the
  668. ** string at offset i to length l.  The members of the string array
  669. ** are moved accordingly and the length of the string at offset i
  670. ** is set to l.
  671. */
  672. static void stradjust(farulong *optrarray,      /* Offset pointer array */
  673.     faruchar *strarray,                     /* String array */
  674.     ulong nstrings,                         /* # of strings */
  675.     ulong i,                                /* Offset to adjust */
  676.     uchar l)                                /* New length */
  677. {
  678. unsigned long nbytes;           /* # of bytes to move */
  679. unsigned long j;                /* Index */
  680. int direction;                  /* Direction indicator */
  681. unsigned char adjamount;        /* Adjustment amount */
  682.  
  683. /*
  684. ** If new length is less than old length, the direction is
  685. ** down.  If new length is greater than old length, the
  686. ** direction is up.
  687. */
  688. direction=(int)l - (int)*(strarray+*(optrarray+i));
  689. adjamount=(unsigned char)abs(direction);
  690.  
  691. /*
  692. ** See if the adjustment is being made to the last
  693. ** string in the string array.  If so, we don't have to
  694. ** do anything more than adjust the length field.
  695. */
  696. if(i==(nstrings-1L))
  697. {       *(strarray+*(optrarray+i))=l;
  698.     return;
  699. }
  700.  
  701. /*
  702. ** Calculate the total # of bytes in string array from
  703. ** location i+1 to end of array.  Whether we're moving "up" or
  704. ** down, this is how many bytes we'll have to move.
  705. */
  706. nbytes=*(optrarray+nstrings-1L) +
  707.     (unsigned long)*(strarray+*(optrarray+nstrings-1L)) + 1L -
  708.     *(optrarray+i+1L);
  709.  
  710. /*
  711. ** Calculate the source and the destination.  Source is
  712. ** string position i+1.  Destination is string position i+l
  713. ** (i+"ell"...don't confuse 1 and l).
  714. ** Hand this straight to memmove and let it handle the
  715. ** "overlap" problem.
  716. */
  717. MoveMemory((farvoid *)(strarray+*(optrarray+i)+l+1),
  718.     (farvoid *)(strarray+*(optrarray+i+1)),
  719.     (unsigned long)nbytes);
  720.  
  721. /*
  722. ** We have to adjust the offset pointer array.
  723. ** This covers string i+1 to numstrings-1.
  724. */
  725. for(j=i+1;j<nstrings;j++)
  726.     if(direction<0)
  727.         *(optrarray+j)=*(optrarray+j)-adjamount;
  728.     else
  729.         *(optrarray+j)=*(optrarray+j)+adjamount;
  730.  
  731. /*
  732. ** Store the new length and go home.
  733. */
  734. *(strarray+*(optrarray+i))=l;
  735. return;
  736. }
  737.  
  738. /****************
  739. ** strheapsort **
  740. *****************
  741. ** Pass this routine a pointer to an array of unsigned char.
  742. ** The array is presumed to hold strings occupying at most
  743. ** 80 bytes (counts a byte count).
  744. ** This routine also needs a pointer to an array of offsets
  745. ** which represent string locations in the array, and
  746. ** an unsigned long indicating the number of strings
  747. ** in the array.
  748. */
  749. static void StrHeapSort(farulong *optrarray, /* Offset pointers */
  750.     faruchar *strarray,             /* Strings array */
  751.     ulong numstrings,               /* # of strings in array */
  752.     ulong bottom,                   /* Region to sort...bottom */
  753.     ulong top)                      /* Region to sort...top */
  754. {
  755. unsigned char temp[80];                 /* Used to exchange elements */
  756. unsigned char tlen;                     /* Temp to hold length */
  757. unsigned long i;                        /* Loop index */
  758.  
  759.  
  760. /*
  761. ** Build a heap in the array
  762. */
  763. for(i=(top/2L); i>0; --i)
  764.     strsift(optrarray,strarray,numstrings,i,top);
  765.  
  766. /*
  767. ** Repeatedly extract maximum from heap and place it at the
  768. ** end of the array.  When we get done, we'll have a sorted
  769. ** array.
  770. */
  771. for(i=top; i>0; --i)
  772. {
  773.     strsift(optrarray,strarray,numstrings,0,i);
  774.  
  775.     /* temp = string[0] */
  776.     tlen=*strarray;
  777.     MoveMemory((farvoid *)&temp[0], /* Perform exchange */
  778.         (farvoid *)strarray,
  779.         (unsigned long)(tlen+1));
  780.  
  781.  
  782.     /* string[0]=string[i] */
  783.     tlen=*(strarray+*(optrarray+i));
  784.     stradjust(optrarray,strarray,numstrings,0,tlen);
  785.     MoveMemory((farvoid *)strarray,
  786.         (farvoid *)(strarray+*(optrarray+i)),
  787.         (unsigned long)(tlen+1));
  788.  
  789.     /* string[i]=temp */
  790.     tlen=temp[0];
  791.     stradjust(optrarray,strarray,numstrings,i,tlen);
  792.     MoveMemory((farvoid *)(strarray+*(optrarray+i)),
  793.         (farvoid *)&temp[0],
  794.         (unsigned long)(tlen+1));
  795.  
  796. }
  797. return;
  798. }
  799.  
  800. /****************
  801. ** str_is_less **
  802. *****************
  803. ** Pass this function:
  804. **      1) A pointer to an array of offset pointers
  805. **      2) A pointer to a string array
  806. **      3) The number of elements in the string array
  807. **      4) Offsets to two strings (a & b)
  808. ** This function returns TRUE if string a is < string b.
  809. */
  810. static int str_is_less(farulong *optrarray, /* Offset pointers */
  811.     faruchar *strarray,                     /* String array */
  812.     ulong numstrings,                       /* # of strings */
  813.     ulong a, ulong b)                       /* Offsets */
  814. {
  815. int slen;               /* String length */
  816.  
  817. /*
  818. ** Determine which string has the minimum length.  Use that
  819. ** to call strncmp().  If they match up to that point, the
  820. ** string with the longer length wins.
  821. */
  822. slen=(int)*(strarray+*(optrarray+a));
  823. if(slen > (int)*(strarray+*(optrarray+b)))
  824.     slen=(int)*(strarray+*(optrarray+b));
  825.  
  826. slen=strncmp((char *)(strarray+*(optrarray+a)),
  827.         (char *)(strarray+*(optrarray+b)),slen);
  828.  
  829. if(slen==0)
  830. {
  831.     /*
  832.     ** They match.  Return true if the length of a
  833.     ** is greater than the length of b.
  834.     */
  835.     if(*(strarray+*(optrarray+a)) >
  836.         *(strarray+*(optrarray+b)))
  837.         return(TRUE);
  838.     return(FALSE);
  839. }
  840.  
  841. if(slen<0) return(TRUE);        /* a is strictly less than b */
  842.  
  843. return(FALSE);                  /* Only other possibility */
  844. }
  845.  
  846. /************
  847. ** strsift **
  848. *************
  849. ** Pass this function:
  850. **      1) A pointer to an array of offset pointers
  851. **      2) A pointer to a string array
  852. **      3) The number of elements in the string array
  853. **      4) Offset within which to sort.
  854. ** Sift the array within the bounds of those offsets (thus
  855. ** building a heap).
  856. */
  857. static void strsift(farulong *optrarray,        /* Offset pointers */
  858.     faruchar *strarray,                     /* String array */
  859.     ulong numstrings,                       /* # of strings */
  860.     ulong i, ulong j)                       /* Offsets */
  861. {
  862. unsigned long k;                /* Temporaries */
  863. unsigned char temp[80];
  864. unsigned char tlen;             /* For string lengths */
  865.  
  866.  
  867. while((i+i)<=j)
  868. {
  869.     k=i+i;
  870.     if(k<j)
  871.         if(str_is_less(optrarray,strarray,numstrings,k,k+1L))
  872.             ++k;
  873.     if(str_is_less(optrarray,strarray,numstrings,i,k))
  874.     {
  875.         /* temp=string[k] */
  876.         tlen=*(strarray+*(optrarray+k));
  877.         MoveMemory((farvoid *)&temp[0],
  878.             (farvoid *)(strarray+*(optrarray+k)),
  879.             (unsigned long)(tlen+1));
  880.  
  881.         /* string[k]=string[i] */
  882.         tlen=*(strarray+*(optrarray+i));
  883.         stradjust(optrarray,strarray,numstrings,k,tlen);
  884.         MoveMemory((farvoid *)(strarray+*(optrarray+k)),
  885.             (farvoid *)(strarray+*(optrarray+i)),
  886.             (unsigned long)(tlen+1));
  887.  
  888.         /* string[i]=temp */
  889.         tlen=temp[0];
  890.         stradjust(optrarray,strarray,numstrings,i,tlen);
  891.         MoveMemory((farvoid *)(strarray+*(optrarray+i)),
  892.             (farvoid *)&temp[0],
  893.             (unsigned long)(tlen+1));
  894.         i=k;
  895.     }
  896.     else
  897.         i=j+1;
  898. }
  899. return;
  900. }
  901.  
  902. /************************
  903. ** BITFIELD OPERATIONS **
  904. *************************/
  905.  
  906. /*************
  907. ** DoBitops **
  908. **************
  909. ** Perform the bit operations test portion of the CPU
  910. ** benchmark.  Returns the iterations per second.
  911. */
  912. void DoBitops(void)
  913. {
  914. BitOpStruct *locbitopstruct;    /* Local bitop structure */
  915. farulong *bitarraybase;         /* Base of bitmap array */
  916. farulong *bitoparraybase;       /* Base of bitmap operations array */
  917. ulong nbitops;                  /* # of bitfield operations */
  918. ulong accumtime;                /* Accumulated time in ticks */
  919. double iterations;              /* # of iterations */
  920. char *errorcontext;             /* Error context string */
  921. int systemerror;                /* For holding error codes */
  922.  
  923. /*
  924. ** Link to global structure.
  925. */
  926. locbitopstruct=&global_bitopstruct;
  927.  
  928. /*
  929. ** Set the error context.
  930. */
  931. errorcontext="CPU:Bitfields";
  932.  
  933. /*
  934. ** See if we need to run adjustment code.
  935. */
  936. if(locbitopstruct->adjust==0)
  937. {
  938.     bitarraybase=(farulong *)AllocateMemory(locbitopstruct->bitfieldarraysize *
  939.         sizeof(ulong),&systemerror);
  940.     if(systemerror)
  941.     {       ReportError(errorcontext,systemerror);
  942.         ErrorExit();
  943.     }
  944.  
  945.     /*
  946.     ** Initialize bitfield operations array to [2,30] elements
  947.     */
  948.     locbitopstruct->bitoparraysize=30L;
  949.  
  950.     while(1)
  951.     {
  952.         /*
  953.         ** Allocate space for operations array
  954.         */
  955.         bitoparraybase=(farulong *)AllocateMemory(locbitopstruct->bitoparraysize*2L*
  956.             sizeof(ulong),
  957.             &systemerror);
  958.         if(systemerror)
  959.         {       ReportError(errorcontext,systemerror);
  960.             FreeMemory((farvoid *)bitarraybase,&systemerror);
  961.             ErrorExit();
  962.         }
  963.         /*
  964.         ** Do an iteration of the bitmap test.  If the
  965.         ** elapsed time is less than or equal to the permitted
  966.         ** minimum, then de-allocate the array, reallocate a
  967.         ** larger version, and try again.
  968.         */
  969.         if(DoBitfieldIteration(bitarraybase,
  970.             bitoparraybase,
  971.             locbitopstruct->bitoparraysize,
  972.             &nbitops)>global_min_ticks)
  973.         break;          /* We're ok...exit */
  974.  
  975.         FreeMemory((farvoid *)bitoparraybase,&systemerror);
  976.         locbitopstruct->bitoparraysize+=100L;
  977.     }
  978. }
  979. else
  980. {
  981.     /*
  982.     ** Don't need to do self adjustment, just allocate
  983.     ** the array space.
  984.     */
  985.     bitarraybase=(farulong *)AllocateMemory(locbitopstruct->bitfieldarraysize *
  986.         sizeof(ulong),&systemerror);
  987.     if(systemerror)
  988.     {       ReportError(errorcontext,systemerror);
  989.         ErrorExit();
  990.     }
  991.     bitoparraybase=(farulong *)AllocateMemory(locbitopstruct->bitoparraysize*2L*
  992.         sizeof(ulong),
  993.         &systemerror);
  994.     if(systemerror)
  995.     {       ReportError(errorcontext,systemerror);
  996.         FreeMemory((farvoid *)bitarraybase,&systemerror);
  997.         ErrorExit();
  998.     }
  999. }
  1000.  
  1001. /*
  1002. ** All's well if we get here.  Repeatedly perform bitops until the
  1003. ** accumulated elapsed time is greater than # of seconds requested.
  1004. */
  1005. accumtime=0L;
  1006. iterations=(double)0.0;
  1007. do {
  1008.     accumtime+=DoBitfieldIteration(bitarraybase,
  1009.             bitoparraybase,
  1010.             locbitopstruct->bitoparraysize,&nbitops);
  1011.     iterations+=(double)nbitops;
  1012. } while(TicksToSecs(accumtime)<locbitopstruct->request_secs);
  1013.  
  1014. /*
  1015. ** Clean up, calculate results, and go home.
  1016. ** Also, set adjustment flag to show that we don't have
  1017. ** to do self adjusting in the future.
  1018. */
  1019. FreeMemory((farvoid *)bitarraybase,&systemerror);
  1020. FreeMemory((farvoid *)bitoparraybase,&systemerror);
  1021. locbitopstruct->bitopspersec=iterations /TicksToFracSecs(accumtime);
  1022. if(locbitopstruct->adjust==0)
  1023.     locbitopstruct->adjust=1;
  1024.  
  1025. return;
  1026. }
  1027.  
  1028. /************************
  1029. ** DoBitfieldIteration **
  1030. *************************
  1031. ** Perform a single iteration of the bitfield benchmark.
  1032. ** Return the # of ticks accumulated by the operation.
  1033. */
  1034. static ulong DoBitfieldIteration(farulong *bitarraybase,
  1035.         farulong *bitoparraybase,
  1036.         long bitoparraysize,
  1037.         ulong *nbitops)
  1038. {
  1039. long i;                         /* Index */
  1040. ulong bitoffset;                /* Offset into bitmap */
  1041. ulong elapsed;                  /* Time to execute */
  1042.  
  1043. /*
  1044. ** Clear # bitops counter
  1045. */
  1046. *nbitops=0L;
  1047.  
  1048. /*
  1049. ** Construct a set of bitmap offsets and run lengths.
  1050. ** The offset can be any random number from 0 to the
  1051. ** size of the bitmap (in bits).  The run length can
  1052. ** be any random number from 1 to the number of bits
  1053. ** between the offset and the end of the bitmap.
  1054. ** Note that the bitmap has 8192 * 32 bits in it.
  1055. ** (262,144 bits)
  1056. */
  1057. for (i=0;i<bitoparraysize;i++)
  1058. {
  1059.     /* First item is offset */
  1060.     *(bitoparraybase+i+i)=bitoffset=abs_randwc(262140L);
  1061.  
  1062.     /* Next item is run length */
  1063.     *nbitops+=*(bitoparraybase+i+i+1L)=abs_randwc(262140L-bitoffset);
  1064. }
  1065.  
  1066. /*
  1067. ** Array of offset and lengths built...do an iteration of
  1068. ** the test.
  1069. ** Start the stopwatch.
  1070. */
  1071. elapsed=StartStopwatch();
  1072.  
  1073. /*
  1074. ** Loop through array off offset/run length pairs.
  1075. ** Execute operation based on modulus of index.
  1076. */
  1077. for(i=0;i<bitoparraysize;i++)
  1078. {
  1079.     switch(i % 3)
  1080.     {
  1081.  
  1082.         case 0: /* Set run of bits */
  1083.             ToggleBitRun(bitarraybase,
  1084.                 *(bitoparraybase+i+i),
  1085.                 *(bitoparraybase+i+i+1),
  1086.                 1);
  1087.             break;
  1088.  
  1089.         case 1: /* Clear run of bits */
  1090.             ToggleBitRun(bitarraybase,
  1091.                 *(bitoparraybase+i+i),
  1092.                 *(bitoparraybase+i+i+1),
  1093.                 0);
  1094.             break;
  1095.  
  1096.         case 2: /* Complement run of bits */
  1097.             FlipBitRun(bitarraybase,
  1098.                 *(bitoparraybase+i+i),
  1099.                 *(bitoparraybase+i+i+1));
  1100.             break;
  1101.     }
  1102. }
  1103.  
  1104. /*
  1105. ** Return elapsed time
  1106. */
  1107. return(StopStopwatch(elapsed));
  1108. }
  1109.  
  1110.  
  1111. /*****************************
  1112. **     ToggleBitRun          *
  1113. ******************************
  1114. ** Set or clear a run of nbits starting at
  1115. ** bit_addr in bitmap.
  1116. */
  1117. static void ToggleBitRun(farulong *bitmap, /* Bitmap */
  1118.         ulong bit_addr,         /* Address of bits to set */
  1119.         ulong nbits,            /* # of bits to set/clr */
  1120.         uint val)               /* 1 or 0 */
  1121. {
  1122. unsigned long bindex;   /* Index into array */
  1123. unsigned long bitnumb;  /* Bit number */
  1124.  
  1125. while(nbits--)
  1126. {
  1127. #ifdef LONG64
  1128.     bindex=bit_addr>>6;     /* Index is number /64 */
  1129.     bindex=bit_addr % 64;   /* Bit number in word */
  1130. #else
  1131.     bindex=bit_addr>>5;     /* Index is number /32 */
  1132.     bitnumb=bit_addr % 32;  /* bit number in word */
  1133. #endif
  1134.     if(val)
  1135.         bitmap[bindex]|=(1L<<bitnumb);
  1136.     else
  1137.         bitmap[bindex]&=~(1L<<bitnumb);
  1138.     bit_addr++;
  1139. }
  1140. return;
  1141. }
  1142.  
  1143. /***************
  1144. ** FlipBitRun **
  1145. ****************
  1146. ** Complements a run of bits.
  1147. */
  1148. static void FlipBitRun(farulong *bitmap,        /* Bit map */
  1149.         ulong bit_addr,                 /* Bit address */
  1150.         ulong nbits)                    /* # of bits to flip */
  1151. {
  1152. unsigned long bindex;   /* Index into array */
  1153. unsigned long bitnumb;  /* Bit number */
  1154.  
  1155. while(nbits--)
  1156. {
  1157. #ifdef LONG64
  1158.     bindex=bit_addr>>6;     /* Index is number /64 */
  1159.     bitnumb=bit_addr % 32;  /* Bit number in longword */
  1160. #else
  1161.     bindex=bit_addr>>5;     /* Index is number /32 */
  1162.     bitnumb=bit_addr % 32;  /* Bit number in longword */
  1163. #endif
  1164.     bitmap[bindex]^=(1L<<bitnumb);
  1165.     bit_addr++;
  1166. }
  1167.  
  1168. return;
  1169. }
  1170.  
  1171. /*****************************
  1172. ** FLOATING-POINT EMULATION **
  1173. *****************************/
  1174.  
  1175. /**************
  1176. ** DoEmFloat **
  1177. ***************
  1178. ** Perform the floating-point emulation routines portion of the
  1179. ** CPU benchmark.  Returns the operations per second.
  1180. */
  1181. void DoEmFloat(void)
  1182. {
  1183. EmFloatStruct *locemfloatstruct;        /* Local structure */
  1184. InternalFPF *abase;             /* Base of A array */
  1185. InternalFPF *bbase;             /* Base of B array */
  1186. InternalFPF *cbase;             /* Base of C array */
  1187. ulong accumtime;                /* Accumulated time in ticks */
  1188. double iterations;              /* # of iterations */
  1189. ulong tickcount;                /* # of ticks */
  1190. char *errorcontext;             /* Error context string pointer */
  1191. int systemerror;                /* For holding error code */
  1192. ulong loops;                    /* # of loops */
  1193.  
  1194. /*
  1195. ** Link to global structure
  1196. */
  1197. locemfloatstruct=&global_emfloatstruct;
  1198.  
  1199. /*
  1200. ** Set the error context
  1201. */
  1202. errorcontext="CPU:Floating Emulation";
  1203.  
  1204.  
  1205. /*
  1206. ** Test the emulation routines.
  1207. */
  1208. #ifdef DEBUG
  1209. #endif
  1210.  
  1211. abase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF),
  1212.         &systemerror);
  1213. if(systemerror)
  1214. {       ReportError(errorcontext,systemerror);
  1215.     ErrorExit();
  1216. }
  1217.  
  1218. bbase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF),
  1219.         &systemerror);
  1220. if(systemerror)
  1221. {       ReportError(errorcontext,systemerror);
  1222.     FreeMemory((farvoid *)abase,&systemerror);
  1223.     ErrorExit();
  1224. }
  1225.  
  1226. cbase=(InternalFPF *)AllocateMemory(locemfloatstruct->arraysize*sizeof(InternalFPF),
  1227.         &systemerror);
  1228. if(systemerror)
  1229. {       ReportError(errorcontext,systemerror);
  1230.     FreeMemory((farvoid *)abase,&systemerror);
  1231.     FreeMemory((farvoid *)bbase,&systemerror);
  1232.     ErrorExit();
  1233. }
  1234.  
  1235. /*
  1236. ** Set up the arrays
  1237. */
  1238. SetupCPUEmFloatArrays(abase,bbase,cbase,locemfloatstruct->arraysize);
  1239.  
  1240. /*
  1241. ** See if we need to do self-adjusting code.
  1242. */
  1243. if(locemfloatstruct->adjust==0)
  1244. {
  1245.     locemfloatstruct->loops=0;
  1246.  
  1247.     /*
  1248.     ** Do an iteration of the tests.  If the elapsed time is
  1249.     ** less than minimum, increase the loop count and try
  1250.     ** again.
  1251.     */
  1252.     for(loops=1;loops<CPUEMFLOATLOOPMAX;loops+=loops)
  1253.     {       tickcount=DoEmFloatIteration(abase,bbase,cbase,
  1254.             locemfloatstruct->arraysize,
  1255.             loops);
  1256.         if(tickcount>global_min_ticks)
  1257.         {       locemfloatstruct->loops=loops;
  1258.             break;
  1259.         }
  1260.     }
  1261. }
  1262.  
  1263. /*
  1264. ** Verify that selft adjustment code worked.
  1265. */
  1266. if(locemfloatstruct->loops==0)
  1267. {       printf("CPU:EMFPU -- CMPUEMFLOATLOOPMAX limit hit\n");
  1268.     FreeMemory((farvoid *)abase,&systemerror);
  1269.     FreeMemory((farvoid *)bbase,&systemerror);
  1270.     FreeMemory((farvoid *)cbase,&systemerror);
  1271.     ErrorExit();
  1272. }
  1273.  
  1274. /*
  1275. ** All's well if we get here.  Repeatedly perform floating
  1276. ** tests until the accumulated time is greater than the
  1277. ** # of seconds requested.
  1278. ** Each iteration performs arraysize * 3 operations.
  1279. */
  1280. accumtime=0L;
  1281. iterations=(double)0.0;
  1282. do {
  1283.     accumtime+=DoEmFloatIteration(abase,bbase,cbase,
  1284.             locemfloatstruct->arraysize,
  1285.             locemfloatstruct->loops);
  1286.     iterations+=(double)1.0;
  1287. } while(TicksToSecs(accumtime)<locemfloatstruct->request_secs);
  1288.  
  1289.  
  1290. /*
  1291. ** Clean up, calculate results, and go home.
  1292. ** Also, indicate that adjustment is done.
  1293. */
  1294. FreeMemory((farvoid *)abase,&systemerror);
  1295. FreeMemory((farvoid *)bbase,&systemerror);
  1296. FreeMemory((farvoid *)cbase,&systemerror);
  1297.  
  1298. locemfloatstruct->emflops=(iterations*(double)locemfloatstruct->loops)/
  1299.         (double)TicksToFracSecs(accumtime);
  1300. if(locemfloatstruct->adjust==0)
  1301.     locemfloatstruct->adjust=1;
  1302.  
  1303. return;
  1304. }
  1305.  
  1306. /*************************
  1307. ** FOURIER COEFFICIENTS **
  1308. *************************/
  1309.  
  1310. /**************
  1311. ** DoFourier **
  1312. ***************
  1313. ** Perform the transcendental/trigonometric portion of the
  1314. ** benchmark.  This benchmark calculates the first n
  1315. ** fourier coefficients of the function (x+1)^x defined
  1316. ** on the interval 0,2.
  1317. */
  1318. void DoFourier(void)
  1319. {
  1320. FourierStruct *locfourierstruct;        /* Local fourier struct */
  1321. fardouble *abase;               /* Base of A[] coefficients array */
  1322. fardouble *bbase;               /* Base of B[] coefficients array */
  1323. unsigned long accumtime;        /* Accumulated time in ticks */
  1324. double iterations;              /* # of iterations */
  1325. char *errorcontext;             /* Error context string pointer */
  1326. int systemerror;                /* For error code */
  1327.  
  1328. /*
  1329. ** Link to global structure
  1330. */
  1331. locfourierstruct=&global_fourierstruct;
  1332.  
  1333. /*
  1334. ** Set error context string
  1335. */
  1336. errorcontext="FPU:Transcendental";
  1337.  
  1338. /*
  1339. ** See if we need to do self-adjustment code.
  1340. */
  1341. if(locfourierstruct->adjust==0)
  1342. {
  1343.     locfourierstruct->arraysize=100L;       /* Start at 100 elements */
  1344.     while(1)
  1345.     {
  1346.  
  1347.         abase=(fardouble *)AllocateMemory(locfourierstruct->arraysize*sizeof(double),
  1348.                 &systemerror);
  1349.         if(systemerror)
  1350.         {       ReportError(errorcontext,systemerror);
  1351.             ErrorExit();
  1352.         }
  1353.  
  1354.         bbase=(fardouble *)AllocateMemory(locfourierstruct->arraysize*sizeof(double),
  1355.                 &systemerror);
  1356.         if(systemerror)
  1357.         {       ReportError(errorcontext,systemerror);
  1358.             FreeMemory((void *)abase,&systemerror);
  1359.             ErrorExit();
  1360.         }
  1361.         /*
  1362.         ** Do an iteration of the tests.  If the elapsed time is
  1363.         ** less than or equal to the permitted minimum, re-allocate
  1364.         ** larger arrays and try again.
  1365.         */
  1366.         if(DoFPUTransIteration(abase,bbase,
  1367.             locfourierstruct->arraysize)>global_min_ticks)
  1368.             break;          /* We're ok...exit */
  1369.  
  1370.         /*
  1371.         ** Make bigger arrays and try again.
  1372.         */
  1373.         FreeMemory((farvoid *)abase,&systemerror);
  1374.         FreeMemory((farvoid *)bbase,&systemerror);
  1375.         locfourierstruct->arraysize+=50L;
  1376.     }
  1377. }
  1378. else
  1379. {       /*
  1380.     ** Don't need self-adjustment.  Just allocate the
  1381.     ** arrays, and go.
  1382.     */
  1383.     abase=(fardouble *)AllocateMemory(locfourierstruct->arraysize*sizeof(double),
  1384.             &systemerror);
  1385.     if(systemerror)
  1386.     {       ReportError(errorcontext,systemerror);
  1387.         ErrorExit();
  1388.     }
  1389.  
  1390.     bbase=(fardouble *)AllocateMemory(locfourierstruct->arraysize*sizeof(double),
  1391.             &systemerror);
  1392.     if(systemerror)
  1393.     {       ReportError(errorcontext,systemerror);
  1394.         FreeMemory((void *)abase,&systemerror);
  1395.         ErrorExit();
  1396.     }
  1397. }
  1398. /*
  1399. ** All's well if we get here.  Repeatedly perform integration
  1400. ** tests until the accumulated time is greater than the
  1401. ** # of seconds requested.
  1402. */
  1403. accumtime=0L;
  1404. iterations=(double)0.0;
  1405. do {
  1406.     accumtime+=DoFPUTransIteration(abase,bbase,locfourierstruct->arraysize);
  1407.     iterations+=(double)locfourierstruct->arraysize*(double)2.0-(double)1.0;
  1408. } while(TicksToSecs(accumtime)<locfourierstruct->request_secs);
  1409.  
  1410.  
  1411. /*
  1412. ** Clean up, calculate results, and go home.
  1413. ** Also set adjustment flag to indicate no adjust code needed.
  1414. */
  1415. FreeMemory((farvoid *)abase,&systemerror);
  1416. FreeMemory((farvoid *)bbase,&systemerror);
  1417.  
  1418. locfourierstruct->fflops=iterations/(double)TicksToFracSecs(accumtime);
  1419.  
  1420. if(locfourierstruct->adjust==0)
  1421.     locfourierstruct->adjust=1;
  1422.  
  1423. return;
  1424. }
  1425.  
  1426. /************************
  1427. ** DoFPUTransIteration **
  1428. *************************
  1429. ** Perform an iteration of the FPU Transcendental/trigonometric
  1430. ** benchmark.  Here, an iteration consists of calculating the
  1431. ** first n fourier coefficients of the function (x+1)^x on
  1432. ** the interval 0,2.  n is given by arraysize.
  1433. ** NOTE: The # of integration steps is fixed at
  1434. ** 200.
  1435. */
  1436. static ulong DoFPUTransIteration(fardouble *abase,      /* A coeffs. */
  1437.             fardouble *bbase,               /* B coeffs. */
  1438.             ulong arraysize)                /* # of coeffs */
  1439. {
  1440. double omega;           /* Fundamental frequency */
  1441. unsigned long i;        /* Index */
  1442. unsigned long elapsed;  /* Elapsed time */
  1443.  
  1444. /*
  1445. ** Start the stopwatch
  1446. */
  1447. elapsed=StartStopwatch();
  1448.  
  1449. /*
  1450. ** Calculate the fourier series.  Begin by
  1451. ** calculating A[0].
  1452. */
  1453.  
  1454. *abase=TrapezoidIntegrate((double)0.0,
  1455.             (double)2.0,
  1456.             200,
  1457.             (double)0.0,    /* No omega * n needed */
  1458.             0 )/(double)2.0;
  1459.  
  1460. /*
  1461. ** Calculate the fundamental frequency.
  1462. ** ( 2 * pi ) / period...and since the period
  1463. ** is 2, omega is simply pi.
  1464. */
  1465. omega=(double)3.1415926535897932;
  1466.  
  1467. for(i=1;i<arraysize;i++)
  1468. {
  1469.  
  1470.     /*
  1471.     ** Calculate A[i] terms.  Note, once again, that we
  1472.     ** can ignore the 2/period term outside the integral
  1473.     ** since the period is 2 and the term cancels itself
  1474.     ** out.
  1475.     */
  1476.     *(abase+i)=TrapezoidIntegrate((double)0.0,
  1477.             (double)2.0,
  1478.             200,
  1479.             omega * (double)i,
  1480.             1);
  1481.  
  1482.     /*
  1483.     ** Calculate the B[i] terms.
  1484.     */
  1485.     *(bbase+i)=TrapezoidIntegrate((double)0.0,
  1486.             (double)2.0,
  1487.             200,
  1488.             omega * (double)i,
  1489.             2);
  1490.  
  1491. }
  1492.  
  1493. /*
  1494. ** All done, stop the stopwatch
  1495. */
  1496. return(StopStopwatch(elapsed));
  1497. }
  1498.  
  1499. /***********************
  1500. ** TrapezoidIntegrate **
  1501. ************************
  1502. ** Perform a simple trapezoid integration on the
  1503. ** function (x+1)**x.
  1504. ** x0,x1 set the lower and upper bounds of the
  1505. ** integration.
  1506. ** nsteps indicates # of trapezoidal sections
  1507. ** omegan is the fundamental frequency times
  1508. **  the series member #
  1509. ** select = 0 for the A[0] term, 1 for cosine terms, and
  1510. **   2 for sine terms.
  1511. ** Returns the value.
  1512. */
  1513. static double TrapezoidIntegrate( double x0,            /* Lower bound */
  1514.             double x1,              /* Upper bound */
  1515.             int nsteps,             /* # of steps */
  1516.             double omegan,          /* omega * n */
  1517.             int select)
  1518. {
  1519. double x;               /* Independent variable */
  1520. double dx;              /* Stepsize */
  1521. double rvalue;          /* Return value */
  1522.  
  1523.  
  1524. /*
  1525. ** Initialize independent variable
  1526. */
  1527. x=x0;
  1528.  
  1529. /*
  1530. ** Calculate stepsize
  1531. */
  1532. dx=(x1 - x0) / (double)nsteps;
  1533.  
  1534. /*
  1535. ** Initialize the return value.
  1536. */
  1537. rvalue=thefunction(x0,omegan,select)/(double)2.0;
  1538.  
  1539. /*
  1540. ** Compute the other terms of the integral.
  1541. */
  1542. if(nsteps!=1)
  1543. {       --nsteps;               /* Already done 1 step */
  1544.     while(--nsteps )
  1545.     {
  1546.         x+=dx;
  1547.         rvalue+=thefunction(x,omegan,select);
  1548.     }
  1549. }
  1550. /*
  1551. ** Finish computation
  1552. */
  1553. rvalue=(rvalue+thefunction(x1,omegan,select)/(double)2.0)*dx;
  1554.  
  1555. return(rvalue);
  1556. }
  1557.  
  1558. /****************
  1559. ** thefunction **
  1560. *****************
  1561. ** This routine selects the function to be used
  1562. ** in the Trapezoid integration.
  1563. ** x is the independent variable
  1564. ** omegan is omega * n
  1565. ** select chooses which of the sine/cosine functions
  1566. **  are used.  note the special case for select=0.
  1567. */
  1568. static double thefunction(double x,             /* Independent variable */
  1569.         double omegan,          /* Omega * term */
  1570.         int select)             /* Choose term */
  1571. {
  1572.  
  1573. /*
  1574. ** Use select to pick which function we call.
  1575. */
  1576. switch(select)
  1577. {
  1578.     case 0: return(pow(x+(double)1.0,x));
  1579.  
  1580.     case 1: return(pow(x+(double)1.0,x) * cos(omegan * x));
  1581.  
  1582.     case 2: return(pow(x+(double)1.0,x) * sin(omegan * x));
  1583. }
  1584.  
  1585. /*
  1586. ** We should never reach this point, but the following
  1587. ** keeps compilers from issuing a warning message.
  1588. */
  1589. return(0.0);
  1590. }
  1591.  
  1592. /*************************
  1593. ** ASSIGNMENT ALGORITHM **
  1594. *************************/
  1595.  
  1596. /*************
  1597. ** DoAssign **
  1598. **************
  1599. ** Perform an assignment algorithm.
  1600. ** The algorithm was adapted from the step by step guide found
  1601. ** in "Quantitative Decision Making for Business" (Gordon,
  1602. **  Pressman, and Cohn; Prentice-Hall)
  1603. **
  1604. **
  1605. ** NOTES:
  1606. ** 1. Even though the algorithm distinguishes between
  1607. **    ASSIGNROWS and ASSIGNCOLS, as though the two might
  1608. **    be different, it does presume a square matrix.
  1609. **    I.E., ASSIGNROWS and ASSIGNCOLS must be the same.
  1610. **    This makes for some algorithmically-correct but
  1611. **    probably non-optimal constructs.
  1612. **
  1613. */
  1614. void DoAssign(void)
  1615. {
  1616. AssignStruct *locassignstruct;  /* Local structure ptr */
  1617. farlong *arraybase;
  1618. char *errorcontext;
  1619. int systemerror;
  1620. ulong accumtime;
  1621. double iterations;
  1622.  
  1623. /*
  1624. ** Link to global structure
  1625. */
  1626. locassignstruct=&global_assignstruct;
  1627.  
  1628. /*
  1629. ** Set the error context string.
  1630. */
  1631. errorcontext="CPU:Assignment";
  1632.  
  1633. /*
  1634. ** See if we need to do self adjustment code.
  1635. */
  1636. if(locassignstruct->adjust==0)
  1637. {
  1638.     /*
  1639.     ** Self-adjustment code.  The system begins by working on 1
  1640.     ** array.  If it does that in no time, then two arrays
  1641.     ** are built.  This process continues until
  1642.     ** enough arrays are built to handle the tolerance.
  1643.     */
  1644.     locassignstruct->numarrays=1;
  1645.     while(1)
  1646.     {
  1647.         /*
  1648.         ** Allocate space for arrays
  1649.         */
  1650.         arraybase=(farlong *) AllocateMemory(sizeof(long)*
  1651.             ASSIGNROWS*ASSIGNCOLS*locassignstruct->numarrays,
  1652.              &systemerror);
  1653.         if(systemerror)
  1654.         {       ReportError(errorcontext,systemerror);
  1655.             FreeMemory((farvoid *)arraybase,
  1656.               &systemerror);
  1657.             ErrorExit();
  1658.         }
  1659.  
  1660.         /*
  1661.         ** Do an iteration of the assignment alg.  If the
  1662.         ** elapsed time is less than or equal to the permitted
  1663.         ** minimum, then allocate for more arrays and
  1664.         ** try again.
  1665.         */
  1666.         if(DoAssignIteration(arraybase,
  1667.             locassignstruct->numarrays)>global_min_ticks)
  1668.             break;          /* We're ok...exit */
  1669.  
  1670.         FreeMemory((farvoid *)arraybase, &systemerror);
  1671.         locassignstruct->numarrays++;
  1672.     }
  1673. }
  1674. else
  1675. {       /*
  1676.     ** Allocate space for arrays
  1677.     */
  1678.     arraybase=(farlong *)AllocateMemory(sizeof(long)*
  1679.         ASSIGNROWS*ASSIGNCOLS*locassignstruct->numarrays,
  1680.          &systemerror);
  1681.     if(systemerror)
  1682.     {       ReportError(errorcontext,systemerror);
  1683.         FreeMemory((farvoid *)arraybase,
  1684.           &systemerror);
  1685.         ErrorExit();
  1686.     }
  1687. }
  1688.  
  1689. /*
  1690. ** All's well if we get here.  Do the tests.
  1691. */
  1692. accumtime=0L;
  1693. iterations=(double)0.0;
  1694.  
  1695. do {
  1696.     accumtime+=DoAssignIteration(arraybase,
  1697.         locassignstruct->numarrays);
  1698.     iterations+=(double)1.0;
  1699. } while(TicksToSecs(accumtime)<locassignstruct->request_secs);
  1700.  
  1701. /*
  1702. ** Clean up, calculate results, and go home.  Be sure to
  1703. ** show that we don't have to rerun adjustment code.
  1704. */
  1705. FreeMemory((farvoid *)arraybase,&systemerror);
  1706.  
  1707. locassignstruct->iterspersec=iterations *
  1708.     (double)locassignstruct->numarrays / TicksToFracSecs(accumtime);
  1709.  
  1710. if(locassignstruct->adjust==0)
  1711.     locassignstruct->adjust=1;
  1712.  
  1713. return;
  1714.  
  1715. }
  1716.  
  1717. /**********************
  1718. ** DoAssignIteration **
  1719. ***********************
  1720. ** This routine executes one iteration of the assignment test.
  1721. ** It returns the number of ticks elapsed in the iteration.
  1722. */
  1723. static ulong DoAssignIteration(farlong *arraybase,
  1724.     ulong numarrays)
  1725. {
  1726. longptr abase;                  /* local pointer */
  1727. ulong elapsed;          /* Elapsed ticks */
  1728. ulong i;
  1729.  
  1730. /*
  1731. ** Set up local pointer
  1732. */
  1733. abase.ptrs.p=arraybase;
  1734.  
  1735. /*
  1736. ** Load up the arrays with a random table.
  1737. */
  1738. LoadAssignArrayWithRand(arraybase,numarrays);
  1739.  
  1740. /*
  1741. ** Start the stopwatch
  1742. */
  1743. elapsed=StartStopwatch();
  1744.  
  1745. /*
  1746. ** Execute assignment algorithms
  1747. */
  1748. for(i=0;i<numarrays;i++)
  1749. {       abase.ptrs.p+=i*ASSIGNROWS*ASSIGNCOLS;
  1750.     Assignment(*abase.ptrs.ap);
  1751. }
  1752.  
  1753. /*
  1754. ** Get elapsed time
  1755. */
  1756. return(StopStopwatch(elapsed));
  1757. }
  1758.  
  1759. /****************************
  1760. ** LoadAssignArrayWithRand **
  1761. *****************************
  1762. ** Load the assignment arrays with random numbers.  All positive.
  1763. ** These numbers represent costs.
  1764. */
  1765. static void LoadAssignArrayWithRand(farlong *arraybase,
  1766.     ulong numarrays)
  1767. {
  1768. longptr abase,abase1;   /* Local for array pointer */
  1769. ulong i;
  1770.  
  1771. /*
  1772. ** Set local array pointer
  1773. */
  1774. abase.ptrs.p=arraybase;
  1775. abase1.ptrs.p=arraybase;
  1776.  
  1777. /*
  1778. ** Set up the first array.  Then just copy it into the
  1779. ** others.
  1780. */
  1781. LoadAssign(*(abase.ptrs.ap));
  1782. if(numarrays>1)
  1783.     for(i=1;i<numarrays;i++)
  1784.     {       abase1.ptrs.p+=i*ASSIGNROWS*ASSIGNCOLS;
  1785.         CopyToAssign(*(abase.ptrs.ap),*(abase1.ptrs.ap));
  1786.     }
  1787.  
  1788. return;
  1789. }
  1790.  
  1791. /***************
  1792. ** LoadAssign **
  1793. ****************
  1794. ** The array given by arraybase is loaded with positive random
  1795. ** numbers.  Elements in the array are capped at 5,000,000.
  1796. */
  1797. static void LoadAssign(farlong arraybase[][ASSIGNCOLS])
  1798. {
  1799. ushort i,j;
  1800.  
  1801. /*
  1802. ** Reset random number generator so things repeat.
  1803. */
  1804. randnum(13L);
  1805.  
  1806. for(i=0;i<ASSIGNROWS;i++)
  1807.     for(j=0;j<ASSIGNROWS;j++)
  1808.         arraybase[i][j]=abs_randwc(5000000L);
  1809. return;
  1810. }
  1811.  
  1812. /*****************
  1813. ** CopyToAssign **
  1814. ******************
  1815. ** Copy the contents of one array to another.  This is called by
  1816. ** the routine that builds the initial array, and is used to copy
  1817. ** the contents of the intial array into all following arrays.
  1818. */
  1819. static void CopyToAssign(farlong arrayfrom[ASSIGNROWS][ASSIGNCOLS],
  1820.         farlong arrayto[ASSIGNROWS][ASSIGNCOLS])
  1821. {
  1822. ushort i,j;
  1823.  
  1824. for(i=0;i<ASSIGNROWS;i++)
  1825.     for(j=0;j<ASSIGNCOLS;j++)
  1826.         arrayto[i][j]=arrayfrom[i][j];
  1827.  
  1828. return;
  1829. }
  1830.  
  1831. /***************
  1832. ** Assignment **
  1833. ***************/
  1834. static void Assignment(farlong arraybase[][ASSIGNCOLS])
  1835. {
  1836. short assignedtableau[ASSIGNROWS][ASSIGNCOLS];
  1837.  
  1838. /*
  1839. ** First, calculate minimum costs
  1840. */
  1841. calc_minimum_costs(arraybase);
  1842.  
  1843. /*
  1844. ** Repeat following until the number of rows selected
  1845. ** equals the number of rows in the tableau.
  1846. */
  1847. while(first_assignments(arraybase,assignedtableau)!=ASSIGNROWS)
  1848. {         second_assignments(arraybase,assignedtableau);
  1849. }
  1850.  
  1851. #ifdef DEBUG
  1852. {
  1853.     int i,j;
  1854.     printf("Column choices for each row\n");
  1855.     for(i=0;i<ASSIGNROWS;i++)
  1856.     {
  1857.         for(j=0;j<ASSIGNCOLS;j++)
  1858.             if(assignedtableau[i][j]!=0)
  1859.                 printf("%d ",j);
  1860.     }
  1861. }
  1862. #endif
  1863.  
  1864. return;
  1865. }
  1866.  
  1867. /***********************
  1868. ** calc_minimum_costs **
  1869. ************************
  1870. ** Revise the tableau by calculating the minimum costs on a
  1871. ** row and column basis.  These minima are subtracted from
  1872. ** their rows and columns, creating a new tableau.
  1873. */
  1874. static void calc_minimum_costs(long tableau[][ASSIGNCOLS])
  1875. {
  1876. ushort i,j;              /* Index variables */
  1877. long currentmin;        /* Current minimum */
  1878. /*
  1879. ** Determine minimum costs on row basis.  This is done by
  1880. ** subtracting -- on a row-per-row basis -- the minum value
  1881. ** for that row.
  1882. */
  1883. for(i=0;i<ASSIGNROWS;i++)
  1884. {
  1885.     currentmin=MAXPOSLONG;  /* Initialize minimum */
  1886.     for(j=0;j<ASSIGNCOLS;j++)
  1887.         if(tableau[i][j]<currentmin)
  1888.             currentmin=tableau[i][j];
  1889.  
  1890.     for(j=0;j<ASSIGNCOLS;j++)
  1891.         tableau[i][j]-=currentmin;
  1892. }
  1893.  
  1894. /*
  1895. ** Determine minimum cost on a column basis.  This works
  1896. ** just as above, only now we step through the array
  1897. ** column-wise
  1898. */
  1899. for(j=0;j<ASSIGNCOLS;j++)
  1900. {
  1901.     currentmin=MAXPOSLONG;  /* Initialize minimum */
  1902.     for(i=0;i<ASSIGNROWS;i++)
  1903.         if(tableau[i][j]<currentmin)
  1904.             currentmin=tableau[i][j];
  1905.  
  1906.     /*
  1907.     ** Here, we'll take the trouble to see if the current
  1908.     ** minimum is zero.  This is likely worth it, since the
  1909.     ** preceding loop will have created at least one zero in
  1910.     ** each row.  We can save ourselves a few iterations.
  1911.     */
  1912.     if(currentmin!=0)
  1913.         for(i=0;i<ASSIGNROWS;i++)
  1914.             tableau[i][j]-=currentmin;
  1915. }
  1916.  
  1917. return;
  1918. }
  1919.  
  1920. /**********************
  1921. ** first_assignments **
  1922. ***********************
  1923. ** Do first assignments.
  1924. ** The assignedtableau[] array holds a set of values that
  1925. ** indicate the assignment of a value, or its elimination.
  1926. ** The values are:
  1927. **      0 = Item is neither assigned nor eliminated.
  1928. **      1 = Item is assigned
  1929. **      2 = Item is eliminated
  1930. ** Returns the number of selections made.  If this equals
  1931. ** the number of rows, then an optimum has been determined.
  1932. */
  1933. static int first_assignments(long tableau[][ASSIGNCOLS],
  1934.         short assignedtableau[][ASSIGNCOLS])
  1935. {
  1936. ushort i,j,k;                   /* Index variables */
  1937. ushort numassigns;              /* # of assignments */
  1938. ushort totnumassigns;           /* Total # of assignments */
  1939. ushort numzeros;                /* # of zeros in row */
  1940. int selected;                   /* Flag used to indicate selection */
  1941.  
  1942. /*
  1943. ** Clear the assignedtableau, setting all members to show that
  1944. ** no one is yet assigned, eliminated, or anything.
  1945. */
  1946. for(i=0;i<ASSIGNROWS;i++)
  1947.     for(j=0;j<ASSIGNCOLS;j++)
  1948.         assignedtableau[i][j]=0;
  1949.  
  1950. totnumassigns=0;
  1951. do {
  1952.     numassigns=0;
  1953.     /*
  1954.     ** Step through rows.  For each one that is not currently
  1955.     ** assigned, see if the row has only one zero in it.  If so,
  1956.     ** mark that as an assigned row/col.  Eliminate other zeros
  1957.     ** in the same column.
  1958.     */
  1959.     for(i=0;i<ASSIGNROWS;i++)
  1960.     {       numzeros=0;
  1961.         for(j=0;j<ASSIGNCOLS;j++)
  1962.             if(tableau[i][j]==0L)
  1963.                 if(assignedtableau[i][j]==0)
  1964.                 {       numzeros++;
  1965.                     selected=j;
  1966.                 }
  1967.         if(numzeros==1)
  1968.         {       numassigns++;
  1969.             totnumassigns++;
  1970.             assignedtableau[i][selected]=1;
  1971.             for(k=0;k<ASSIGNROWS;k++)
  1972.                 if((k!=i) &&
  1973.                    (tableau[k][selected]==0))
  1974.                     assignedtableau[k][selected]=2;
  1975.         }
  1976.     }
  1977.     /*
  1978.     ** Step through columns, doing same as above.  Now, be careful
  1979.     ** of items in the other rows of a selected column.
  1980.     */
  1981.     for(j=0;j<ASSIGNCOLS;j++)
  1982.     {       numzeros=0;
  1983.         for(i=0;i<ASSIGNROWS;i++)
  1984.             if(tableau[i][j]==0L)
  1985.                 if(assignedtableau[i][j]==0)
  1986.                 {       numzeros++;
  1987.                     selected=i;
  1988.                 }
  1989.         if(numzeros==1)
  1990.         {       numassigns++;
  1991.             totnumassigns++;
  1992.             assignedtableau[selected][j]=1;
  1993.             for(k=0;k<ASSIGNCOLS;k++)
  1994.                 if((k!=j) &&
  1995.                    (tableau[selected][k]==0))
  1996.                     assignedtableau[selected][k]=2;
  1997.         }
  1998.     }
  1999.     /*
  2000.     ** Repeat until no more assignments to be made.
  2001.     */
  2002. } while(numassigns!=0);
  2003.  
  2004. /*
  2005. ** See if we can leave at this point.
  2006. */
  2007. if(totnumassigns==ASSIGNROWS) return(totnumassigns);
  2008.  
  2009. /*
  2010. ** Now step through the array by row.  If you find any unassigned
  2011. ** zeros, pick the first in the row.  Eliminate all zeros from
  2012. ** that same row & column.  This occurs if there are multiple optima...
  2013. ** possibly.
  2014. */
  2015. for(i=0;i<ASSIGNROWS;i++)
  2016. {       selected=-1;
  2017.     for(j=0;j<ASSIGNCOLS;j++)
  2018.         if((tableau[i][j]==0L) &&
  2019.            (assignedtableau[i][j]==0))
  2020.         {       selected=j;
  2021.             break;
  2022.         }
  2023.     if(selected!=-1)
  2024.     {       assignedtableau[i][selected]=1;
  2025.         totnumassigns++;
  2026.         for(k=0;k<ASSIGNCOLS;k++)
  2027.             if((k!=selected) &&
  2028.                (tableau[i][k]==0L))
  2029.                 assignedtableau[i][k]=2;
  2030.         for(k=0;k<ASSIGNROWS;k++)
  2031.             if((k!=i) &&
  2032.                (tableau[k][selected]==0L))
  2033.                 assignedtableau[k][selected]=2;
  2034.     }
  2035. }
  2036.  
  2037. return(totnumassigns);
  2038. }
  2039.  
  2040. /***********************
  2041. ** second_assignments **
  2042. ************************
  2043. ** This section of the algorithm creates the revised
  2044. ** tableau, and is difficult to explain.  I suggest you
  2045. ** refer to the algorithm's source, mentioned in comments
  2046. ** toward the beginning of the program.
  2047. */
  2048. static void second_assignments(long tableau[][ASSIGNCOLS],
  2049.         short assignedtableau[][ASSIGNCOLS])
  2050. {
  2051. int i,j;                                /* Indexes */
  2052. short linesrow[ASSIGNROWS];
  2053. short linescol[ASSIGNCOLS];
  2054. long smallest;                          /* Holds smallest value */
  2055. ushort numassigns;                      /* Number of assignments */
  2056. ushort newrows;                         /* New rows to be considered */
  2057. /*
  2058. ** Clear the linesrow and linescol arrays.
  2059. */
  2060. for(i=0;i<ASSIGNROWS;i++)
  2061.     linesrow[i]=0;
  2062. for(i=0;i<ASSIGNCOLS;i++)
  2063.     linescol[i]=0;
  2064.  
  2065. /*
  2066. ** Scan rows, flag each row that has no assignment in it.
  2067. */
  2068. for(i=0;i<ASSIGNROWS;i++)
  2069. {       numassigns=0;
  2070.     for(j=0;j<ASSIGNCOLS;j++)
  2071.         if(assignedtableau[i][j]==1)
  2072.         {       numassigns++;
  2073.             break;
  2074.         }
  2075.     if(numassigns==0) linesrow[i]=1;
  2076. }
  2077.  
  2078. do {
  2079.  
  2080.     newrows=0;
  2081.     /*
  2082.     ** For each row checked above, scan for any zeros.  If found,
  2083.     ** check the associated column.
  2084.     */
  2085.     for(i=0;i<ASSIGNROWS;i++)
  2086.     {       if(linesrow[i]==1)
  2087.             for(j=0;j<ASSIGNCOLS;j++)
  2088.                 if(tableau[i][j]==0)
  2089.                     linescol[j]=1;
  2090.     }
  2091.  
  2092.     /*
  2093.     ** Now scan checked columns.  If any contain assigned zeros, check
  2094.     ** the associated row.
  2095.     */
  2096.     for(j=0;j<ASSIGNCOLS;j++)
  2097.         if(linescol[j]==1)
  2098.             for(i=0;i<ASSIGNROWS;i++)
  2099.                 if((assignedtableau[i][j]==1) &&
  2100.                     (linesrow[i]!=1))
  2101.                 {
  2102.                     linesrow[i]=1;
  2103.                     newrows++;
  2104.                 }
  2105. } while(newrows!=0);
  2106.  
  2107. /*
  2108. ** linesrow[n]==0 indicate rows covered by imaginary line
  2109. ** linescol[n]==1 indicate cols covered by imaginary line
  2110. ** For all cells not covered by imaginary lines, determine smallest
  2111. ** value.
  2112. */
  2113. smallest=MAXPOSLONG;
  2114. for(i=0;i<ASSIGNROWS;i++)
  2115.     if(linesrow[i]!=0)
  2116.         for(j=0;j<ASSIGNCOLS;j++)
  2117.             if(linescol[j]!=1)
  2118.                 if(tableau[i][j]<smallest)
  2119.                     smallest=tableau[i][j];
  2120.  
  2121. /*
  2122. ** Subtract smallest from all cells in the above set.
  2123. */
  2124. for(i=0;i<ASSIGNROWS;i++)
  2125.     if(linesrow[i]!=0)
  2126.         for(j=0;j<ASSIGNCOLS;j++)
  2127.             if(linescol[j]!=1)
  2128.                 tableau[i][j]-=smallest;
  2129.  
  2130. /*
  2131. ** Add smallest to all cells covered by two lines.
  2132. */
  2133. for(i=0;i<ASSIGNROWS;i++)
  2134.     if(linesrow[i]==0)
  2135.         for(j=0;j<ASSIGNCOLS;j++)
  2136.             if(linescol[j]==1)
  2137.                 tableau[i][j]+=smallest;
  2138.  
  2139. return;
  2140. }
  2141.  
  2142. /********************
  2143. ** IDEA Encryption **
  2144. *********************
  2145. ** IDEA - International Data Encryption Algorithm.
  2146. ** Based on code presented in Applied Cryptography by Bruce Schneier.
  2147. ** Which was based on code developed by Xuejia Lai and James L. Massey.
  2148. ** Other modifications made by Colin Plumb.
  2149. **
  2150. */
  2151.  
  2152. /***********
  2153. ** DoIDEA **
  2154. ************
  2155. ** Perform IDEA encryption.  Note that we time encryption & decryption
  2156. ** time as being a single loop.
  2157. */
  2158. void DoIDEA(void)
  2159. {
  2160. IDEAStruct *locideastruct;      /* Loc pointer to global structure */
  2161. int i;
  2162. IDEAkey Z,DK;
  2163. u16 userkey[8];
  2164. ulong accumtime;
  2165. double iterations;
  2166. char *errorcontext;
  2167. int systemerror;
  2168. faruchar *plain1;               /* First plaintext buffer */
  2169. faruchar *crypt1;               /* Encryption buffer */
  2170. faruchar *plain2;               /* Second plaintext buffer */
  2171.  
  2172. /*
  2173. ** Link to global data
  2174. */
  2175. locideastruct=&global_ideastruct;
  2176.  
  2177. /*
  2178. ** Set error context
  2179. */
  2180. errorcontext="CPU:IDEA";
  2181.  
  2182. /*
  2183. ** Re-init random-number generator.
  2184. */
  2185. randnum(3L);
  2186.  
  2187. /*
  2188. ** Build an encryption/decryption key
  2189. */
  2190. for (i=0;i<8;i++)
  2191.     userkey[i]=(u16)(abs_randwc(60000L) & 0xFFFF);
  2192. for(i=0;i<KEYLEN;i++)
  2193.     Z[i]=0;
  2194.  
  2195. /*
  2196. ** Compute encryption/decryption subkeys
  2197. */
  2198. en_key_idea(userkey,Z);
  2199. de_key_idea(Z,DK);
  2200.  
  2201. /*
  2202. ** Allocate memory for buffers.  We'll make 3, called plain1,
  2203. ** crypt1, and plain2.  It works like this:
  2204. **   plain1 >>encrypt>> crypt1 >>decrypt>> plain2.
  2205. ** So, plain1 and plain2 should match.
  2206. ** Also, fill up plain1 with sample text.
  2207. */
  2208. plain1=(faruchar *)AllocateMemory(locideastruct->arraysize,&systemerror);
  2209. if(systemerror)
  2210. {
  2211.     ReportError(errorcontext,systemerror);
  2212.     ErrorExit();
  2213. }
  2214.  
  2215. crypt1=(faruchar *)AllocateMemory(locideastruct->arraysize,&systemerror);
  2216. if(systemerror)
  2217. {
  2218.     ReportError(errorcontext,systemerror);
  2219.     FreeMemory((farvoid *)plain1,&systemerror);
  2220.     ErrorExit();
  2221. }
  2222.  
  2223. plain2=(faruchar *)AllocateMemory(locideastruct->arraysize,&systemerror);
  2224. if(systemerror)
  2225. {
  2226.     ReportError(errorcontext,systemerror);
  2227.     FreeMemory((farvoid *)plain1,&systemerror);
  2228.     FreeMemory((farvoid *)crypt1,&systemerror);
  2229.     ErrorExit();
  2230. }
  2231. /*
  2232. ** Note that we build the "plaintext" by simply loading
  2233. ** the array up with random numbers.
  2234. */
  2235. for(i=0;i<locideastruct->arraysize;i++)
  2236.     plain1[i]=(uchar)(abs_randwc(255) & 0xFF);
  2237.  
  2238. /*
  2239. ** See if we need to perform self adjustment loop.
  2240. */
  2241. if(locideastruct->adjust==0)
  2242. {
  2243.     /*
  2244.     ** Do self-adjustment.  This involves initializing the
  2245.     ** # of loops and increasing the loop count until we
  2246.     ** get a number of loops that we can use.
  2247.     */
  2248.     for(locideastruct->loops=100L;
  2249.       locideastruct->loops<MAXIDEALOOPS;
  2250.       locideastruct->loops+=10L)
  2251.         if(DoIDEAIteration(plain1,crypt1,plain2,
  2252.           locideastruct->arraysize,
  2253.           locideastruct->loops,
  2254.           Z,DK)>global_min_ticks) break;
  2255. }
  2256.  
  2257. /*
  2258. ** All's well if we get here.  Do the test.
  2259. */
  2260. accumtime=0L;
  2261. iterations=(double)0.0;
  2262.  
  2263. do {
  2264.     accumtime+=DoIDEAIteration(plain1,crypt1,plain2,
  2265.         locideastruct->arraysize,
  2266.         locideastruct->loops,Z,DK);
  2267.     iterations+=(double)locideastruct->loops;
  2268. } while(TicksToSecs(accumtime)<locideastruct->request_secs);
  2269.  
  2270. /*
  2271. ** Clean up, calculate results, and go home.  Be sure to
  2272. ** show that we don't have to rerun adjustment code.
  2273. */
  2274. FreeMemory((farvoid *)plain1,&systemerror);
  2275. FreeMemory((farvoid *)crypt1,&systemerror);
  2276. FreeMemory((farvoid *)plain2,&systemerror);
  2277. locideastruct->iterspersec=iterations / TicksToFracSecs(accumtime);
  2278.  
  2279. if(locideastruct->adjust==0)
  2280.     locideastruct->adjust=1;
  2281.  
  2282. return;
  2283.  
  2284. }
  2285.  
  2286. /********************
  2287. ** DoIDEAIteration **
  2288. *********************
  2289. ** Execute a single iteration of the IDEA encryption algorithm.
  2290. ** Actually, a single iteration is one encryption and one
  2291. ** decryption.
  2292. */
  2293. static ulong DoIDEAIteration(faruchar *plain1,
  2294.             faruchar *crypt1,
  2295.             faruchar *plain2,
  2296.             ulong arraysize,
  2297.             ulong nloops,
  2298.             IDEAkey Z,
  2299.             IDEAkey DK)
  2300. {
  2301. register ulong i;
  2302. register ulong j;
  2303. ulong elapsed;
  2304.  
  2305. /*
  2306. ** Start the stopwatch.
  2307. */
  2308. elapsed=StartStopwatch();
  2309.  
  2310. /*
  2311. ** Do everything for nloops.
  2312. */
  2313. for(i=0;i<nloops;i++)
  2314. {
  2315.     for(j=0;j<arraysize;j+=(sizeof(u16)*4))
  2316.         cipher_idea((u16 *)(plain1+j),(u16 *)(crypt1+j),Z);       /* Encrypt */
  2317.  
  2318.     for(j=0;j<arraysize;j+=(sizeof(u16)*4))
  2319.         cipher_idea((u16 *)(crypt1+j),(u16 *)(plain2+j),DK);      /* Decrypt */
  2320. }
  2321.  
  2322. #ifdef DEBUG
  2323. for(j=0;j<arraysize;j++)
  2324.     if(*(plain1+j)!=*(plain2+j))
  2325.         printf("IDEA Error! \n");
  2326. #endif
  2327.  
  2328. /*
  2329. ** Get elapsed time.
  2330. */
  2331. return(StopStopwatch(elapsed));
  2332. }
  2333.  
  2334. /********
  2335. ** mul **
  2336. *********
  2337. ** Performs multiplication, modulo (2**16)+1.  This code is structured
  2338. ** on the assumption that untaken branches are cheaper than taken
  2339. ** branches, and that the compiler doesn't schedule branches.
  2340. */
  2341. static u16 mul(register u16 a, register u16 b)
  2342. {
  2343. register u32 p;
  2344. if(a)
  2345. {       if(b)
  2346.     {       p=(u32)(a*b);
  2347.         b=low16(p);
  2348.         a=(u16)(p>>16);
  2349.         return(b-a+(b<a));
  2350.     }
  2351.     else
  2352.         return(1-a);
  2353. }
  2354. else
  2355.     return(1-b);
  2356. }
  2357.  
  2358. /********
  2359. ** inv **
  2360. *********
  2361. ** Compute multiplicative inverse of x, modulo (2**16)+1
  2362. ** using Euclid's GCD algorithm.  It is unrolled twice
  2363. ** to avoid swapping the meaning of the registers.  And
  2364. ** some subtracts are changed to adds.
  2365. */
  2366. static u16 inv(u16 x)
  2367. {
  2368. u16 t0, t1;
  2369. u16 q, y;
  2370.  
  2371. if(x<=1)
  2372.     return(x);      /* 0 and 1 are self-inverse */
  2373. t1=0x10001 / x;
  2374. y=0x10001 % x;
  2375. if(y==1)
  2376.     return(low16(1-t1));
  2377. t0=1;
  2378. do {
  2379.     q=x/y;
  2380.     x=x%y;
  2381.     t0+=q*t1;
  2382.     if(x==1) return(t0);
  2383.     q=y/x;
  2384.     y=y%x;
  2385.     t1+=q*t0;
  2386. } while(y!=1);
  2387. return(low16(1-t1));
  2388. }
  2389.  
  2390. /****************
  2391. ** en_key_idea **
  2392. *****************
  2393. ** Compute IDEA encryption subkeys Z
  2394. */
  2395. static void en_key_idea(u16 *userkey, u16 *Z)
  2396. {
  2397. int i,j;
  2398.  
  2399. /*
  2400. ** shifts
  2401. */
  2402. for(j=0;j<8;j++)
  2403.     Z[j]=*userkey++;
  2404. for(i=0;j<KEYLEN;j++)
  2405. {       i++;
  2406.     Z[i+7]=(Z[i&7]<<9)| (Z[(i+1) & 7] >> 7);
  2407.     Z+=i&8;
  2408.     i&=7;
  2409. }
  2410. return;
  2411. }
  2412.  
  2413. /****************
  2414. ** de_key_idea **
  2415. *****************
  2416. ** Compute IDEA decryption subkeys DK from encryption
  2417. ** subkeys Z.
  2418. */
  2419. static void de_key_idea(IDEAkey Z, IDEAkey DK)
  2420. {
  2421. IDEAkey TT;
  2422. int j;
  2423. u16 t1, t2, t3;
  2424. u16 *p;
  2425. p=(u16 *)(TT+KEYLEN);
  2426.  
  2427. t1=inv(*Z++);
  2428. t2=-*Z++;
  2429. t3=-*Z++;
  2430. *--p=inv(*Z++);
  2431. *--p=t3;
  2432. *--p=t2;
  2433. *--p=t1;
  2434.  
  2435. for(j=1;j<ROUNDS;j++)
  2436. {       t1=*Z++;
  2437.     *--p=*Z++;
  2438.     *--p=t1;
  2439.     t1=inv(*Z++);
  2440.     t2=-*Z++;
  2441.     t3=-*Z++;
  2442.     *--p=inv(*Z++);
  2443.     *--p=t2;
  2444.     *--p=t3;
  2445.     *--p=t1;
  2446. }
  2447. t1=*Z++;
  2448. *--p=*Z++;
  2449. *--p=t1;
  2450. t1=inv(*Z++);
  2451. t2=-*Z++;
  2452. t3=-*Z++;
  2453. *--p=inv(*Z++);
  2454. *--p=t3;
  2455. *--p=t2;
  2456. *--p=t1;
  2457. /*
  2458. ** Copy and destroy temp copy
  2459. */
  2460. for(j=0,p=TT;j<KEYLEN;j++)
  2461. {       *DK++=*p;
  2462.     *p++=0;
  2463. }
  2464.  
  2465. return;
  2466. }
  2467.  
  2468. /*
  2469. ** MUL(x,y)
  2470. ** This #define creates a macro that computes x=x*y modulo 0x10001.
  2471. ** Requires temps t16 and t32.  Also requires y to be strictly 16
  2472. ** bits.  Here, I am using the simplest form.  May not be the
  2473. ** fastest. -- RG
  2474. */
  2475. /* #define MUL(x,y) (x=mul(low16(x),y)) */
  2476.  
  2477. /****************
  2478. ** cipher_idea **
  2479. *****************
  2480. ** IDEA encryption/decryption algorithm.
  2481. */
  2482. static void cipher_idea(u16 in[4],
  2483.         u16 out[4],
  2484.         register IDEAkey Z)
  2485. {
  2486. register u16 x1, x2, x3, x4, t1, t2;
  2487. /* register u16 t16;
  2488. register u16 t32; */
  2489. int r=ROUNDS;
  2490.  
  2491. x1=*in++;
  2492. x2=*in++;
  2493. x3=*in++;
  2494. x4=*in;
  2495.  
  2496. do {
  2497.     MUL(x1,*Z++);
  2498.     x2+=*Z++;
  2499.     x3+=*Z++;
  2500.     MUL(x4,*Z++);
  2501.  
  2502.     t2=x1^x3;
  2503.     MUL(t2,*Z++);
  2504.     t1=t2+(x2^x4);
  2505.     MUL(t1,*Z++);
  2506.     t2=t1+t2;
  2507.  
  2508.     x1^=t1;
  2509.     x4^=t2;
  2510.  
  2511.     t2^=x2;
  2512.     x2=x3^t1;
  2513.     x3=t2;
  2514. } while(--r);
  2515. MUL(x1,*Z++);
  2516. *out++=x1;
  2517. *out++=x3+*Z++;
  2518. *out++=x2+*Z++;
  2519. MUL(x4,*Z);
  2520. *out=x4;
  2521. return;
  2522. }
  2523.  
  2524. /************************
  2525. ** HUFFMAN COMPRESSION **
  2526. ************************/
  2527.  
  2528. /**************
  2529. ** DoHuffman **
  2530. ***************
  2531. ** Execute a huffman compression on a block of plaintext.
  2532. ** Note that (as with IDEA encryption) an iteration of the
  2533. ** Huffman test includes a compression AND a decompression.
  2534. ** Also, the compression cycle includes building the
  2535. ** Huffman tree.
  2536. */
  2537. void DoHuffman(void)
  2538. {
  2539. HuffStruct *lochuffstruct;      /* Loc pointer to global data */
  2540. char *errorcontext;
  2541. int systemerror;
  2542. ulong accumtime;
  2543. double iterations;
  2544. farchar *comparray;
  2545. farchar *decomparray;
  2546. farchar *plaintext;
  2547.  
  2548. /*
  2549. ** Link to global data
  2550. */
  2551. lochuffstruct=&global_huffstruct;
  2552.  
  2553. /*
  2554. ** Set error context.
  2555. */
  2556. errorcontext="CPU:Huffman";
  2557.  
  2558. /*
  2559. ** Allocate memory for the plaintext and the compressed text.
  2560. ** We'll be really pessimistic here, and allocate equal amounts
  2561. ** for both (though we know...well, we PRESUME) the compressed
  2562. ** stuff will take less than the plain stuff.
  2563. ** Also note that we'll build a 3rd buffer to decompress
  2564. ** into, and we preallocate space for the huffman tree.
  2565. ** (We presume that the Huffman tree will grow no larger
  2566. ** than 512 bytes.  This is actually a super-conservative
  2567. ** estimate...but, who cares?)
  2568. */
  2569. plaintext=(farchar *)AllocateMemory(lochuffstruct->arraysize,&systemerror);
  2570. if(systemerror)
  2571. {       ReportError(errorcontext,systemerror);
  2572.     ErrorExit();
  2573. }
  2574. comparray=(farchar *)AllocateMemory(lochuffstruct->arraysize,&systemerror);
  2575. if(systemerror)
  2576. {       ReportError(errorcontext,systemerror);
  2577.     FreeMemory(plaintext,&systemerror);
  2578.     ErrorExit();
  2579. }
  2580. decomparray=(farchar *)AllocateMemory(lochuffstruct->arraysize,&systemerror);
  2581. if(systemerror)
  2582. {       ReportError(errorcontext,systemerror);
  2583.     FreeMemory(plaintext,&systemerror);
  2584.     FreeMemory(comparray,&systemerror);
  2585.     ErrorExit();
  2586. }
  2587.  
  2588. hufftree=(huff_node *)AllocateMemory(sizeof(huff_node) * 512,
  2589.     &systemerror);
  2590. if(systemerror)
  2591. {       ReportError(errorcontext,systemerror);
  2592.     FreeMemory(plaintext,&systemerror);
  2593.     FreeMemory(comparray,&systemerror);
  2594.     FreeMemory(decomparray,&systemerror);
  2595.     ErrorExit();
  2596. }
  2597.  
  2598. /*
  2599. ** Build the plaintext buffer.  Since we want this to
  2600. ** actually be able to compress, we'll use the
  2601. ** wordcatalog to build the plaintext stuff.
  2602. */
  2603. create_text_block(plaintext,lochuffstruct->arraysize-1,(ushort)500);
  2604. plaintext[lochuffstruct->arraysize-1L]='\0';
  2605. plaintextlen=lochuffstruct->arraysize;
  2606.  
  2607. /*
  2608. ** See if we need to perform self adjustment loop.
  2609. */
  2610. if(lochuffstruct->adjust==0)
  2611. {
  2612.     /*
  2613.     ** Do self-adjustment.  This involves initializing the
  2614.     ** # of loops and increasing the loop count until we
  2615.     ** get a number of loops that we can use.
  2616.     */
  2617.     for(lochuffstruct->loops=100L;
  2618.       lochuffstruct->loops<MAXHUFFLOOPS;
  2619.       lochuffstruct->loops+=10L)
  2620.         if(DoHuffIteration(plaintext,
  2621.             comparray,
  2622.             decomparray,
  2623.           lochuffstruct->arraysize,
  2624.           lochuffstruct->loops,
  2625.           hufftree)>global_min_ticks) break;
  2626. }
  2627.  
  2628. /*
  2629. ** All's well if we get here.  Do the test.
  2630. */
  2631. accumtime=0L;
  2632. iterations=(double)0.0;
  2633.  
  2634. do {
  2635.     accumtime+=DoHuffIteration(plaintext,
  2636.         comparray,
  2637.         decomparray,
  2638.         lochuffstruct->arraysize,
  2639.         lochuffstruct->loops,
  2640.         hufftree);
  2641.     iterations+=(double)lochuffstruct->loops;
  2642. } while(TicksToSecs(accumtime)<lochuffstruct->request_secs);
  2643.  
  2644. /*
  2645. ** Clean up, calculate results, and go home.  Be sure to
  2646. ** show that we don't have to rerun adjustment code.
  2647. */
  2648. FreeMemory((farvoid *)plaintext,&systemerror);
  2649. FreeMemory((farvoid *)comparray,&systemerror);
  2650. FreeMemory((farvoid *)decomparray,&systemerror);
  2651. FreeMemory((farvoid *)hufftree,&systemerror);
  2652. lochuffstruct->iterspersec=iterations / TicksToFracSecs(accumtime);
  2653.  
  2654. if(lochuffstruct->adjust==0)
  2655.     lochuffstruct->adjust=1;
  2656.  
  2657. }
  2658.  
  2659. /*********************
  2660. ** create_text_line **
  2661. **********************
  2662. ** Create a random line of text, stored at *dt.  The line may be
  2663. ** no more than nchars long.
  2664. */
  2665. static void create_text_line(farchar *dt,
  2666.             long nchars)
  2667. {
  2668. long charssofar;        /* # of characters so far */
  2669. long tomove;            /* # of characters to move */
  2670. char myword[40];        /* Local buffer for words */
  2671. farchar *wordptr;       /* Pointer to word from catalog */
  2672.  
  2673. charssofar=0;
  2674.  
  2675. do {
  2676. /*
  2677. ** Grab a random word from the wordcatalog
  2678. */
  2679. wordptr=wordcatarray[abs_randwc((long)WORDCATSIZE)];
  2680. MoveMemory((farvoid *)myword,
  2681.     (farvoid *)wordptr,
  2682.     (unsigned long)strlen(wordptr)+1);
  2683.  
  2684. /*
  2685. ** Append a blank.
  2686. */
  2687. tomove=strlen(myword)+1;
  2688. myword[tomove-1]=' ';
  2689.  
  2690. /*
  2691. ** See how long it is.  If its length+charssofar > nchars, we have
  2692. ** to trim it.
  2693. */
  2694. if((tomove+charssofar)>nchars)
  2695.     tomove=nchars-charssofar;
  2696. /*
  2697. ** Attach the word to the current line.  Increment counter.
  2698. */
  2699. MoveMemory((farvoid *)dt,(farvoid *)myword,(unsigned long)tomove);
  2700. charssofar+=tomove;
  2701. dt+=tomove;
  2702.  
  2703. /*
  2704. ** If we're done, bail out.  Otherwise, go get another word.
  2705. */
  2706. } while(charssofar<nchars);
  2707.  
  2708. return;
  2709. }
  2710.  
  2711. /**********************
  2712. ** create_text_block **
  2713. ***********************
  2714. ** Build a block of text randomly loaded with words.  The words
  2715. ** come from the wordcatalog (which must be loaded before you
  2716. ** call this).
  2717. ** *tb points to the memory where the text is to be built.
  2718. ** tblen is the # of bytes to put into the text block
  2719. ** maxlinlen is the maximum length of any line (line end indicated
  2720. **  by a carriage return).
  2721. */
  2722. static void create_text_block(farchar *tb,
  2723.             ulong tblen,
  2724.             ushort maxlinlen)
  2725. {
  2726. ulong bytessofar;       /* # of bytes so far */
  2727. ulong linelen;          /* Line length */
  2728.  
  2729. bytessofar=0L;
  2730. do {
  2731.  
  2732. /*
  2733. ** Pick a random length for a line and fill the line.
  2734. ** Make sure the line can fit (haven't exceeded tablen) and also
  2735. ** make sure you leave room to append a carriage return.
  2736. */
  2737. linelen=abs_randwc(maxlinlen-6)+6;
  2738. if((linelen+bytessofar)>tblen)
  2739.     linelen=tblen-bytessofar;
  2740.  
  2741. if(linelen>1)
  2742. {
  2743.     create_text_line(tb,linelen);
  2744. }
  2745. tb+=linelen-1;          /* Add the carriage return */
  2746. *tb++='\n';
  2747.  
  2748. bytessofar+=linelen;
  2749.  
  2750. } while(bytessofar<tblen);
  2751.  
  2752. }
  2753.  
  2754. /********************
  2755. ** DoHuffIteration **
  2756. *********************
  2757. ** Perform the huffman benchmark.  This routine
  2758. **  (a) Builds the huffman tree
  2759. **  (b) Compresses the text
  2760. **  (c) Decompresses the text and verifies correct decompression
  2761. */
  2762. static ulong DoHuffIteration(farchar *plaintext,
  2763.     farchar *comparray,
  2764.     farchar *decomparray,
  2765.     ulong arraysize,
  2766.     ulong nloops,
  2767.     huff_node *hufftree)
  2768. {
  2769. int i;                          /* Index */
  2770. long j;                         /* Bigger index */
  2771. int root;                       /* Pointer to huffman tree root */
  2772. float lowfreq1, lowfreq2;       /* Low frequency counters */
  2773. int lowidx1, lowidx2;           /* Indexes of low freq. elements */
  2774. long bitoffset;                 /* Bit offset into text */
  2775. long textoffset;                /* Char offset into text */
  2776. long maxbitoffset;              /* Holds limit of bit offset */
  2777. long bitstringlen;              /* Length of bitstring */
  2778. int c;                          /* Character from plaintext */
  2779. char bitstring[30];             /* Holds bitstring */
  2780. ulong elapsed;                  /* For stopwatch */
  2781.  
  2782. /*
  2783. ** Start the stopwatch
  2784. */
  2785. elapsed=StartStopwatch();
  2786.  
  2787. /*
  2788. ** Do everything for nloops
  2789. */
  2790. while(nloops--)
  2791. {
  2792.  
  2793. /*
  2794. ** Calculate the frequency of each byte value. Store the
  2795. ** results in what will become the "leaves" of the
  2796. ** Huffman tree.  Interior nodes will be built in those
  2797. ** nodes greater than node #255.
  2798. */
  2799. for(i=0;i<256;i++)
  2800. {
  2801.     hufftree[i].freq=(float)0.0;
  2802.     hufftree[i].c=(unsigned char)i;
  2803. }
  2804.  
  2805. for(j=0;j<arraysize;j++)
  2806.     hufftree[plaintext[j]].freq+=(float)1.0;
  2807.  
  2808. for(i=0;i<256;i++)
  2809.     if(hufftree[i].freq != (float)0.0)
  2810.         hufftree[i].freq/=(float)arraysize;
  2811.  
  2812. /*
  2813. ** Build the huffman tree.  First clear all the parent
  2814. ** pointers and left/right pointers.  Also, discard all
  2815. ** nodes that have a frequency of true 0.
  2816. */
  2817. for(i=0;i<512;i++)
  2818. {       if(hufftree[i].freq==(float)0.0)
  2819.         hufftree[i].parent=EXCLUDED;
  2820.     else
  2821.         hufftree[i].parent=hufftree[i].left=hufftree[i].right=-1;
  2822. }
  2823.  
  2824. /*
  2825. ** Go through the tree. Finding nodes of really low
  2826. ** frequency.
  2827. */
  2828. root=255;                       /* Starting root node-1 */
  2829. while(1)
  2830. {
  2831.     lowfreq1=(float)2.0; lowfreq2=(float)2.0;
  2832.     lowidx1=-1; lowidx2=-1;
  2833.     /*
  2834.     ** Find first lowest frequency.
  2835.     */
  2836.     for(i=0;i<=root;i++)
  2837.         if(hufftree[i].parent<0)
  2838.             if(hufftree[i].freq<lowfreq1)
  2839.             {       lowfreq1=hufftree[i].freq;
  2840.                 lowidx1=i;
  2841.             }
  2842.  
  2843.     /*
  2844.     ** Did we find a lowest value?  If not, the
  2845.     ** tree is done.
  2846.     */
  2847.     if(lowidx1==-1) break;
  2848.  
  2849.     /*
  2850.     ** Find next lowest frequency
  2851.     */
  2852.     for(i=0;i<=root;i++)
  2853.         if((hufftree[i].parent<0) && (i!=lowidx1))
  2854.             if(hufftree[i].freq<lowfreq2)
  2855.             {       lowfreq2=hufftree[i].freq;
  2856.                 lowidx2=i;
  2857.             }
  2858.  
  2859.     /*
  2860.     ** If we could only find one item, then that
  2861.     ** item is surely the root, and (as above) the
  2862.     ** tree is done.
  2863.     */
  2864.     if(lowidx2==-1) break;
  2865.  
  2866.     /*
  2867.     ** Attach the two new nodes to the current root, and
  2868.     ** advance the current root.
  2869.     */
  2870.     root++;                 /* New root */
  2871.     hufftree[lowidx1].parent=root;
  2872.     hufftree[lowidx2].parent=root;
  2873.     hufftree[root].freq=lowfreq1+lowfreq2;
  2874.     hufftree[root].left=lowidx1;
  2875.     hufftree[root].right=lowidx2;
  2876.     hufftree[root].parent=-2;       /* Show root */
  2877. }
  2878.  
  2879. /*
  2880. ** Huffman tree built...compress the plaintext
  2881. */
  2882. bitoffset=0L;                           /* Initialize bit offset */
  2883. for(i=0;i<arraysize;i++)
  2884. {
  2885.     c=(int)plaintext[i];                 /* Fetch character */
  2886.     /*
  2887.     ** Build a bit string for byte c
  2888.     */
  2889.     bitstringlen=0;
  2890.     while(hufftree[c].parent!=-2)
  2891.     {       if(hufftree[hufftree[c].parent].left==c)
  2892.             bitstring[bitstringlen]='0';
  2893.         else
  2894.             bitstring[bitstringlen]='1';
  2895.         c=hufftree[c].parent;
  2896.         bitstringlen++;
  2897.     }
  2898.  
  2899.     /*
  2900.     ** Step backwards through the bit string, setting
  2901.     ** bits in the compressed array as you go.
  2902.     */
  2903.     while(bitstringlen--)
  2904.     {       SetCompBit((u8 *)comparray,(u32)bitoffset,bitstring[bitstringlen]);
  2905.         bitoffset++;
  2906.     }
  2907. }
  2908.  
  2909. /*
  2910. ** Compression done.  Perform de-compression.
  2911. */
  2912. maxbitoffset=bitoffset;
  2913. bitoffset=0;
  2914. textoffset=0;
  2915. do {
  2916.     i=root;
  2917.     while(hufftree[i].left!=-1)
  2918.     {       if(GetCompBit((u8 *)comparray,(u32)bitoffset)==0)
  2919.             i=hufftree[i].left;
  2920.         else
  2921.             i=hufftree[i].right;
  2922.         bitoffset++;
  2923.     }
  2924.     decomparray[textoffset]=hufftree[i].c;
  2925.  
  2926. #ifdef DEBUG
  2927.     if(hufftree[i].c != plaintext[textoffset])
  2928.     {
  2929.         /* Show error */
  2930.         printf("Error at textoffset %d\n",textoffset);
  2931.     }
  2932. #endif
  2933.     textoffset++;
  2934. } while(bitoffset<maxbitoffset);
  2935.  
  2936. }       /* End the big while(nloops--) from above */
  2937.  
  2938. /*
  2939. ** All done
  2940. */
  2941. return(StopStopwatch(elapsed));
  2942. }
  2943.  
  2944. /***************
  2945. ** SetCompBit **
  2946. ****************
  2947. ** Set a bit in the compression array.  The value of the
  2948. ** bit is set according to char bitchar.
  2949. */
  2950. static void SetCompBit(u8 *comparray,
  2951.         u32 bitoffset,
  2952.         char bitchar)
  2953. {
  2954. u32 byteoffset;
  2955. int bitnumb;
  2956.  
  2957. /*
  2958. ** First calculate which element in the comparray to
  2959. ** alter. and the bitnumber.
  2960. */
  2961. byteoffset=bitoffset>>3;
  2962. bitnumb=bitoffset % 8;
  2963.  
  2964. /*
  2965. ** Set or clear
  2966. */
  2967. if(bitchar=='1')
  2968.     comparray[byteoffset]|=(1<<bitnumb);
  2969. else
  2970.     comparray[byteoffset]&=~(1<<bitnumb);
  2971.  
  2972. return;
  2973. }
  2974.  
  2975. /***************
  2976. ** GetCompBit **
  2977. ****************
  2978. ** Return the bit value of a bit in the comparession array.
  2979. ** Returns 0 if the bit is clear, nonzero otherwise.
  2980. */
  2981. static int GetCompBit(u8 *comparray,
  2982.         u32 bitoffset)
  2983. {
  2984. u32 byteoffset;
  2985. int bitnumb;
  2986.  
  2987. /*
  2988. ** Calculate byte offset and bit number.
  2989. */
  2990. byteoffset=bitoffset>>3;
  2991. bitnumb=bitoffset % 8;
  2992.  
  2993. /*
  2994. ** Fetch
  2995. */
  2996. return((1<<bitnumb) & comparray[byteoffset] );
  2997. }
  2998.  
  2999. /********************************
  3000. ** BACK PROPAGATION NEURAL NET **
  3001. *********************************
  3002. ** This code is a modified version of the code
  3003. ** that was submitted to BYTE Magazine by
  3004. ** Maureen Caudill.  It accomanied an article
  3005. ** that I CANNOT NOW RECALL.
  3006. ** The author's original heading/comment was
  3007. ** as follows:
  3008. **
  3009. **  Backpropagation Network
  3010. **  Written by Maureen Caudill
  3011. **  in Think C 4.0 on a Macintosh
  3012. **
  3013. **  (c) Maureen Caudill 1988-1991
  3014. **  This network will accept 5x7 input patterns
  3015. **  and produce 8 bit output patterns.
  3016. **  The source code may be copied or modified without restriction,
  3017. **  but no fee may be charged for its use.
  3018. **
  3019. ** ++++++++++++++
  3020. ** I have modified the code so that it will work
  3021. ** on systems other than a Macintosh -- RG
  3022. */
  3023.  
  3024. /***********
  3025. ** DoNNet **
  3026. ************
  3027. ** Perform the neural net benchmark.
  3028. ** Note that this benchmark is one of the few that
  3029. ** requires an input file.  That file is "NNET.DAT" and
  3030. ** should be on the local directory (from which the
  3031. ** benchmark program in launched).
  3032. */
  3033. void DoNNET(void)
  3034. {
  3035. NNetStruct *locnnetstruct;      /* Local ptr to global data */
  3036. char *errorcontext;
  3037. int systemerror;
  3038. ulong accumtime;
  3039. double iterations;
  3040.  
  3041. /*
  3042. ** Link to global data
  3043. */
  3044. locnnetstruct=&global_nnetstruct;
  3045.  
  3046. /*
  3047. ** Set error context
  3048. */
  3049. errorcontext="CPU:NNET";
  3050.  
  3051. /*
  3052. ** Init random number generator.
  3053. ** NOTE: It is important that the random number generator
  3054. **  be re-initialized for every pass through this test.
  3055. **  The NNET algorithm uses the random number generator
  3056. **  to initialize the net.  Results are sensitive to
  3057. **  the initial neural net state.
  3058. */
  3059. randnum(3L);
  3060.  
  3061. /*
  3062. ** Read in the input and output patterns.  We'll do this
  3063. ** only once here at the beginning.  These values don't
  3064. ** change once loaded.
  3065. */
  3066. if(read_data_file()!=0)
  3067.    ErrorExit();
  3068.  
  3069.  
  3070. /*
  3071. ** See if we need to perform self adjustment loop.
  3072. */
  3073. if(locnnetstruct->adjust==0)
  3074. {
  3075.     /*
  3076.     ** Do self-adjustment.  This involves initializing the
  3077.     ** # of loops and increasing the loop count until we
  3078.     ** get a number of loops that we can use.
  3079.     */
  3080.     for(locnnetstruct->loops=1L;
  3081.       locnnetstruct->loops<MAXNNETLOOPS;
  3082.       locnnetstruct->loops++)
  3083.       {     randnum(3L);
  3084.         if(DoNNetIteration(locnnetstruct->loops)
  3085.             >global_min_ticks) break;
  3086.       }
  3087. }
  3088.  
  3089. /*
  3090. ** All's well if we get here.  Do the test.
  3091. */
  3092. accumtime=0L;
  3093. iterations=(double)0.0;
  3094.  
  3095. do {
  3096.     randnum(3L);    /* Gotta do this for Neural Net */
  3097.     accumtime+=DoNNetIteration(locnnetstruct->loops);
  3098.     iterations+=(double)locnnetstruct->loops;
  3099. } while(TicksToSecs(accumtime)<locnnetstruct->request_secs);
  3100.  
  3101. /*
  3102. ** Clean up, calculate results, and go home.  Be sure to
  3103. ** show that we don't have to rerun adjustment code.
  3104. */
  3105. locnnetstruct->iterspersec=iterations / TicksToFracSecs(accumtime);
  3106.  
  3107. if(locnnetstruct->adjust==0)
  3108.     locnnetstruct->adjust=1;
  3109.  
  3110.  
  3111. return;
  3112. }
  3113.  
  3114. /********************
  3115. ** DoNNetIteration **
  3116. *********************
  3117. ** Do a single iteration of the neural net benchmark.
  3118. ** By iteration, we mean a "learning" pass.
  3119. */
  3120. static ulong DoNNetIteration(ulong nloops)
  3121. {
  3122. ulong elapsed;          /* Elapsed time */
  3123. int patt;
  3124.  
  3125. /*
  3126. ** Run nloops learning cycles.  Notice that, counted with
  3127. ** the learning cycle is the weight randomization and
  3128. ** zeroing of changes.  This should reduce clock jitter,
  3129. ** since we don't have to stop and start the clock for
  3130. ** each iteration.
  3131. */
  3132. elapsed=StartStopwatch();
  3133. while(nloops--)
  3134. {
  3135.     randomize_wts();
  3136.     zero_changes();
  3137.     iteration_count=1;
  3138.     learned = F;
  3139.     numpasses = 0;
  3140.     while (learned == F)
  3141.     {
  3142.         for (patt=0; patt<numpats; patt++)
  3143.         {
  3144.             worst_error = 0.0;      /* reset this every pass through data */
  3145.             move_wt_changes();      /* move last pass's wt changes to momentum array */
  3146.             do_forward_pass(patt);
  3147.             do_back_pass(patt);
  3148.             iteration_count++;
  3149.         }
  3150.         numpasses ++;
  3151.         learned = check_out_error();
  3152.     }
  3153. #ifdef DEBUG
  3154. printf("Learned in %d passes\n",numpasses);
  3155. #endif
  3156. }
  3157. return(StopStopwatch(elapsed));
  3158. }
  3159.  
  3160. /*************************
  3161. ** do_mid_forward(patt) **
  3162. **************************
  3163. ** Process the middle layer's forward pass
  3164. ** The activation of middle layer's neurode is the weighted
  3165. ** sum of the inputs from the input pattern, with sigmoid
  3166. ** function applied to the inputs.
  3167. **/
  3168. static void  do_mid_forward(int patt)
  3169. {
  3170. double  sum;
  3171. int     neurode, i;
  3172.  
  3173. for (neurode=0;neurode<MID_SIZE; neurode++)
  3174. {
  3175.     sum = 0.0;
  3176.     for (i=0; i<IN_SIZE; i++)
  3177.     {       /* compute weighted sum of input signals */
  3178.         sum += mid_wts[neurode][i]*in_pats[patt][i];
  3179.     }
  3180.     /*
  3181.     ** apply sigmoid function f(x) = 1/(1+exp(-x)) to weighted sum
  3182.     */
  3183.     sum = 1.0/(1.0+exp(-sum));
  3184.     mid_out[neurode] = sum;
  3185. }
  3186. return;
  3187. }
  3188.  
  3189. /*********************
  3190. ** do_out_forward() **
  3191. **********************
  3192. ** process the forward pass through the output layer
  3193. ** The activation of the output layer is the weighted sum of
  3194. ** the inputs (outputs from middle layer), modified by the
  3195. ** sigmoid function.
  3196. **/
  3197. static void  do_out_forward()
  3198. {
  3199. double sum;
  3200. int neurode, i;
  3201.  
  3202. for (neurode=0; neurode<OUT_SIZE; neurode++)
  3203. {
  3204.     sum = 0.0;
  3205.     for (i=0; i<MID_SIZE; i++)
  3206.     {       /*
  3207.         ** compute weighted sum of input signals
  3208.         ** from middle layer
  3209.         */
  3210.         sum += out_wts[neurode][i]*mid_out[i];
  3211.     }
  3212.     /*
  3213.     ** Apply f(x) = 1/(1+exp(-x)) to weighted input
  3214.     */
  3215.     sum = 1.0/(1.0+exp(-sum));
  3216.     out_out[neurode] = sum;
  3217. }
  3218. return;
  3219. }
  3220.  
  3221. /*************************
  3222. ** display_output(patt) **
  3223. **************************
  3224. ** Display the actual output vs. the desired output of the
  3225. ** network.
  3226. ** Once the training is complete, and the "learned" flag set
  3227. ** to TRUE, then display_output sends its output to both
  3228. ** the screen and to a text output file.
  3229. **
  3230. ** NOTE: This routine has been disabled in the benchmark
  3231. ** version. -- RG
  3232. **/
  3233. /*
  3234. void  display_output(int patt)
  3235. {
  3236. int             i;
  3237.  
  3238.     fprintf(outfile,"\n Iteration # %d",iteration_count);
  3239.     fprintf(outfile,"\n Desired Output:  ");
  3240.  
  3241.     for (i=0; i<OUT_SIZE; i++)
  3242.     {
  3243.         fprintf(outfile,"%6.3f  ",out_pats[patt][i]);
  3244.     }
  3245.     fprintf(outfile,"\n Actual Output:   ");
  3246.  
  3247.     for (i=0; i<OUT_SIZE; i++)
  3248.     {
  3249.         fprintf(outfile,"%6.3f  ",out_out[i]);
  3250.     }
  3251.     fprintf(outfile,"\n");
  3252.     return;
  3253. }
  3254. */
  3255.  
  3256. /**********************
  3257. ** do_forward_pass() **
  3258. ***********************
  3259. ** control function for the forward pass through the network
  3260. ** NOTE: I have disabled the call to display_output() in
  3261. **  the benchmark version -- RG.
  3262. **/
  3263. static void  do_forward_pass(int patt)
  3264. {
  3265. do_mid_forward(patt);   /* process forward pass, middle layer */
  3266. do_out_forward();       /* process forward pass, output layer */
  3267. /* display_output(patt);        ** display results of forward pass */
  3268. return;
  3269. }
  3270.  
  3271. /***********************
  3272. ** do_out_error(patt) **
  3273. ************************
  3274. ** Compute the error for the output layer neurodes.
  3275. ** This is simply Desired - Actual.
  3276. **/
  3277. static void do_out_error(int patt)
  3278. {
  3279. int neurode;
  3280. double error,tot_error, sum;
  3281.  
  3282. tot_error = 0.0;
  3283. sum = 0.0;
  3284. for (neurode=0; neurode<OUT_SIZE; neurode++)
  3285. {
  3286.     out_error[neurode] = out_pats[patt][neurode] - out_out[neurode];
  3287.     /*
  3288.     ** while we're here, also compute magnitude
  3289.     ** of total error and worst error in this pass.
  3290.     ** We use these to decide if we are done yet.
  3291.     */
  3292.     error = out_error[neurode];
  3293.     if (error <0.0)
  3294.     {
  3295.         sum += -error;
  3296.         if (-error > tot_error)
  3297.             tot_error = -error; /* worst error this pattern */
  3298.     }
  3299.     else
  3300.     {
  3301.         sum += error;
  3302.         if (error > tot_error)
  3303.             tot_error = error; /* worst error this pattern */
  3304.     }
  3305. }
  3306. avg_out_error[patt] = sum/OUT_SIZE;
  3307. tot_out_error[patt] = tot_error;
  3308. return;
  3309. }
  3310.  
  3311. /***********************
  3312. ** worst_pass_error() **
  3313. ************************
  3314. ** Find the worst and average error in the pass and save it
  3315. **/
  3316. static void  worst_pass_error()
  3317. {
  3318. double error,sum;
  3319.  
  3320. int i;
  3321.  
  3322. error = 0.0;
  3323. sum = 0.0;
  3324. for (i=0; i<numpats; i++)
  3325. {
  3326.     if (tot_out_error[i] > error) error = tot_out_error[i];
  3327.     sum += avg_out_error[i];
  3328. }
  3329. worst_error = error;
  3330. average_error = sum/numpats;
  3331. return;
  3332. }
  3333.  
  3334. /*******************
  3335. ** do_mid_error() **
  3336. ********************
  3337. ** Compute the error for the middle layer neurodes
  3338. ** This is based on the output errors computed above.
  3339. ** Note that the derivative of the sigmoid f(x) is
  3340. **        f'(x) = f(x)(1 - f(x))
  3341. ** Recall that f(x) is merely the output of the middle
  3342. ** layer neurode on the forward pass.
  3343. **/
  3344. static void do_mid_error()
  3345. {
  3346. double sum;
  3347. int neurode, i;
  3348.  
  3349. for (neurode=0; neurode<MID_SIZE; neurode++)
  3350. {
  3351.     sum = 0.0;
  3352.     for (i=0; i<OUT_SIZE; i++)
  3353.         sum += out_wts[i][neurode]*out_error[i];
  3354.  
  3355.     /*
  3356.     ** apply the derivative of the sigmoid here
  3357.     ** Because of the choice of sigmoid f(I), the derivative
  3358.     ** of the sigmoid is f'(I) = f(I)(1 - f(I))
  3359.     */
  3360.     mid_error[neurode] = mid_out[neurode]*(1-mid_out[neurode])*sum;
  3361. }
  3362. return;
  3363. }
  3364.  
  3365. /*********************
  3366. ** adjust_out_wts() **
  3367. **********************
  3368. ** Adjust the weights of the output layer.  The error for
  3369. ** the output layer has been previously propagated back to
  3370. ** the middle layer.
  3371. ** Use the Delta Rule with momentum term to adjust the weights.
  3372. **/
  3373. static void adjust_out_wts()
  3374. {
  3375. int weight, neurode;
  3376. double learn,delta,alph;
  3377.  
  3378. learn = BETA;
  3379. alph  = ALPHA;
  3380. for (neurode=0; neurode<OUT_SIZE; neurode++)
  3381. {
  3382.     for (weight=0; weight<MID_SIZE; weight++)
  3383.     {
  3384.         /* standard delta rule */
  3385.         delta = learn * out_error[neurode] * mid_out[weight];
  3386.  
  3387.         /* now the momentum term */
  3388.         delta += alph * out_wt_change[neurode][weight];
  3389.         out_wts[neurode][weight] += delta;
  3390.  
  3391.         /* keep track of this pass's cum wt changes for next pass's momentum */
  3392.         out_wt_cum_change[neurode][weight] += delta;
  3393.     }
  3394. }
  3395. return;
  3396. }
  3397.  
  3398. /*************************
  3399. ** adjust_mid_wts(patt) **
  3400. **************************
  3401. ** Adjust the middle layer weights using the previously computed
  3402. ** errors.
  3403. ** We use the Generalized Delta Rule with momentum term
  3404. **/
  3405. static void adjust_mid_wts(int patt)
  3406. {
  3407. int weight, neurode;
  3408. double learn,alph,delta;
  3409.  
  3410. learn = BETA;
  3411. alph  = ALPHA;
  3412. for (neurode=0; neurode<MID_SIZE; neurode++)
  3413. {
  3414.     for (weight=0; weight<IN_SIZE; weight++)
  3415.     {
  3416.         /* first the basic delta rule */
  3417.         delta = learn * mid_error[neurode] * in_pats[patt][weight];
  3418.  
  3419.         /* with the momentum term */
  3420.         delta += alph * mid_wt_change[neurode][weight];
  3421.         mid_wts[neurode][weight] += delta;
  3422.  
  3423.         /* keep track of this pass's cum wt changes for next pass's momentum */
  3424.         mid_wt_cum_change[neurode][weight] += delta;
  3425.     }
  3426. }
  3427. return;
  3428. }
  3429.  
  3430. /*******************
  3431. ** do_back_pass() **
  3432. ********************
  3433. ** Process the backward propagation of error through network.
  3434. **/
  3435. void  do_back_pass(int patt)
  3436. {
  3437.  
  3438. do_out_error(patt);
  3439. do_mid_error();
  3440. adjust_out_wts();
  3441. adjust_mid_wts(patt);
  3442.  
  3443. return;
  3444. }
  3445.  
  3446.  
  3447. /**********************
  3448. ** move_wt_changes() **
  3449. ***********************
  3450. ** Move the weight changes accumulated last pass into the wt-change
  3451. ** array for use by the momentum term in this pass. Also zero out
  3452. ** the accumulating arrays after the move.
  3453. **/
  3454. static void move_wt_changes()
  3455. {
  3456. int i,j;
  3457.  
  3458. for (i = 0; i<MID_SIZE; i++)
  3459.     for (j = 0; j<IN_SIZE; j++)
  3460.     {
  3461.         mid_wt_change[i][j] = mid_wt_cum_change[i][j];
  3462.         /*
  3463.         ** Zero it out for next pass accumulation.
  3464.         */
  3465.         mid_wt_cum_change[i][j] = 0.0;
  3466.     }
  3467.  
  3468. for (i = 0; i<OUT_SIZE; i++)
  3469.     for (j=0; j<MID_SIZE; j++)
  3470.     {
  3471.         out_wt_change[i][j] = out_wt_cum_change[i][j];
  3472.         out_wt_cum_change[i][j] = 0.0;
  3473.     }
  3474.  
  3475. return;
  3476. }
  3477.  
  3478. /**********************
  3479. ** check_out_error() **
  3480. ***********************
  3481. ** Check to see if the error in the output layer is below
  3482. ** MARGIN*OUT_SIZE for all output patterns.  If so, then
  3483. ** assume the network has learned acceptably well.  This
  3484. ** is simply an arbitrary measure of how well the network
  3485. ** has learned -- many other standards are possible.
  3486. **/
  3487. static int check_out_error()
  3488. {
  3489. int result,i,error;
  3490.  
  3491. result  = T;
  3492. error   = F;
  3493. worst_pass_error();     /* identify the worst error in this pass */
  3494.  
  3495. /*
  3496. #ifdef DEBUG
  3497. printf("\n Iteration # %d",iteration_count);
  3498. #endif
  3499. */
  3500. for (i=0; i<numpats; i++)
  3501. {
  3502. /*      printf("\n Error pattern %d:   Worst: %8.3f; Average: %8.3f",
  3503.       i+1,tot_out_error[i], avg_out_error[i]);
  3504.     fprintf(outfile,
  3505.      "\n Error pattern %d:   Worst: %8.3f; Average: %8.3f",
  3506.      i+1,tot_out_error[i]);
  3507. */
  3508.  
  3509.     if (worst_error >= STOP) result = F;
  3510.     if (tot_out_error[i] >= 16.0) error = T;
  3511. }
  3512.  
  3513. if (error == T) result = ERR;
  3514.  
  3515.  
  3516. #ifdef DEBUG
  3517. /* printf("\n Error this pass thru data:   Worst: %8.3f; Average: %8.3f",
  3518.  worst_error,average_error);
  3519. */
  3520. /* fprintf(outfile,
  3521.  "\n Error this pass thru data:   Worst: %8.3f; Average: %8.3f",
  3522.   worst_error, average_error); */
  3523. #endif
  3524.  
  3525. return(result);
  3526. }
  3527.  
  3528.  
  3529. /*******************
  3530. ** zero_changes() **
  3531. ********************
  3532. ** Zero out all the wt change arrays
  3533. **/
  3534. static void zero_changes()
  3535. {
  3536. int i,j;
  3537.  
  3538. for (i = 0; i<MID_SIZE; i++)
  3539. {
  3540.     for (j=0; j<IN_SIZE; j++)
  3541.     {
  3542.         mid_wt_change[i][j] = 0.0;
  3543.         mid_wt_cum_change[i][j] = 0.0;
  3544.     }
  3545. }
  3546.  
  3547. for (i = 0; i< OUT_SIZE; i++)
  3548. {
  3549.     for (j=0; j<MID_SIZE; j++)
  3550.     {
  3551.         out_wt_change[i][j] = 0.0;
  3552.         out_wt_cum_change[i][j] = 0.0;
  3553.     }
  3554. }
  3555. return;
  3556. }
  3557.  
  3558.  
  3559. /********************
  3560. ** randomize_wts() **
  3561. *********************
  3562. ** Intialize the weights in the middle and output layers to
  3563. ** random values between -0.25..+0.25
  3564. ** Function rand() returns a value between 0 and 32767.
  3565. **
  3566. ** NOTE: Had to make alterations to how the random numbers were
  3567. ** created.  -- RG.
  3568. **/
  3569. static void randomize_wts()
  3570. {
  3571. int neurode,i;
  3572. double value;
  3573.  
  3574. /*
  3575. ** Following not used int benchmark version -- RG
  3576. **
  3577. **        printf("\n Please enter a random number seed (1..32767):  ");
  3578. **        scanf("%d", &i);
  3579. **        srand(i);
  3580. */
  3581. for (neurode = 0; neurode<MID_SIZE; neurode++)
  3582. {
  3583.     for(i=0; i<IN_SIZE; i++)
  3584.     {
  3585.         value=(double)abs_randwc(100000L);
  3586.         value=value/(double)100000.0 - (double) 0.5;
  3587.         mid_wts[neurode][i] = value/2;
  3588.     }
  3589. }
  3590.  
  3591. for (neurode=0; neurode<OUT_SIZE; neurode++)
  3592. {
  3593.     for(i=0; i<MID_SIZE; i++)
  3594.     {
  3595.         value=(double)abs_randwc(100000L);
  3596.         value=value/(double)10000.0 - (double) 0.5;
  3597.         out_wts[neurode][i] = value/2;
  3598.     }
  3599. }
  3600. return;
  3601. }
  3602.  
  3603.  
  3604. /*********************
  3605. ** read_data_file() **
  3606. **********************
  3607. ** Read in the input data file and store the patterns in
  3608. ** in_pats and out_pats.
  3609. ** The format for the data file is as follows:
  3610. **
  3611. ** line#   data expected
  3612. ** -----   ------------------------------
  3613. ** 1               In-X-size,in-y-size,out-size
  3614. ** 2               number of patterns in file
  3615. ** 3               1st X row of 1st input pattern
  3616. ** 4..             following rows of 1st input pattern pattern
  3617. **                 in-x+2  y-out pattern
  3618. **                                 1st X row of 2nd pattern
  3619. **                 etc.
  3620. **
  3621. ** Each row of data is separated by commas or spaces.
  3622. ** The data is expected to be ascii text corresponding to
  3623. ** either a +1 or a 0.
  3624. **
  3625. ** Sample input for a 1-pattern file (The comments to the
  3626. ** right may NOT be in the file unless more sophisticated
  3627. ** parsing of the input is done.):
  3628. **
  3629. ** 5,7,8                      input is 5x7 grid, output is 8 bits
  3630. ** 1                          one pattern in file
  3631. ** 0,1,1,1,0                  beginning of pattern for "O"
  3632. ** 1,0,0,0,1
  3633. ** 1,0,0,0,1
  3634. ** 1,0,0,0,1
  3635. ** 1,0,0,0,1
  3636. ** 1,0,0,0,0
  3637. ** 0,1,1,1,0
  3638. ** 0,1,0,0,1,1,1,1            ASCII code for "O" -- 0100 1111
  3639. **
  3640. ** Clearly, this simple scheme can be expanded or enhanced
  3641. ** any way you like.
  3642. **
  3643. ** Returns -1 if any file error occurred, otherwise 0.
  3644. **/
  3645. static int read_data_file()
  3646. {
  3647. FILE *infile;
  3648.  
  3649. int xinsize,yinsize,youtsize;
  3650. int patt, element, i, row;
  3651. int vals_read;
  3652. int val1,val2,val3,val4,val5,val6,val7,val8;
  3653.  
  3654. /* printf("\n Opening and retrieving data from file."); */
  3655.  
  3656. infile = fopen(inpath, "r");
  3657. if (infile == NULL)
  3658. {
  3659.     printf("\n CPU:NNET--error in opening file!");
  3660.     return -1 ;
  3661. }
  3662. vals_read =fscanf(infile,"%d  %d  %d",&xinsize,&yinsize,&youtsize);
  3663. if (vals_read != 3)
  3664. {
  3665.     printf("\n CPU:NNET -- Should read 3 items in line one; did read %d",vals_read);
  3666.     return -1;
  3667. }
  3668. vals_read=fscanf(infile,"%d",&numpats);
  3669. if (vals_read !=1)
  3670. {
  3671.     printf("\n CPU:NNET -- Should read 1 item in line 2; did read &d",vals_read);
  3672.     return -1;
  3673. }
  3674. if (numpats > MAXPATS)
  3675.     numpats = MAXPATS;
  3676.  
  3677. for (patt=0; patt<numpats; patt++)
  3678. {
  3679.     element = 0;
  3680.     for (row = 0; row<yinsize; row++)
  3681.     {
  3682.         vals_read = fscanf(infile,"%d  %d  %d  %d  %d",
  3683.             &val1, &val2, &val3, &val4, &val5);
  3684.         if (vals_read != 5)
  3685.         {
  3686.             printf ("\n CPU:NNET -- failure in reading input!");
  3687.             return -1;
  3688.         }
  3689.         element=row*xinsize;
  3690.  
  3691.         in_pats[patt][element] = (double) val1; element++;
  3692.         in_pats[patt][element] = (double) val2; element++;
  3693.         in_pats[patt][element] = (double) val3; element++;
  3694.         in_pats[patt][element] = (double) val4; element++;
  3695.         in_pats[patt][element] = (double) val5; element++;
  3696.     }
  3697.     for (i=0;i<IN_SIZE; i++)
  3698.     {
  3699.         if (in_pats[patt][i] >= 0.9)
  3700.             in_pats[patt][i] = 0.9;
  3701.         if (in_pats[patt][i] <= 0.1)
  3702.             in_pats[patt][i] = 0.1;
  3703.     }
  3704.     element = 0;
  3705.     vals_read = fscanf(infile,"%d  %d  %d  %d  %d  %d  %d  %d",
  3706.         &val1, &val2, &val3, &val4, &val5, &val6, &val7, &val8);
  3707.  
  3708.     out_pats[patt][element] = (double) val1; element++;
  3709.     out_pats[patt][element] = (double) val2; element++;
  3710.     out_pats[patt][element] = (double) val3; element++;
  3711.     out_pats[patt][element] = (double) val4; element++;
  3712.     out_pats[patt][element] = (double) val5; element++;
  3713.     out_pats[patt][element] = (double) val6; element++;
  3714.     out_pats[patt][element] = (double) val7; element++;
  3715.     out_pats[patt][element] = (double) val8; element++;
  3716. }
  3717.  
  3718. /* printf("\n Closing the input file now. "); */
  3719.  
  3720. fclose(infile);
  3721. return(0);
  3722. }
  3723.  
  3724. /*********************
  3725. ** initialize_net() **
  3726. **********************
  3727. ** Do all the initialization stuff before beginning
  3728. */
  3729. static int initialize_net()
  3730. {
  3731. int err_code;
  3732.  
  3733. randomize_wts();
  3734. zero_changes();
  3735. err_code = read_data_file();
  3736. iteration_count = 1;
  3737. return(err_code);
  3738. }
  3739.  
  3740. /**********************
  3741. ** display_mid_wts() **
  3742. ***********************
  3743. ** Display the weights on the middle layer neurodes
  3744. ** NOTE: This routine is not used in the benchmark
  3745. **  test -- RG
  3746. **/
  3747. /* static void display_mid_wts()
  3748. {
  3749. int             neurode, weight, row, col;
  3750.  
  3751. fprintf(outfile,"\n Weights of Middle Layer neurodes:");
  3752.  
  3753. for (neurode=0; neurode<MID_SIZE; neurode++)
  3754. {
  3755.     fprintf(outfile,"\n  Mid Neurode # %d",neurode);
  3756.     for (row=0; row<IN_Y_SIZE; row++)
  3757.     {
  3758.         fprintf(outfile,"\n ");
  3759.         for (col=0; col<IN_X_SIZE; col++)
  3760.         {
  3761.             weight = IN_X_SIZE * row + col;
  3762.             fprintf(outfile," %8.3f ", mid_wts[neurode][weight]);
  3763.         }
  3764.     }
  3765. }
  3766. return;
  3767. }
  3768. */
  3769. /**********************
  3770. ** display_out_wts() **
  3771. ***********************
  3772. ** Display the weights on the output layer neurodes
  3773. ** NOTE: This code is not used in the benchmark
  3774. **  test -- RG
  3775. */
  3776. /* void  display_out_wts()
  3777. {
  3778. int             neurode, weight;
  3779.  
  3780.     fprintf(outfile,"\n Weights of Output Layer neurodes:");
  3781.  
  3782.     for (neurode=0; neurode<OUT_SIZE; neurode++)
  3783.     {
  3784.         fprintf(outfile,"\n  Out Neurode # %d \n",neurode);
  3785.         for (weight=0; weight<MID_SIZE; weight++)
  3786.         {
  3787.             fprintf(outfile," %8.3f ", out_wts[neurode][weight]);
  3788.         }
  3789.     }
  3790.     return;
  3791. }
  3792. */
  3793.  
  3794. /***********************
  3795. **  LU DECOMPOSITION  **
  3796. ** (Linear Equations) **
  3797. ************************
  3798. ** These routines come from "Numerical Recipes in Pascal".
  3799. ** Note that, as in the assignment algorithm, though we
  3800. ** separately define LUARRAYROWS and LUARRAYCOLS, the two
  3801. ** must be the same value (this routine depends on a square
  3802. ** matrix).
  3803. */
  3804.  
  3805. /*********
  3806. ** DoLU **
  3807. **********
  3808. ** Perform the LU decomposition benchmark.
  3809. */
  3810. void DoLU(void)
  3811. {
  3812. LUStruct *loclustruct;  /* Local pointer to global data */
  3813. char *errorcontext;
  3814. int systemerror;
  3815. fardouble *a;
  3816. fardouble *b;
  3817. fardouble *abase;
  3818. fardouble *bbase;
  3819. LUdblptr ptra;
  3820. int n;
  3821. int i;
  3822. ulong accumtime;
  3823. double iterations;
  3824.  
  3825. /*
  3826. ** Link to global data
  3827. */
  3828. loclustruct=&global_lustruct;
  3829.  
  3830. /*
  3831. ** Set error context.
  3832. */
  3833. errorcontext="FPU:LU";
  3834.  
  3835. /*
  3836. ** Our first step is to build a "solvable" problem.  This
  3837. ** will become the "seed" set that all others will be
  3838. ** derived from. (I.E., we'll simply copy these arrays
  3839. ** into the others.
  3840. */
  3841. a=(fardouble *)AllocateMemory(sizeof(double) * LUARRAYCOLS * LUARRAYROWS,
  3842.         &systemerror);
  3843. b=(fardouble *)AllocateMemory(sizeof(double) * LUARRAYROWS,
  3844.         &systemerror);
  3845. n=LUARRAYROWS;
  3846.  
  3847. /*
  3848. ** We need to allocate a temp vector that is used by the LU
  3849. ** algorithm.  This removes the allocation routine from the
  3850. ** timing.
  3851. */
  3852. LUtempvv=(fardouble *)AllocateMemory(sizeof(double)*LUARRAYROWS,
  3853.     &systemerror);
  3854.  
  3855. /*
  3856. ** Build a problem to be solved.
  3857. */
  3858. ptra.ptrs.p=a;                  /* Gotta coerce linear array to 2D array */
  3859. build_problem(*ptra.ptrs.ap,n,b);
  3860.  
  3861. /*
  3862. ** Now that we have a problem built, see if we need to do
  3863. ** auto-adjust.  If so, repeatedly call the DoLUIteration routine,
  3864. ** increasing the number of solutions per iteration as you go.
  3865. */
  3866. if(loclustruct->adjust==0)
  3867. {
  3868.     loclustruct->numarrays=0;
  3869.     for(i=1;i<=MAXLUARRAYS;i++)
  3870.     {
  3871.         abase=(fardouble *)AllocateMemory(sizeof(double) *
  3872.             LUARRAYCOLS*LUARRAYROWS*(i+1),&systemerror);
  3873.         if(systemerror)
  3874.         {       ReportError(errorcontext,systemerror);
  3875.             LUFreeMem(a,b,(fardouble *)NULL,(fardouble *)NULL);
  3876.             ErrorExit();
  3877.         }
  3878.         bbase=(fardouble *)AllocateMemory(sizeof(double) *
  3879.             LUARRAYROWS*(i+1),&systemerror);
  3880.         if(systemerror)
  3881.         {       ReportError(errorcontext,systemerror);
  3882.             LUFreeMem(a,b,abase,(fardouble *)NULL);
  3883.             ErrorExit();
  3884.         }
  3885.         if(DoLUIteration(a,b,abase,bbase,i)>global_min_ticks)
  3886.         {       loclustruct->numarrays=i;
  3887.             break;
  3888.         }
  3889.                 /*
  3890.                 ** Not enough arrays...free them all and try again
  3891.                 */
  3892.                 FreeMemory((farvoid *)abase,&systemerror);
  3893.                 FreeMemory((farvoid *)bbase,&systemerror);
  3894.     }
  3895.     /*
  3896.     ** Were we able to do it?
  3897.     */
  3898.     if(loclustruct->numarrays==0)
  3899.     {       printf("FPU:LU -- Array limit reached\n");
  3900.         LUFreeMem(a,b,abase,bbase);
  3901.         ErrorExit();
  3902.     }
  3903. }
  3904. else
  3905. {       /*
  3906.     ** Don't need to adjust -- just allocate the proper
  3907.     ** number of arrays and proceed.
  3908.     */
  3909.     abase=(fardouble *)AllocateMemory(sizeof(double) *
  3910.         LUARRAYCOLS*LUARRAYROWS*loclustruct->numarrays,
  3911.         &systemerror);
  3912.     if(systemerror)
  3913.     {       ReportError(errorcontext,systemerror);
  3914.         LUFreeMem(a,b,(fardouble *)NULL,(fardouble *)NULL);
  3915.         ErrorExit();
  3916.     }
  3917.     bbase=(fardouble *)AllocateMemory(sizeof(double) *
  3918.         LUARRAYROWS*loclustruct->numarrays,&systemerror);
  3919.     if(systemerror)
  3920.     {
  3921.         ReportError(errorcontext,systemerror);
  3922.         LUFreeMem(a,b,abase,(fardouble *)NULL);
  3923.         ErrorExit();
  3924.     }
  3925. }
  3926. /*
  3927. ** All's well if we get here.  Do the test.
  3928. */
  3929. accumtime=0L;
  3930. iterations=(double)0.0;
  3931.  
  3932. do {
  3933.     accumtime+=DoLUIteration(a,b,abase,bbase,
  3934.         loclustruct->numarrays);
  3935.     iterations+=(double)loclustruct->numarrays;
  3936. } while(TicksToSecs(accumtime)<loclustruct->request_secs);
  3937.  
  3938. /*
  3939. ** Clean up, calculate results, and go home.  Be sure to
  3940. ** show that we don't have to rerun adjustment code.
  3941. */
  3942. loclustruct->iterspersec=iterations / TicksToFracSecs(accumtime);
  3943.  
  3944. if(loclustruct->adjust==0)
  3945.     loclustruct->adjust=1;
  3946.  
  3947. LUFreeMem(a,b,abase,bbase);
  3948. return;
  3949. }
  3950.  
  3951. /**************
  3952. ** LUFreeMem **
  3953. ***************
  3954. ** Release memory associated with LU benchmark.
  3955. */
  3956. static void LUFreeMem(fardouble *a, fardouble *b,
  3957.             fardouble *abase,fardouble *bbase)
  3958. {
  3959. int systemerror;
  3960.  
  3961. FreeMemory((farvoid *)a,&systemerror);
  3962. FreeMemory((farvoid *)b,&systemerror);
  3963. FreeMemory((farvoid *)LUtempvv,&systemerror);
  3964.  
  3965. if(abase!=(fardouble *)NULL) FreeMemory((farvoid *)abase,&systemerror);
  3966. if(bbase!=(fardouble *)NULL) FreeMemory((farvoid *)bbase,&systemerror);
  3967. return;
  3968. }
  3969.  
  3970. /******************
  3971. ** DoLUIteration **
  3972. *******************
  3973. ** Perform an iteration of the LU decomposition benchmark.
  3974. ** An iteration refers to the repeated solution of several
  3975. ** identical matrices.
  3976. */
  3977. static ulong DoLUIteration(fardouble *a,fardouble *b,
  3978.         fardouble *abase, fardouble *bbase,
  3979.         ulong numarrays)
  3980. {
  3981. fardouble *locabase;
  3982. fardouble *locbbase;
  3983. LUdblptr ptra;  /* For converting ptr to 2D array */
  3984. ulong elapsed;
  3985. ulong j,i;              /* Indexes */
  3986.  
  3987.  
  3988. /*
  3989. ** Move the seed arrays (a & b) into the destination
  3990. ** arrays;
  3991. */
  3992. for(j=0;j<numarrays;j++)
  3993. {       locabase=abase+j*LUARRAYROWS*LUARRAYCOLS;
  3994.     locbbase=bbase+j*LUARRAYROWS;
  3995.     for(i=0;i<LUARRAYROWS*LUARRAYCOLS;i++)
  3996.         *(locabase+i)=*(a+i);
  3997.     for(i=0;i<LUARRAYROWS;i++)
  3998.         *(locbbase+i)=*(b+i);
  3999. }
  4000.  
  4001. /*
  4002. ** Do test...begin timing.
  4003. */
  4004. elapsed=StartStopwatch();
  4005. for(i=0;i<numarrays;i++)
  4006. {       locabase=abase+i*LUARRAYROWS*LUARRAYCOLS;
  4007.     locbbase=bbase+i*LUARRAYROWS;
  4008.     ptra.ptrs.p=locabase;
  4009.     lusolve(*ptra.ptrs.ap,LUARRAYROWS,locbbase);
  4010. }
  4011.  
  4012. return(StopStopwatch(elapsed));
  4013. }
  4014.  
  4015. /******************
  4016. ** build_problem **
  4017. *******************
  4018. ** Constructs a solvable set of linear equations.  It does this by
  4019. ** creating an identity matrix, then loading the solution vector
  4020. ** with random numbers.  After that, the identity matrix and
  4021. ** solution vector are randomly "scrambled".  Scrambling is
  4022. ** done by (a) randomly selecting a row and multiplying that
  4023. ** row by a random number and (b) adding one randomly-selected
  4024. ** row to another.
  4025. */
  4026. static void build_problem(double a[][LUARRAYCOLS],
  4027.         int n,
  4028.         double b[LUARRAYROWS])
  4029. {
  4030. long i,j,k,k1;  /* Indexes */
  4031. double rcon;     /* Random constant */
  4032.  
  4033. /*
  4034. ** Reset random number generator
  4035. */
  4036. randnum(13L);
  4037.  
  4038. /*
  4039. ** Build an identity matrix.
  4040. ** We'll also use this as a chance to load the solution
  4041. ** vector.
  4042. */
  4043. for(i=0;i<n;i++)
  4044. {       b[i]=(double)(abs_randwc(100L)+1L);
  4045.     for(j=0;j<n;j++)
  4046.         if(i==j)
  4047.             a[i][j]=(double)(abs_randwc(1000L)+1L);
  4048.         else
  4049.             a[i][j]=(double)0.0;
  4050. }
  4051.  
  4052. #ifdef DEBUG
  4053. for(i=0;i<n;i++)
  4054. {
  4055.     for(j=0;j<n;j++)
  4056.         printf("%6.2f ",a[i][j]);
  4057.     printf(":: %6.2f\n",b[i]);
  4058. }
  4059. #endif
  4060.  
  4061. /*
  4062. ** Scramble.  Do this 8n times.  See comment above for
  4063. ** a description of the scrambling process.
  4064. */
  4065.  
  4066. for(i=0;i<8*n;i++)
  4067. {
  4068.     /*
  4069.     ** Pick a row and a random constant.  Multiply
  4070.     ** all elements in the row by the constant.
  4071.     */
  4072.  /*       k=abs_randwc((long)n);
  4073.     rcon=(double)(abs_randwc(20L)+1L);
  4074.     for(j=0;j<n;j++)
  4075.         a[k][j]=a[k][j]*rcon;
  4076.     b[k]=b[k]*rcon;
  4077. */
  4078.     /*
  4079.     ** Pick two random rows and add second to
  4080.     ** first.  Note that we also occasionally multiply
  4081.     ** by minus 1 so that we get a subtraction operation.
  4082.     */
  4083.     k=abs_randwc((long)n);
  4084.     k1=abs_randwc((long)n);
  4085.     if(k!=k1)
  4086.     {
  4087.         if(k<k1) rcon=(double)1.0;
  4088.             else rcon=(double)-1.0;
  4089.         for(j=0;j<n;j++)
  4090.             a[k][j]+=a[k1][j]*rcon;;
  4091.         b[k]+=b[k1]*rcon;
  4092.     }
  4093. }
  4094.  
  4095. return;
  4096. }
  4097.  
  4098.  
  4099. /***********
  4100. ** ludcmp **
  4101. ************
  4102. ** From the procedure of the same name in "Numerical Recipes in Pascal",
  4103. ** by Press, Flannery, Tukolsky, and Vetterling.
  4104. ** Given an nxn matrix a[], this routine replaces it by the LU
  4105. ** decomposition of a rowwise permutation of itself.  a[] and n
  4106. ** are input.  a[] is output, modified as follows:
  4107. **   --                       --
  4108. **  |  b(1,1) b(1,2) b(1,3)...  |
  4109. **  |  a(2,1) b(2,2) b(2,3)...  |
  4110. **  |  a(3,1) a(3,2) b(3,3)...  |
  4111. **  |  a(4,1) a(4,2) a(4,3)...  |
  4112. **  |  ...                      |
  4113. **   --                        --
  4114. **
  4115. ** Where the b(i,j) elements form the upper triangular matrix of the
  4116. ** LU decomposition, and the a(i,j) elements form the lower triangular
  4117. ** elements.  The LU decomposition is calculated so that we don't
  4118. ** need to store the a(i,i) elements (which would have laid along the
  4119. ** diagonal and would have all been 1).
  4120. **
  4121. ** indx[] is an output vector that records the row permutation
  4122. ** effected by the partial pivoting; d is output as +/-1 depending
  4123. ** on whether the number of row interchanges was even or odd,
  4124. ** respectively.
  4125. ** Returns 0 if matrix singular, else returns 1.
  4126. */
  4127. static int ludcmp(double a[][LUARRAYCOLS],
  4128.         int n,
  4129.         int indx[],
  4130.         int *d)
  4131. {
  4132.  
  4133. double big;     /* Holds largest element value */
  4134. double sum;
  4135. double dum;     /* Holds dummy value */
  4136. int i,j,k;      /* Indexes */
  4137. int imax;       /* Holds max index value */
  4138. double tiny;    /* A really small number */
  4139. int systemerror;
  4140.  
  4141. tiny=(double)1.0e-20;
  4142.  
  4143. *d=1;           /* No interchanges yet */
  4144.  
  4145. for(i=0;i<n;i++)
  4146. {       big=(double)0.0;
  4147.     for(j=0;j<n;j++)
  4148.         if((double)fabs(a[i][j]) > big)
  4149.             big=fabs(a[i][j]);
  4150.     /* Bail out on singular matrix */
  4151.     if(big==(double)0.0) return(0);
  4152.     LUtempvv[i]=1.0/big;
  4153. }
  4154.  
  4155. /*
  4156. ** Crout's algorithm...loop over columns.
  4157. */
  4158. for(j=0;j<n;j++)
  4159. {       if(j!=0)
  4160.         for(i=0;i<j;i++)
  4161.         {       sum=a[i][j];
  4162.             if(i!=0)
  4163.                 for(k=0;k<i;k++)
  4164.                     sum-=(a[i][k]*a[k][j]);
  4165.             a[i][j]=sum;
  4166.         }
  4167.     big=(double)0.0;
  4168.     for(i=j;i<n;i++)
  4169.     {       sum=a[i][j];
  4170.         if(j!=0)
  4171.             for(k=0;k<j;k++)
  4172.                 sum-=a[i][k]*a[k][j];
  4173.         a[i][j]=sum;
  4174.         dum=LUtempvv[i]*fabs(sum);
  4175.         if(dum>=big)
  4176.         {       big=dum;
  4177.             imax=i;
  4178.         }
  4179.     }
  4180.     if(j!=imax)             /* Interchange rows if necessary */
  4181.     {       for(k=0;k<n;k++)
  4182.         {       dum=a[imax][k];
  4183.             a[imax][k]=a[j][k];
  4184.             a[j][k]=dum;
  4185.         }
  4186.         *d=-*d;         /* Change parity of d */
  4187.         dum=LUtempvv[imax];
  4188.         LUtempvv[imax]=LUtempvv[j]; /* Don't forget scale factor */
  4189.         LUtempvv[j]=dum;
  4190.     }
  4191.     indx[j]=imax;
  4192.     /*
  4193.     ** If the pivot element is zero, the matrix is singular
  4194.     ** (at least as far as the precision of the machine
  4195.     ** is concerned.)  We'll take the original author's
  4196.     ** recommendation and replace 0.0 with "tiny".
  4197.     */
  4198.     if(a[j][j]==(double)0.0)
  4199.         a[j][j]=tiny;
  4200.  
  4201.     if(j!=(n-1))
  4202.     {       dum=1.0/a[j][j];
  4203.         for(i=j+1;i<n;i++)
  4204.             a[i][j]=a[i][j]*dum;
  4205.     }
  4206. }
  4207.  
  4208. return(1);
  4209. }
  4210.  
  4211. /***********
  4212. ** lubksb **
  4213. ************
  4214. ** Also from "Numerical Recipes in Pascal".
  4215. ** This routine solves the set of n linear equations A X = B.
  4216. ** Here, a[][] is input, not as the matrix A, but as its
  4217. ** LU decomposition, created by the routine ludcmp().
  4218. ** Indx[] is input as the permutation vector returned by ludcmp().
  4219. **  b[] is input as the right-hand side an returns the
  4220. ** solution vector X.
  4221. ** a[], n, and indx are not modified by this routine and
  4222. ** can be left in place for different values of b[].
  4223. ** This routine takes into account the possibility that b will
  4224. ** begin with many zero elements, so it is efficient for use in
  4225. ** matrix inversion.
  4226. */
  4227. static void lubksb( double a[][LUARRAYCOLS],
  4228.         int n,
  4229.         int indx[LUARRAYROWS],
  4230.         double b[LUARRAYROWS])
  4231. {
  4232.  
  4233. int i,j;        /* Indexes */
  4234. int ip;         /* "pointer" into indx */
  4235. int ii;
  4236. double sum;
  4237.  
  4238. /*
  4239. ** When ii is set to a positive value, it will become
  4240. ** the index of the first nonvanishing element of b[].
  4241. ** We now do the forward substitution. The only wrinkle
  4242. ** is to unscramble the permutation as we go.
  4243. */
  4244. ii=-1;
  4245. for(i=0;i<n;i++)
  4246. {       ip=indx[i];
  4247.     sum=b[ip];
  4248.     b[ip]=b[i];
  4249.     if(ii!=-1)
  4250.         for(j=ii;j<i;j++)
  4251.             sum=sum-a[i][j]*b[j];
  4252.     else
  4253.         /*
  4254.         ** If a nonzero element is encountered, we have
  4255.         ** to do the sums in the loop above.
  4256.         */
  4257.         if(sum!=(double)0.0)
  4258.             ii=i;
  4259.     b[i]=sum;
  4260. }
  4261. /*
  4262. ** Do backsubstitution
  4263. */
  4264. for(i=(n-1);i>=0;i--)
  4265. {
  4266.     sum=b[i];
  4267.     if(i!=(n-1))
  4268.         for(j=(i+1);j<n;j++)
  4269.             sum=sum-a[i][j]*b[j];
  4270.     b[i]=sum/a[i][i];
  4271. }
  4272. return;
  4273. }
  4274.  
  4275. /************
  4276. ** lusolve **
  4277. *************
  4278. ** Solve a linear set of equations: A x = b
  4279. ** Original matrix A will be destroyed by this operation.
  4280. ** Returns 0 if matrix is singular, 1 otherwise.
  4281. */
  4282. static int lusolve(double a[][LUARRAYCOLS],
  4283.         int n,
  4284.         double b[LUARRAYROWS])
  4285. {
  4286. int indx[LUARRAYROWS];
  4287. int d;
  4288. int i,j;
  4289.  
  4290. if(ludcmp(a,n,indx,&d)==0) return(0);
  4291.  
  4292. /* Matrix not singular -- proceed */
  4293. lubksb(a,n,indx,b);
  4294.  
  4295. #ifdef DEBUG
  4296. for(i=0;i<n;i++)
  4297. {
  4298.          for(j=0;j<n;j++)
  4299.         printf("%6.2f ",a[i][j]); */
  4300.     printf("%6.2f ",b[i]);
  4301. }
  4302. printf("\n");
  4303. #endif
  4304.  
  4305. return(1);
  4306. }
  4307.