Click here to Skip to main content
16,022,205 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm a newbie to C programming.
After including the "xoshiro256starstar.c" and "splitmix64.c",
what should I do to generate 7 pseudo random numbers in a range from 0 to 99?

https://prng.di.unimi.it/xoshiro256starstar.c
https://prng.di.unimi.it/splitmix64.c
xoshiro/xoroshiro generators and the PRNG shootout

What I have tried:

C
#include <stdio.h>
#include "xoshiro256starstar.c"
#include "splitmix64.c"

int main(void)
{
  int random_number[7];
  /* How do I actually generate pseudo random numbers? */

  for(int i = 0; i < 7; ++i)
  {
    printf("random_number[%d] = %d\n", i, random_number[i] % 100);
  }

  return 0;
}
Posted
Updated 22-Aug-24 10:00am
v3

The algorithm author suggests to use the splitmix64 routine to generate the seed for the xoshiro256** one.
In order to avoid name clashes (for instance, both algorithms use the next function) I suggest the following approach:
Change the function names and provide (and then include) proper header files:

splitmix64.h header file
C
#ifndef __SPLITMIX64__
#define __SPLITMIX64__
#include <stdint.h>
uint64_t splitmix64_next();
void splitmix64_set_state(uint64_t state);
#endif


splitmix64.c source file
C
//...

// provide a set_state function
void splitmix64_set_state(uint64_t state)
{
  x = state;
}

// just change the function name, here
uint64_t splitmix64_next() {
//..



xoshiro256starstar.h header file
#ifndef __XOSHIRO256STARSTAR__
#define __XOSHIRO256STARSTAR__
#include <stdint.h>
void xosh_set_state(uint64_t state[4]);
uint64_t xosh_next();
#endif


xoshiro256starstar.c source file
//...
// provide a 'set_state' function
void xosh_set_state(uint64_t state[4])
{
  s[0] = state[0];
  s[1] = state[1];
  s[2] = state[2];
  s[3] = state[3];
}

// just change the function name, here
uint64_t xosh_next(void) { 
//..


eventually create the main function, for instance
C
#include <stdio.h>
#include <time.h>
#include "splitmix64.h"
#include "xoshiro256starstar.h"

int main(void)
{
  int random_number[7];

  uint64_t sm64seed = time(NULL); // this is the seed for the splitmix64 routine
  splitmix64_set_state(sm64seed);

  uint64_t xoshseed[4]; // this is the seed for the xoshiro256** routine
  // compute the seed for the xoshiro256**, using the splitmix64 
  xoshseed[0] =    splitmix64_next();
  xoshseed[1] =    splitmix64_next();
  xoshseed[2] =    splitmix64_next();
  xoshseed[3] =    splitmix64_next();
  xosh_set_state(xoshseed);

  // eventually generate the random numbers using the xoshiro256** algorithm
  for(int i = 0; i < 7; ++i)
  {
    printf("random_number[%d] = %lu\n", i, (xosh_next() % 100));
  }

  return 0;
}
 
Share this answer
 
v2
Comments
sasil4 29-Aug-24 16:07pm    
Thank you so much for taking the time to help me. I really appreciate the explanation you provided. It all makes sense now.
CPallini 31-Aug-24 3:43am    
You are welcome.
I would do something like this :
int main(void)
{
#define NUMBER_COUNT  7

  int random_number[ NUMBER_COUNT ];

  srand( 47 );    // seed the PRNG with a prime number for a repeatable sequence

// srand( time( NULL ) % RAND_MAX );   // seeded for a different sequence every time

  /* How do I actually generate pseudo random numbers? */

  for( int i = 0; i < NUMBER_COUNT; ++i )
       random_number[ i ] = rand() % 100;  // results will range from 0 to 99

  for(int i = 0; i < NUMBER_COUNT; ++i)
  {
    printf("random_number[%d] = %d\n", i, random_number[i] );
  }

  return 0;
}
I think you will also need to include time.h and stdlib.h to make it compile.

For more info here are some links to documentation : srand[^] and rand[^]
 
Share this answer
 
Comments
sasil4 22-Aug-24 16:08pm    
As I mentioned in my question, I'd like to generate random numbers using the xoshiro256starstar algorithm specifically.
For anyone who stumbles upon this thread in the future:

Since the Xoshiro256** PRNG relies on the SplitMix64 PRNG anyway,
I merged the source files xoshiro256ss.c and splitmix64.c into prng.c,
and also created a corresponding header file prng.h.

To use, just copy prng.c and prng.h into your project directory
and include the header file in your main.c with #include "prng.h"

main.c source file:
C
#include <stdio.h>
#include <time.h>
#include "prng.h"

int main(void)
{
  /* The following code demonstrates
  a detailed approach to generating a pseudorandom number
  with fine-grained control over the Xoshiro256** PRNG state:

  1. Initialize the seed for the SplitMix64 PRNG.
  2. Set the internal state of the SplitMix64 PRNG.
  3. Generate seeds for the Xoshiro256** PRNG using the SplitMix64 PRNG.
  4. Set the internal state of the Xoshiro256** PRNG.
  5. Generate a 64-bit pseudorandom number using the Xoshiro256** PRNG.*/

  uint64_t seed_splitmix64 = time(NULL);                          /* 1 */
  PRNG_SetState_splitmix64(seed_splitmix64);                      /* 2 */

  uint64_t seed_xoshiro256ss[4] = {0};                            /* 3 */
  for(int i = 0; i < 4; ++i)
  {
    seed_xoshiro256ss[i] = PRNG_GenerateNumber_splitmix64();
  }
  PRNG_SetState_xoshiro256ss(seed_xoshiro256ss);                  /* 4 */

  uint64_t num_xoshiro256ss = PRNG_GenerateNumber_xoshiro256ss(); /* 5 */
  printf("%lu\n", num_xoshiro256ss);


  /* Alternatively, the following code uses aliases
  for a simpler 3-step pseudorandom number generation process:

  1. Initialize the seed.
  2. Set the internal state of the PRNG.
  3. Generate a random number. */

  uint64_t seed = time(NULL);                                     /* 1 */
  PRNG_SetState(seed);                                            /* 2 */
  uint64_t num = PRNG_GenerateNumber();                           /* 3 */
  printf("%lu\n", num);

  return 0;
}

prng.h header file:
#ifndef SPLITMIX64_H
#define SPLITMIX64_H

#include <stdint.h>

void     PRNG_SetState_splitmix64(uint64_t state);
void     PRNG_SetState_xoshiro256ss(uint64_t state[4]);
void     PRNG_SetState(uint64_t state);

uint64_t PRNG_GenerateNumber_splitmix64(void);
uint64_t PRNG_GenerateNumber_xoshiro256ss(void);

typedef uint64_t (*generate_number)(void);
extern generate_number PRNG_GenerateNumber;

#endif


I don't understand the algorithm logic. But because of the compiler warning:

"comparison of integer expressions of different signedness:
‘int’ and ‘long unsigned int’ [-Wsign-compare]"


I replaced for(int i = 0; i < sizeof JUMP / sizeof *JUMP; i++)
with for(uint64_t i = 0; i < sizeof JUMP / sizeof *JUMP; i++)

and also for(int i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++)
with for(uint64_t i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++)

I'm not sure if it breaks the algorithm in any way but that's what I did.

prng.c source file:
C
/* splitmix64 */
/* https://prng.di.unimi.it/splitmix64.c */

/*  Written in 2015 by Sebastiano Vigna (vigna@acm.org)

To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */

#include "prng.h"
//#include <stdint.h>

/* This is a fixed-increment version of Java 8's SplittableRandom generator
   See http://dx.doi.org/10.1145/2714064.2660195 and 
   http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html

   It is a very fast generator passing BigCrush, and it can be useful if
   for some reason you absolutely want 64 bits of state. */

static uint64_t x; /* The state can be seeded with any value. */

uint64_t PRNG_GenerateNumber_splitmix64(void)
//uint64_t next()
{
  uint64_t z = (x += 0x9e3779b97f4a7c15);
  z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
  z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
  return z ^ (z >> 31);
}



/* xoshiro256** */
/* https://prng.di.unimi.it/xoshiro256starstar.c */

/*  Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)

To the extent possible under law, the author has dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */

/* This is xoshiro256** 1.0, one of our all-purpose, rock-solid
   generators. It has excellent (sub-ns) speed, a state (256 bits) that is
   large enough for any parallel application, and it passes all tests we
   are aware of.

   For generating just floating-point numbers, xoshiro256+ is even faster.

   The state must be seeded so that it is not everywhere zero. If you have
   a 64-bit seed, we suggest to seed a splitmix64 generator and use its
   output to fill s. */

// Replace x with xl, so it doesn't shadow the global declaration
static inline uint64_t rotl(const uint64_t xl, int k)
{
  return (xl << k) | (xl >> (64 - k));
}

static uint64_t s[4];

uint64_t PRNG_GenerateNumber_xoshiro256ss(void)
//uint64_t next(void)
{
  const uint64_t result = rotl(s[1] * 5, 7) * 9;

  const uint64_t t = s[1] << 17;

  s[2] ^= s[0];
  s[3] ^= s[1];
  s[1] ^= s[2];
  s[0] ^= s[3];

  s[2] ^= t;

  s[3] = rotl(s[3], 45);

  return result;
}

/* This is the jump function for the generator. It is equivalent
   to 2^128 calls to PRNG_GenerateNumber_xoshiro256ss(); it can be used to generate 2^128
   non-overlapping subsequences for parallel computations. */
void jump(void)
{
  static const uint64_t JUMP[] = { 0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, 0xa9582618e03fc9aa, 0x39abdc4529b1661c };

  uint64_t s0 = 0;
  uint64_t s1 = 0;
  uint64_t s2 = 0;
  uint64_t s3 = 0;

  for(uint64_t i = 0; i < sizeof JUMP / sizeof *JUMP; i++)
  //for(int i = 0; i < sizeof JUMP / sizeof *JUMP; i++)
  {
    for(int b = 0; b < 64; b++)
    {
      if (JUMP[i] & UINT64_C(1) << b)
      {
        s0 ^= s[0];
        s1 ^= s[1];
        s2 ^= s[2];
        s3 ^= s[3];
      }
      PRNG_GenerateNumber_xoshiro256ss();  
    }
  }
    
  s[0] = s0;
  s[1] = s1;
  s[2] = s2;
  s[3] = s3;
}

/* This is the long-jump function for the generator. It is equivalent to
   2^192 calls to PRNG_GenerateNumber_xoshiro256ss(); it can be used to generate 2^64 starting points,
   from each of which jump() will generate 2^64 non-overlapping
   subsequences for parallel distributed computations. */
void long_jump(void)
{
  static const uint64_t LONG_JUMP[] = { 0x76e15d3efefdcbbf, 0xc5004e441c522fb3, 0x77710069854ee241, 0x39109bb02acbe635 };

  uint64_t s0 = 0;
  uint64_t s1 = 0;
  uint64_t s2 = 0;
  uint64_t s3 = 0;

  for(uint64_t i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++)
  //for(int i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++)
  {
    for(int b = 0; b < 64; b++)
    {
      if (LONG_JUMP[i] & UINT64_C(1) << b)
      {
        s0 ^= s[0];
        s1 ^= s[1];
        s2 ^= s[2];
        s3 ^= s[3];
      }
      PRNG_GenerateNumber_xoshiro256ss();  
    }
  }
    
  s[0] = s0;
  s[1] = s1;
  s[2] = s2;
  s[3] = s3;
}

// Provide the function
void PRNG_SetState_splitmix64(uint64_t state)
{
  x = state;
}

// Provide the function
void PRNG_SetState_xoshiro256ss(uint64_t state[4])
{
  for(int i = 0; i < 4; ++i)
  {
    s[i] = state[i];
  }
}

// Provide the function
void PRNG_SetState(uint64_t state)
{
  x = state;

  for(int i = 0; i < 4; ++i)
  {
    s[i] = PRNG_GenerateNumber_splitmix64();
  }
}

// Provide the function alias
generate_number PRNG_GenerateNumber = PRNG_GenerateNumber_xoshiro256ss;
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900