libc/rand_r: support rand_r api

refs to https://pubs.opengroup.org/onlinepubs/7908799/xsh/rand.html

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
dongjiuzhu1 2023-06-28 12:29:03 +08:00 committed by Xiang Xiao
parent 97a2528de9
commit 5d09b4cbd0
2 changed files with 73 additions and 42 deletions

View File

@ -132,6 +132,7 @@ extern "C"
void srand(unsigned int seed); void srand(unsigned int seed);
int rand(void); int rand(void);
int rand_r(FAR unsigned int *seedp);
void lcong48(FAR unsigned short int param[7]); void lcong48(FAR unsigned short int param[7]);
FAR unsigned short int *seed48(FAR unsigned short int seed16v[3]); FAR unsigned short int *seed48(FAR unsigned short int seed16v[3]);
void srand48(long int seedval); void srand48(long int seedval);

View File

@ -67,9 +67,9 @@ typedef double float_t;
/* First order congruential generators */ /* First order congruential generators */
static inline unsigned long fgenerate1(void); static inline unsigned long fgenerate1(FAR unsigned long *seed);
#if (CONFIG_LIBC_RAND_ORDER == 1) #if (CONFIG_LIBC_RAND_ORDER == 1)
static float_t frand1(void); static float_t frand1(FAR unsigned long *seed);
#endif #endif
/* Second order congruential generators */ /* Second order congruential generators */
@ -106,7 +106,7 @@ static unsigned long g_randint3;
/* First order congruential generators */ /* First order congruential generators */
static inline unsigned long fgenerate1(void) static inline unsigned long fgenerate1(FAR unsigned long *seed)
{ {
unsigned long randint; unsigned long randint;
@ -115,17 +115,17 @@ static inline unsigned long fgenerate1(void)
* the first order random number generator. * the first order random number generator.
*/ */
randint = (RND1_CONSTK * g_randint1) % RND1_CONSTP; randint = (RND1_CONSTK * (*seed)) % RND1_CONSTP;
g_randint1 = (randint == 0 ? 1 : randint); *seed = (randint == 0 ? 1 : randint);
return randint; return randint;
} }
#if (CONFIG_LIBC_RAND_ORDER == 1) #if (CONFIG_LIBC_RAND_ORDER == 1)
static float_t frand1(void) static float_t frand1(FAR unsigned long *seed)
{ {
/* First order congruential generator. */ /* First order congruential generator. */
unsigned long randint = fgenerate1(); unsigned long randint = fgenerate1(seed);
/* Construct an floating point value in the range from 0.0 up to 1.0 */ /* Construct an floating point value in the range from 0.0 up to 1.0 */
@ -215,40 +215,8 @@ static float_t frand3(void)
#endif #endif
#endif #endif
/**************************************************************************** static unsigned long nrand_r(unsigned long limit,
* Public Functions FAR unsigned long *seed)
****************************************************************************/
/****************************************************************************
* Name: srand
*
* Description:
* Seed the congruential random number generator.
*
****************************************************************************/
void srand(unsigned int seed)
{
g_randint1 = seed;
#if (CONFIG_LIBC_RAND_ORDER > 1)
g_randint2 = seed;
fgenerate1();
#if (CONFIG_LIBC_RAND_ORDER > 2)
g_randint3 = seed;
fgenerate2();
#endif
#endif
}
/****************************************************************************
* Name: nrand
*
* Description:
* Return a random, unsigned long value in the range of 0 to (limit - 1)
*
****************************************************************************/
unsigned long nrand(unsigned long limit)
{ {
unsigned long result; unsigned long result;
float_t ratio; float_t ratio;
@ -260,7 +228,7 @@ unsigned long nrand(unsigned long limit)
/* Get a random integer in the range 0.0 - 1.0 */ /* Get a random integer in the range 0.0 - 1.0 */
#if (CONFIG_LIBC_RAND_ORDER == 1) #if (CONFIG_LIBC_RAND_ORDER == 1)
ratio = frand1(); ratio = frand1(seed);
#elif (CONFIG_LIBC_RAND_ORDER == 2) #elif (CONFIG_LIBC_RAND_ORDER == 2)
ratio = frand2(); ratio = frand2();
#else /* if (CONFIG_LIBC_RAND_ORDER > 2) */ #else /* if (CONFIG_LIBC_RAND_ORDER > 2) */
@ -279,3 +247,65 @@ unsigned long nrand(unsigned long limit)
return result; return result;
} }
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: srand
*
* Description:
* Seed the congruential random number generator.
*
****************************************************************************/
void srand(unsigned int seed)
{
g_randint1 = seed;
#if (CONFIG_LIBC_RAND_ORDER > 1)
g_randint2 = seed;
fgenerate1(&g_randint1);
#if (CONFIG_LIBC_RAND_ORDER > 2)
g_randint3 = seed;
fgenerate2();
#endif
#endif
}
/****************************************************************************
* Name: nrand
*
* Description:
* Return a random, unsigned long value in the range of 0 to (limit - 1)
*
****************************************************************************/
unsigned long nrand(unsigned long limit)
{
return nrand_r(limit, &g_randint1);
}
/****************************************************************************
* Name: rand_r
*
* Description:
* The function rand() is not reentrant, since it uses hidden state that
* is modified on each call. This might just be the seed value to be used
* by the next call, or it might be something more elaborate. In order to
* get reproducible behavior in a threaded application, this state must be
* made explicit; this can be done using the reentrant function rand_r().
*
* Return a random, int value in the range of 0 to INT_MAX.
*
****************************************************************************/
int rand_r(FAR unsigned int *seedp)
{
unsigned long seed = *seedp;
unsigned long rand;
rand = nrand_r(INT_MAX, &seed);
*seedp = (unsigned int)seed;
return (int)rand;
}