src/glprng01.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

- Generated files and doc/notes are removed
alpar@1
     1
/* glprng01.c */
alpar@1
     2
alpar@1
     3
/***********************************************************************
alpar@1
     4
*  This code is part of GLPK (GNU Linear Programming Kit).
alpar@1
     5
*
alpar@1
     6
*  This code is a modified version of the module GB_FLIP, a portable
alpar@1
     7
*  pseudo-random number generator. The original version of GB_FLIP is
alpar@1
     8
*  a part of The Stanford GraphBase developed by Donald E. Knuth (see
alpar@1
     9
*  http://www-cs-staff.stanford.edu/~knuth/sgb.html).
alpar@1
    10
*
alpar@1
    11
*  Note that all changes concern only external names, so this modified
alpar@1
    12
*  version produces exactly the same results as the original version.
alpar@1
    13
*
alpar@1
    14
*  Changes were made by Andrew Makhorin <mao@gnu.org>.
alpar@1
    15
*
alpar@1
    16
*  GLPK is free software: you can redistribute it and/or modify it
alpar@1
    17
*  under the terms of the GNU General Public License as published by
alpar@1
    18
*  the Free Software Foundation, either version 3 of the License, or
alpar@1
    19
*  (at your option) any later version.
alpar@1
    20
*
alpar@1
    21
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@1
    22
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@1
    23
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@1
    24
*  License for more details.
alpar@1
    25
*
alpar@1
    26
*  You should have received a copy of the GNU General Public License
alpar@1
    27
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@1
    28
***********************************************************************/
alpar@1
    29
alpar@1
    30
#include "glpenv.h"
alpar@1
    31
#include "glprng.h"
alpar@1
    32
alpar@1
    33
#if 0
alpar@1
    34
int A[56] = { -1 };
alpar@1
    35
#else
alpar@1
    36
#define A (rand->A)
alpar@1
    37
#endif
alpar@1
    38
/* pseudo-random values */
alpar@1
    39
alpar@1
    40
#if 0
alpar@1
    41
int *fptr = A;
alpar@1
    42
#else
alpar@1
    43
#define fptr (rand->fptr)
alpar@1
    44
#endif
alpar@1
    45
/* the next A value to be exported */
alpar@1
    46
alpar@1
    47
#define mod_diff(x, y) (((x) - (y)) & 0x7FFFFFFF)
alpar@1
    48
/* difference modulo 2^31 */
alpar@1
    49
alpar@1
    50
static int flip_cycle(RNG *rand)
alpar@1
    51
{     /* this is an auxiliary routine to do 55 more steps of the basic
alpar@1
    52
         recurrence, at high speed, and to reset fptr */
alpar@1
    53
      int *ii, *jj;
alpar@1
    54
      for (ii = &A[1], jj = &A[32]; jj <= &A[55]; ii++, jj++)
alpar@1
    55
         *ii = mod_diff(*ii, *jj);
alpar@1
    56
      for (jj = &A[1]; ii <= &A[55]; ii++, jj++)
alpar@1
    57
         *ii = mod_diff(*ii, *jj);
alpar@1
    58
      fptr = &A[54];
alpar@1
    59
      return A[55];
alpar@1
    60
}
alpar@1
    61
alpar@1
    62
/***********************************************************************
alpar@1
    63
*  NAME
alpar@1
    64
*
alpar@1
    65
*  rng_create_rand - create pseudo-random number generator
alpar@1
    66
*
alpar@1
    67
*  SYNOPSIS
alpar@1
    68
*
alpar@1
    69
*  #include "glprng.h"
alpar@1
    70
*  RNG *rng_create_rand(void);
alpar@1
    71
*
alpar@1
    72
*  DESCRIPTION
alpar@1
    73
*
alpar@1
    74
*  The routine rng_create_rand creates and initializes a pseudo-random
alpar@1
    75
*  number generator.
alpar@1
    76
*
alpar@1
    77
*  RETURNS
alpar@1
    78
*
alpar@1
    79
*  The routine returns a pointer to the generator created. */
alpar@1
    80
alpar@1
    81
RNG *rng_create_rand(void)
alpar@1
    82
{     RNG *rand;
alpar@1
    83
      int i;
alpar@1
    84
      rand = xmalloc(sizeof(RNG));
alpar@1
    85
      A[0] = -1;
alpar@1
    86
      for (i = 1; i <= 55; i++) A[i] = 0;
alpar@1
    87
      fptr = A;
alpar@1
    88
      rng_init_rand(rand, 1);
alpar@1
    89
      return rand;
alpar@1
    90
}
alpar@1
    91
alpar@1
    92
/***********************************************************************
alpar@1
    93
*  NAME
alpar@1
    94
*
alpar@1
    95
*  rng_init_rand - initialize pseudo-random number generator
alpar@1
    96
*
alpar@1
    97
*  SYNOPSIS
alpar@1
    98
*
alpar@1
    99
*  #include "glprng.h"
alpar@1
   100
*  void rng_init_rand(RNG *rand, int seed);
alpar@1
   101
*
alpar@1
   102
*  DESCRIPTION
alpar@1
   103
*
alpar@1
   104
*  The routine rng_init_rand initializes the pseudo-random number
alpar@1
   105
*  generator. The parameter seed may be any integer number. Note that
alpar@1
   106
*  on creating the generator this routine is called with the parameter
alpar@1
   107
*  seed equal to 1. */
alpar@1
   108
alpar@1
   109
void rng_init_rand(RNG *rand, int seed)
alpar@1
   110
{     int i;
alpar@1
   111
      int prev = seed, next = 1;
alpar@1
   112
      seed = prev = mod_diff(prev, 0);
alpar@1
   113
      A[55] = prev;
alpar@1
   114
      for (i = 21; i; i = (i + 21) % 55)
alpar@1
   115
      {  A[i] = next;
alpar@1
   116
         next = mod_diff(prev, next);
alpar@1
   117
         if (seed & 1)
alpar@1
   118
            seed = 0x40000000 + (seed >> 1);
alpar@1
   119
         else
alpar@1
   120
            seed >>= 1;
alpar@1
   121
         next = mod_diff(next, seed);
alpar@1
   122
         prev = A[i];
alpar@1
   123
      }
alpar@1
   124
      flip_cycle(rand);
alpar@1
   125
      flip_cycle(rand);
alpar@1
   126
      flip_cycle(rand);
alpar@1
   127
      flip_cycle(rand);
alpar@1
   128
      flip_cycle(rand);
alpar@1
   129
      return;
alpar@1
   130
}
alpar@1
   131
alpar@1
   132
/***********************************************************************
alpar@1
   133
*  NAME
alpar@1
   134
*
alpar@1
   135
*  rng_next_rand - obtain pseudo-random integer in the range [0, 2^31-1]
alpar@1
   136
*
alpar@1
   137
*  SYNOPSIS
alpar@1
   138
*
alpar@1
   139
*  #include "glprng.h"
alpar@1
   140
*  int rng_next_rand(RNG *rand);
alpar@1
   141
*
alpar@1
   142
*  RETURNS
alpar@1
   143
*
alpar@1
   144
*  The routine rng_next_rand returns a next pseudo-random integer which
alpar@1
   145
*  is uniformly distributed between 0 and 2^31-1, inclusive. The period
alpar@1
   146
*  length of the generated numbers is 2^85 - 2^30. The low order bits of
alpar@1
   147
*  the generated numbers are just as random as the high-order bits. */
alpar@1
   148
alpar@1
   149
int rng_next_rand(RNG *rand)
alpar@1
   150
{     return
alpar@1
   151
         *fptr >= 0 ? *fptr-- : flip_cycle(rand);
alpar@1
   152
}
alpar@1
   153
alpar@1
   154
/***********************************************************************
alpar@1
   155
*  NAME
alpar@1
   156
*
alpar@1
   157
*  rng_unif_rand - obtain pseudo-random integer in the range [0, m-1]
alpar@1
   158
*
alpar@1
   159
*  SYNOPSIS
alpar@1
   160
*
alpar@1
   161
*  #include "glprng.h"
alpar@1
   162
*  int rng_unif_rand(RNG *rand, int m);
alpar@1
   163
*
alpar@1
   164
*  RETURNS
alpar@1
   165
*
alpar@1
   166
*  The routine rng_unif_rand returns a next pseudo-random integer which
alpar@1
   167
*  is uniformly distributed between 0 and m-1, inclusive, where m is any
alpar@1
   168
*  positive integer less than 2^31. */
alpar@1
   169
alpar@1
   170
#define two_to_the_31 ((unsigned int)0x80000000)
alpar@1
   171
alpar@1
   172
int rng_unif_rand(RNG *rand, int m)
alpar@1
   173
{     unsigned int t = two_to_the_31 - (two_to_the_31 % m);
alpar@1
   174
      int r;
alpar@1
   175
      xassert(m > 0);
alpar@1
   176
      do { r = rng_next_rand(rand); } while (t <= (unsigned int)r);
alpar@1
   177
      return r % m;
alpar@1
   178
}
alpar@1
   179
alpar@1
   180
/***********************************************************************
alpar@1
   181
*  NAME
alpar@1
   182
*
alpar@1
   183
*  rng_delete_rand - delete pseudo-random number generator
alpar@1
   184
*
alpar@1
   185
*  SYNOPSIS
alpar@1
   186
*
alpar@1
   187
*  #include "glprng.h"
alpar@1
   188
*  void rng_delete_rand(RNG *rand);
alpar@1
   189
*
alpar@1
   190
*  DESCRIPTION
alpar@1
   191
*
alpar@1
   192
*  The routine rng_delete_rand frees all the memory allocated to the
alpar@1
   193
*  specified pseudo-random number generator. */
alpar@1
   194
alpar@1
   195
void rng_delete_rand(RNG *rand)
alpar@1
   196
{     xfree(rand);
alpar@1
   197
      return;
alpar@1
   198
}
alpar@1
   199
alpar@1
   200
/**********************************************************************/
alpar@1
   201
alpar@1
   202
#if 0
alpar@1
   203
/* To be sure that this modified version produces the same results as
alpar@1
   204
   the original version, run this validation program. */
alpar@1
   205
alpar@1
   206
int main(void)
alpar@1
   207
{     RNG *rand;
alpar@1
   208
      int j;
alpar@1
   209
      rand = rng_create_rand();
alpar@1
   210
      rng_init_rand(rand, -314159);
alpar@1
   211
      if (rng_next_rand(rand) != 119318998)
alpar@1
   212
      {  fprintf(stderr, "Failure on the first try!\n");
alpar@1
   213
         return -1;
alpar@1
   214
      }
alpar@1
   215
      for (j = 1; j <= 133; j++) rng_next_rand(rand);
alpar@1
   216
      if (rng_unif_rand(rand, 0x55555555) != 748103812)
alpar@1
   217
      {  fprintf(stderr, "Failure on the second try!\n");
alpar@1
   218
         return -2;
alpar@1
   219
      }
alpar@1
   220
      fprintf(stderr, "OK, the random-number generator routines seem to"
alpar@1
   221
         " work!\n");
alpar@1
   222
      rng_delete_rand(rand);
alpar@1
   223
      return 0;
alpar@1
   224
}
alpar@1
   225
#endif
alpar@1
   226
alpar@1
   227
/* eof */