Linuxの擬似乱数解析について

7829 ワード

rand関数
関数の説明:rand()は、0~RAND_の範囲のランダムな数値を返します.MAX間.この関数を呼び出して乱数を生成する前に、srand()を使用して乱数シードを設定する必要があります.乱数シードを設定していない場合、rand()は呼び出し時に自動的に乱数シードを1に設定します.乱数シードについてはsrand()の戻り値を参照してください.0からRAND_に戻ります.MAX間の乱数、RAND_MAXはstdlibで定義.h,その値は2147483647
srand関数
関数の説明:srand()はrand()が乱数を生成するときの乱数シードを設定するために使用されます.パラメータseedは整数でなければなりません.通常、geypid()またはtime(0)の戻り値をseedとして使用できます.seedのたびに同じ値を設定すると、rand()によって生成されるランダムな数値は毎回同じになります.
Linux乱数解析
最も一般的な乱数過程,すなわちsrand−>randの過程は,得られた乱数に基づいて種子を逆方向に放出することを目的とする.
unsafe_state:
146 static int32_t randtbl[DEG_3 + 1] =
147   {
148     TYPE_3,
149 
150     -1726662223, 379960547, 1735697613, 1040273694, 1313901226,
151     1627687941, -179304937, -2073333483, 1780058412, -1989503057,
152     -615974602, 344556628, 939512070, -1249116260, 1507946756,
153     -812545463, 154635395, 1388815473, -1926676823, 525320961,
154     -1009028674, 968117788, -123449607, 1284210865, 435012392,
155     -2017506339, -911064859, -370259173, 1132637927, 1398500161,
156     -205601318,
157   };
160 static struct random_data unsafe_state =
161   {
162 /* FPTR and RPTR are two pointers into the state info, a front and a rear
163    pointer.  These two pointers are always rand_sep places apart, as they
164    cycle through the state information.  (Yes, this does mean we could get
165    away with just one pointer, but the code for random is more efficient
166    this way).  The pointers are left positioned as they would be from the call:
167         initstate(1, randtbl, 128);
168    (The position of the rear pointer, rptr, is really 0 (as explained above
169    in the initialization of randtbl) because the state table pointer is set
170    to point to randtbl[1] (as explained below).)  */
171 
172     .fptr = &randtbl[SEP_3 + 1], //      
173     .rptr = &randtbl[1], //    
174 
175 /* The following things are the pointer to the state information table,
176    the type of the current generator, the degree of the current polynomial
177    being used, and the separation between the two pointers.
178    Note that for efficiency of random, we remember the first location of
179    the state information, not the zeroth.  Hence it is valid to access
180    state[-1], which is used to store the type of the R.N.G.
181    Also, we remember the last location, since this is more efficient than
182    indexing every time to find the address of the last element to see if
183    the front and rear pointers have wrapped.  */
184 
185     .state = &randtbl[1], // randtbl     ,state  srand             ,              
186 
187     .rand_type = TYPE_3, // 3
188     .rand_deg = DEG_3, // state    31,  state  randtbl[1]    ,randtbl[0]   TYPE_3
189     .rand_sep = SEP_3, // 3
190 
191     .end_ptr = &randtbl[sizeof (randtbl) / sizeof (randtbl[0])] // randtbl     
192 };

srand関数:
srandの具体的な実装は__ですsrandom_r,パラメータseedがシード,bufが上のunsafe_state. ここでは主にseedをベースにstate[0]と表記し、state[i]=(16807*state[i-1])%2147483647を実現する.
161 __srandom_r (unsigned int seed, struct random_data *buf) 
162 {
163   int type;
164   int32_t *state;
165   long int i;
166   int32_t word;
167   int32_t *dst;
168   int kc;
169 
170   if (buf == NULL)
171     goto fail;
172   type = buf->rand_type; // type   3
173   if ((unsigned int) type >= MAX_TYPES)
174     goto fail;
175 
176   state = buf->state; // state   randtbl[1]  
177   /* We must make sure the seed is not 0.  Take arbitrarily 1 in this case.  */
178   if (seed == 0) // seed 0   1
179     seed = 1;
180   state[0] = seed; // state[0]   seed,   TYPE_3
181   if (type == TYPE_0)
182     goto done;
183   //  state[1]  ,  state[i] = (16807 * state[i - 1]) % 2147483647
184   dst = state;  // dst  state[i]
185   word = seed; // word  state[i-1]
186   kc = buf->rand_deg; // kc=31,  table   
187   for (i = 1; i < kc; ++i) //  30 
188     {
189       /* This does:
190            state[i] = (16807 * state[i - 1]) % 2147483647;
191          but avoids overflowing 31 bits.  */
192       long int hi = word / 127773;
193       long int lo = word % 127773;
194       word = 16807 * lo - 2836 * hi;
195       if (word < 0)
196         word += 2147483647;
197       *++dst = word;
198     }
199 
200   buf->fptr = &state[buf->rand_sep]; // fptr state[3]  
201   buf->rptr = &state[0]; // rptr state[0]  
202   kc *= 10; // 310
203   while (--kc >= 0) //   __random_r  310    
204     {
205       int32_t discard;
206       (void) __random_r (buf, &discard);
207     }
208 
209  done:
210   return 0;
211 
212  fail:
213   return -1;
214 }

rand関数:
randの具体的な実装は_random_r,パラメータbufは依然として上のunsafe_state,resultは私たちが返したランダム数です.
352 int
353 __random_r (struct random_data *buf, int32_t *result)
354 {
355   int32_t *state;
356 
357   if (buf == NULL || result == NULL)
358     goto fail;
359 
360   state = buf->state;
361 
362   if (buf->rand_type == TYPE_0)
363     {
364       int32_t val = state[0];
365       val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
366       state[0] = val;
367       *result = val;
368     }
369   else //   type=3,        
370     {
371       int32_t *fptr = buf->fptr; 
372       int32_t *rptr = buf->rptr;
373       int32_t *end_ptr = buf->end_ptr;
374       int32_t val;
375 
376       val = *fptr += *rptr;
377       /* Chucking least random bit.  */
378       *result = (val >> 1) & 0x7fffffff;
379       ++fptr;
380       if (fptr >= end_ptr)
381         {
382           fptr = state;
383           ++rptr;
384         }
385       else
386         {
387           ++rptr;
388           if (rptr >= end_ptr)
389             rptr = state;
390         }
391       buf->fptr = fptr;
392       buf->rptr = rptr;
393     }
394   return 0;
395 
396  fail:  
397   __set_errno (EINVAL);
398   return -1;
399 }

疑似コード:
以上の解析により,後続seedに基づいて乱数と対応するstateを得ることができるようになった.
#include          
#define MAX 1000
#define seed 1
#int main() {
    int r[MAX],i,j;
    int state[31];
    state[0] = seed;
    for (i=1; i<31; i++){
            state[i] = (16807LL * state[i-1]) % 2147483647;
            if (state[i] < 0) {
                state[i] += 2147483647;
            }
        }
    for (i=31; i<341;i++){
        state[(i+3)%31] = (state[(i+3)%31]+state[i%31]);
    }
    for (i=341;i>1)&0x7fffffff;
        printf("%d : %x
",i-340,r[i-340]); } return 0; }

コードの簡略化:
#include 
#define MAX 1000
#define seed 1
int main() {
    int r[MAX],i;
    r[0] = seed;
    for (i=1; i<31; i++){
            r[i] = (16807LL * r[i-1])%0x7fffffff;
            if (r[i] < 0) {
                r[i] += 0x7fffffff;
            }
        }
    for (i=31; i<34; i++){
        r[i] = r[i-31];
    }
    for (i=34; i<344;i++){
        r[i] = r[i-31] + r[i-3];
    }
    for (i=344;i<350;i++){
        r[i] = r[i-31] + r[i-3];
        printf("%d %#x
", i-343, (r[i]>>1)&0x7fffffff); } return 0; }

予測:上に&0 x 7 fffffffが存在し、かつ2で割ることも存在することが分かるので、予測に成功する場合はr[i-31]とr[i-3]ともに&0 x 7 fffffffは存在しない.これはr[i]=((r[i-31]<<1)+(r[i-3]<<1))に対応する乱数か(r[i]>>1)&0 x 7 fffffffffffかであるが、実際にはさらに簡単であり、我々が得たのは乱数であるため、このようなものである.
rand[i]=(r[i]>>1)&0 x 7 fffffff r[i]=(r[i−31]<<1)+(r[i−3]<<1))rand[i−3]=(r[i−3]>>1)&0 x 7 fffffffffffffff rand[i−31]=(r[i−31]>>1)&0 x 7 fffffffffffffffff総合:rand[i]=((r[i−31]<<1)+(r[i−31]<<1)&0 x 7 fffffffffffffffffffff発売rand[i]=(rand[i](rand[i](rand[i]-3]+(rand[i]+(r[i rand[i-31]&0 x 7 fffffffしかし2で割った原因があるため、1の誤差がある可能性がある