home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / src / out-of-phase-102-c / OutOfPhase 1.02 Source / OutOfPhase Folder / Level 1 Extensions 29Sep94 / RandomNumbers.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-23  |  5.6 KB  |  157 lines  |  [TEXT/KAHL]

  1. /* RandomNumbers.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    System Dependency Library for Building Portable Software               */
  5. /*    Macintosh Version                                                      */
  6. /*    Written by Thomas R. Lawrence, 1993 - 1994.                            */
  7. /*                                                                           */
  8. /*    This file is Public Domain; it may be used for any purpose whatsoever  */
  9. /*    without restriction.                                                   */
  10. /*                                                                           */
  11. /*    This package is distributed in the hope that it will be useful,        */
  12. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  13. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                   */
  14. /*                                                                           */
  15. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  16. /*                                                                           */
  17. /*****************************************************************************/
  18.  
  19. #include "MiscInfo.h"
  20. #include "Audit.h"
  21. #include "Debug.h"
  22. #include "Definitions.h"
  23.  
  24. #include "RandomNumbers.h"
  25.  
  26.  
  27. #define CHECKPARKANDMILLER (1)
  28.  
  29.  
  30. static long                ParkAndMillerSeed = 1;
  31.  
  32. #define ParkAndMillerA (16807L)
  33. #define ParkAndMillerM (2147483647L)
  34. #define ParkAndMillerQ (127773L)
  35. #define ParkAndMillerR (2836L)
  36. /* this implements the Park and Miller (Communications of the ACM, 1988) Minimal */
  37. /* Standard random number generator. it returns a number in the range [1..2147483646] */
  38. long                            ParkAndMillerRandom(void)
  39.     {
  40.         long                        Lo;
  41.         long                        Hi;
  42.         long                        Test;
  43.  
  44.         Hi = ParkAndMillerSeed / ParkAndMillerQ;
  45.         Lo = ParkAndMillerSeed % ParkAndMillerQ;
  46.         Test = ParkAndMillerA * Lo - ParkAndMillerR * Hi;
  47.         if (Test > 0)
  48.             {
  49.                 ParkAndMillerSeed = Test;
  50.             }
  51.          else
  52.             {
  53.                 ParkAndMillerSeed = Test + ParkAndMillerM;
  54.             }
  55.         ERROR((ParkAndMillerSeed < 1L) || (ParkAndMillerSeed > 2147483646L),PRERR(ForceAbort,
  56.             "ParkAndMillerRandom:  seed exceeded range."));
  57.         ERROR((1L != PARKANDMILLERMINIMUM) || (2147483646L != 2147483646L),PRERR(ForceAbort,
  58.             "ParkAndMillerRandom:  limit macros are bad"));
  59.         return ParkAndMillerSeed;
  60.     }
  61.  
  62.  
  63. /* set the Park and Miller random number seed.  it returns the old seed so that */
  64. /* multiple clients can save and restore the seed so they don't interfere with */
  65. /* each other.  the seed must be in the range [1..2147483646]. */
  66. long                            SetParkAndMillerRandomSeed(long NewSeed)
  67.     {
  68.         long                        OriginalSeedValue;
  69. #if DEBUG && CHECKPARKANDMILLER
  70.         long                        Counter;
  71.         long                        Value;
  72. #endif
  73.  
  74.         ERROR((NewSeed < 1) || (NewSeed > 2147483646),PRERR(ForceAbort,
  75.             "SetParkAndMillerRandomSeed:  seed is out of range"));
  76.         OriginalSeedValue = ParkAndMillerSeed;
  77. #if DEBUG && CHECKPARKANDMILLER
  78.         ParkAndMillerSeed = 1;
  79.         for (Counter = 1; Counter <= 10000; Counter += 1)
  80.             {
  81.                 Value = ParkAndMillerRandom();
  82.             }
  83.         if (Value != 1043618065)
  84.             {
  85.                 PRERR(ForceAbort,"SetParkAndMillerRandomSeed:  random number failure");
  86.             }
  87. #endif
  88.         ParkAndMillerSeed = NewSeed;
  89.         return OriginalSeedValue;
  90.     }
  91.  
  92.  
  93.  
  94. static long                LEcuyerSeed1 = 1; /* must be in [1..2147483562] */
  95. static long                LEcuyerSeed2 = 1; /* must be in [1..2147483398] */
  96.  
  97. /* this implements the L'Ecuyer (Communications of the ACM, 1988) hybrid 32-bit */
  98. /* random number generator.  it returns a value in the range [1..2147483562] */
  99. /* WARNING:  no test data or algorithm was supplied in the article, so the */
  100. /* correctness of this implementation can not be guarranteed. */
  101. long                            LEcuyerRandom(void)
  102.     {
  103.         long                        Z;
  104.         long                        K;
  105.  
  106.         K = LEcuyerSeed1 / 53668L;
  107.         LEcuyerSeed1 = 40014L * (LEcuyerSeed1 - K * 53668L) - K * 12211L;
  108.         if (LEcuyerSeed1 < 0)
  109.             {
  110.                 LEcuyerSeed1 = LEcuyerSeed1 + 2147483563L;
  111.             }
  112.         K = LEcuyerSeed2 / 52774L;
  113.         LEcuyerSeed2 = 40692L * (LEcuyerSeed2 - K * 52774L) - K * 3791L;
  114.         if (LEcuyerSeed2 < 0)
  115.             {
  116.                 LEcuyerSeed2 = LEcuyerSeed2 + 2147483399L;
  117.             }
  118.         Z = LEcuyerSeed1 - LEcuyerSeed2;
  119.         if (Z < 1)
  120.             {
  121.                 Z = Z + 2147483562L;
  122.             }
  123.         ERROR((LEcuyerSeed1 < 1L) || (LEcuyerSeed1 > 2147483562L),PRERR(ForceAbort,
  124.             "LEcuyerRandom:  first seed is out of range"));
  125.         ERROR((LEcuyerSeed2 < 1L) || (LEcuyerSeed2 > 2147483398L),PRERR(ForceAbort,
  126.             "LEcuyerRandom:  second seed is out of range"));
  127.         ERROR((LECUYERMINIMUM != 1L) || (LECUYERMAXIMUM != 2147483562L),PRERR(ForceAbort,
  128.             "LEcuyerRandom:  limit macros are bad"));
  129.         ERROR((Z < LECUYERMINIMUM) || (Z > LECUYERMAXIMUM),PRERR(ForceAbort,
  130.             "LEcuyerRandom:  return value is outside of limit macro range"));
  131.         return Z;
  132.     }
  133.  
  134.  
  135. /* sets the LEcuyer seeds.  the first seed must be in the range [1..2147483562] */
  136. /* and the second seed in the range [1..2147483398].  the previous are returned */
  137. /* so that multiple clients can save and restore seeds without interfering with */
  138. /* each other.  the pointers may be NIL if the old seeds values are not needed. */
  139. void                            SetLEcuyerRandomSeed(long NewS1, long NewS2, long* OldS1Out,
  140.                                         long* OldS2Out)
  141.     {
  142.         ERROR((NewS1 < 1L) || (NewS1 > 2147483562L),PRERR(ForceAbort,
  143.             "SetLEcuyerRandomSeed:  first seed is out of range"));
  144.         ERROR((NewS2 < 1L) || (NewS2 > 2147483398L),PRERR(ForceAbort,
  145.             "SetLEcuyerRandomSeed:  second seed is out of range"));
  146.         if (OldS1Out != NIL)
  147.             {
  148.                 *OldS1Out = LEcuyerSeed1;
  149.             }
  150.         if (OldS2Out != NIL)
  151.             {
  152.                 *OldS2Out = LEcuyerSeed2;
  153.             }
  154.         LEcuyerSeed1 = NewS1;
  155.         LEcuyerSeed2 = NewS2;
  156.     }
  157.