---
title: libc-2.23 rand
tags: libc-2.23
lang: zh_tw
---
# libc-2.23 rand
[TOC]
# 相關資料結構
## struct random_data
```c
struct random_data
{
int32_t *fptr; /* Front pointer. */
int32_t *rptr; /* Rear pointer. */
int32_t *state; /* Array of state values. */
int rand_type; /* Type of random number generator. */
int rand_deg; /* Degree of random number generator. */
int rand_sep; /* Distance between front and rear. */
int32_t *end_ptr; /* Pointer behind state table. */
};
```
- [link](https://elixir.bootlin.com/glibc/glibc-2.23/source/stdlib/stdlib.h#L343)
## static int32_t randtbl[DEG_3 + 1]
```c
/* Initially, everything is set up as if from:
initstate(1, randtbl, 128);
Note that this initialization takes advantage of the fact that srandom
advances the front and rear pointers 10*rand_deg times, and hence the
rear pointer which starts at 0 will also end up at zero; thus the zeroth
element of the state information, which contains info about the current
position of the rear pointer is just
(MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */
static int32_t randtbl[DEG_3 + 1] =
{
TYPE_3,
-1726662223, 379960547, 1735697613, 1040273694, 1313901226,
1627687941, -179304937, -2073333483, 1780058412, -1989503057,
-615974602, 344556628, 939512070, -1249116260, 1507946756,
-812545463, 154635395, 1388815473, -1926676823, 525320961,
-1009028674, 968117788, -123449607, 1284210865, 435012392,
-2017506339, -911064859, -370259173, 1132637927, 1398500161,
-205601318,
};
```
- [link](https://elixir.bootlin.com/glibc/glibc-2.23/source/stdlib/random.c#L146)
- 為 fptr、rptr 指向的位置
# Function call
## rand()
```c
/* Return a random integer between 0 and RAND_MAX. */
int
rand (void)
{
return (int) __random ();
}
```
- [link](https://elixir.bootlin.com/glibc/glibc-2.23/source/stdlib/rand.c#L25)
## __random()
```c
/* If we are using the trivial TYPE_0 R.N.G., just do the old linear
congruential bit. Otherwise, we do our fancy trinomial stuff, which is the
same in all the other cases due to all the global variables that have been
set up. The basic operation is to add the number at the rear pointer into
the one at the front pointer. Then both pointers are advanced to the next
location cyclically in the table. The value returned is the sum generated,
reduced to 31 bits by throwing away the "least random" low bit.
Note: The code takes advantage of the fact that both the front and
rear pointers can't wrap on the same call by not testing the rear
pointer if the front one has wrapped. Returns a 31-bit random number. */
long int
__random (void)
{
int32_t retval;
__libc_lock_lock (lock);
(void) __random_r (&unsafe_state, &retval);
__libc_lock_unlock (lock);
return retval;
}
weak_alias (__random, random)
```
- [link](https://elixir.bootlin.com/glibc/glibc-2.23/source/stdlib/random.c#L287)
## __random_r (struct random_data \*buf, int32_t \*result)
```c
/* If we are using the trivial TYPE_0 R.N.G., just do the old linear
congruential bit. Otherwise, we do our fancy trinomial stuff, which is the
same in all the other cases due to all the global variables that have been
set up. The basic operation is to add the number at the rear pointer into
the one at the front pointer. Then both pointers are advanced to the next
location cyclically in the table. The value returned is the sum generated,
reduced to 31 bits by throwing away the "least random" low bit.
Note: The code takes advantage of the fact that both the front and
rear pointers can't wrap on the same call by not testing the rear
pointer if the front one has wrapped. Returns a 31-bit random number. */
int
__random_r (struct random_data *buf, int32_t *result)
{
int32_t *state;
if (buf == NULL || result == NULL)
goto fail;
state = buf->state;
if (buf->rand_type == TYPE_0)
{
int32_t val = state[0];
val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
state[0] = val;
*result = val;
}
else
{
int32_t *fptr = buf->fptr;
int32_t *rptr = buf->rptr;
int32_t *end_ptr = buf->end_ptr;
int32_t val;
val = *fptr += *rptr;
/* Chucking least random bit. */
*result = (val >> 1) & 0x7fffffff;
++fptr;
if (fptr >= end_ptr)
{
fptr = state;
++rptr;
}
else
{
++rptr;
if (rptr >= end_ptr)
rptr = state;
}
buf->fptr = fptr;
buf->rptr = rptr;
}
return 0;
fail:
__set_errno (EINVAL);
return -1;
}
weak_alias (__random_r, random_r)
```