#ifndef RAND_H
#define RAND_H

/*
 * Random number generators.
 * 2021-09-22 Udo Krebelder <udo@krebelder.at>
 */

#include "winutil.h"

#ifdef __cplusplus
extern "C" {
#endif


/*
 * Doug Lea splitmix Random Number Generator used in Java SDK,
 * but without the split feature.
 * http://gee.cs.oswego.edu/dl/papers/oopsla14.pdf
 *
 * Splitmix is used internally as seed generator for RandEx.
 *
 * Note that the generator fails the Birthday test, but
 * the values are not uniqe.
 *
 * There are some problems reported in
 * https://www.pcg-random.org/posts/bugs-in-splitmix.html.
 */

typedef struct {
    UINT64 data;
} SPLITMIX_STATE;


UINT64  SplitmixRandEx(SPLITMIX_STATE *state);
VOID    SplitmixSeedEx(SPLITMIX_STATE *state, UINT64 seed);

/* Global state of SplitmixRand */
EXTERN  SPLITMIX_STATE g_SplitmixState;

UINT64  SplitmixRand(VOID);
VOID    SplitmixSeed(UINT64 seed);


/*
 * xoroshiro128++ Random Number Generator.
 * https://prng.di.unimi.it/
 * According to the authors this is one of the best
 * pseudo random number generator.
 * The seed function uses SplitmixEx internally.
 */

typedef struct {
    UINT64 data[2];
} RAND_STATE;


UINT64  RandEx(RAND_STATE *state);
VOID    RandSeedEx(RAND_STATE *state, UINT64 seed);
VOID    RandJumpEx(RAND_STATE *state);

/* Global state of Rand */
EXTERN  RAND_STATE g_RandState;

UINT64  Rand(VOID);
VOID    RandSeed(UINT64 seed);
VOID    RandJump(VOID);


/*
 * Generate a random number between min and max-1 from
 * the uniform distributed 64 bit random argument.
 */
UINT64  RandRangeEx(UINT64 rnd_num, UINT64 min, UINT64 max);


/*
 * Generate a random number between min and max-1.
 * Uses Rand() internally as random number generator.
 */
UINT64  RandRange(UINT64 min, UINT64 max);


/*
 * For compatibility; uses Rand() internally.
 */
INT random(VOID);
void srandom(UINT seed);

/*
 * Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs"
 * Note that the generator fail the Birthday test because
 * values never repeat, which is sometimes useful
 * (Note that XorShift32Rand()%NUMBER destroys this feature).
 */

typedef struct {
    UINT    data;
} XORSHIFT32_STATE;


UINT    XorShift32RandEx(XORSHIFT32_STATE *state);
VOID    XorShift32SeedEx(XORSHIFT32_STATE *state, UINT seed);

EXTERN  XORSHIFT32_STATE g_XorShiftState;

VOID    XorShift32Seed(UINT seed);
UINT    XorShift32Rand(VOID);


#ifdef __cplusplus
}
#endif

#endif /* RAND_H */
