Search code examples
crandomgsl

gsl_rng functions: in what order do they compile


I am learning gsl_rng library and found an interesting question.

I understand that the environment variables (GSL_RNG_TYPE and GSL_RNG_SEED) can be used to set library variables (gsl_rng_default and gsl_rng_default_seed) during run time (without re-compile). You just need to add gsl_rng_env_setup() and then change these two variables in terminal before do ./a.out.

However, if I specifically set the gsl_rng_default and gsl_rng_default_seed in the code (eg. use "taus" and "12"), with the same program compiled, now I cannot change the seed value at run time but can still change the generator type.

I am new to this stuff so probably I missed something. But can anyone help me understand why this happen? Why do these two variables behave differently? Is there an order or over-write problem?

Here is my code (simple practice):

#include <stdio.h>
#include <gsl/gsl_rng.h>

int main (void)
{
  const gsl_rng_type * T;   /*generator type*/
  gsl_rng * r;          /*rng instance*/

  int i, n = 20;

  gsl_rng_env_setup();      /*read from environment variable*/


  T = gsl_rng_default;  /*choose default generator type*/

  gsl_rng_default = gsl_rng_mt19937;
  gsl_rng_default_seed = 12;

  r = gsl_rng_alloc (T);    /*create an instance*/

  for (i = 0; i < n; i++) 
    {
      double u = gsl_rng_uniform (r);
      printf ("%.5f\n", u);
    }



  gsl_rng_free (r);     /*free all memory associated with r*/

 return 0;
}

Solution

  • If we step through the code in execution order, we see what happens:

    gsl_rng_env_setup();      /*read from environment variable*/
    

    so gsl_rnd_default and gsl_rng_default_seed now contain the values from the environment, or if they weren't set, the library defaults.

    T = gsl_rng_default;  /*choose default generator type*/
    

    T now contains a copy of the environment value

    gsl_rng_default = gsl_rng_mt19937;
    gsl_rng_default_seed = 12;
    

    now we've overwritten both the values from earlier

    r = gsl_rng_alloc (T);    /*create an instance*/
    

    At this point, since gsl_rng_alloc() uses the generator type we pass in the parameter, it doesn't matter that gsl_rng_default was overwritten because we're passing T, and that still contains its copy of the value from beforehand. However, since gsl_rng_alloc() will go ahead and use the current value of gsl_rnd_default, it gets the 12 that we put there.

    If you were to assign your default values before calling gsl_rng_env_setup(), you'd overwrite the library defaults, then those values you set will be overwritten if the environment variables are set, or passed through if they aren't, which seems like the behaviour you really want.