// Random numbers for testing.

#include "trandom.h"
#include "cl_macros.h"
#include "cl_DS.h"
#include "cl_random_impl.h"
#include "cl_I.h"

static void testrandom_UDS (cl_random_state& randomstate, uintD* MSDptr, uintC len)
{
  // Idea from Torbjörn Granlund, see his "random2.c" file in gmp 2.0.
  var uintD* ptr = MSDptr mspop len;
  DS_clear_loop(MSDptr,len,ptr);
  var uintL bit_pos = 0;
  var uint32 ran = 0;
  var uintC ran_bits = 0;
  while (bit_pos < intDsize*(uintL)len)
    { if (ran_bits < log2_intDsize+1)
        { ran = random32(randomstate); ran_bits = 32; }
      var uintL n_bits = (ran >> 1) % intDsize + 1; // number of bits
      if (ran & 1)
        { // put in a bit string of n_bits bits at position bit_pos.
          if (bit_pos + n_bits > intDsize*(uintL)len)
            { n_bits = intDsize*(uintL)len - bit_pos; }
          if (bit_pos / intDsize == (bit_pos + n_bits - 1) / intDsize)
            { // need to modify one digit
              lspref(ptr,bit_pos/intDsize) |= (((uintD)1 << n_bits) - 1) << (bit_pos%intDsize);
            }
            else
            { // need to modify two adjacent digits
              lspref(ptr,bit_pos/intDsize) |= ((uintD)(-1) << (bit_pos%intDsize));
              lspref(ptr,bit_pos/intDsize+1) |= (((uintD)1 << ((bit_pos+n_bits)%intDsize)) - 1);
            }
        }
      bit_pos = bit_pos + n_bits;
      ran = ran >> (log2_intDsize+1); ran_bits -= log2_intDsize+1;
    }
}

cl_I testrandom_I ()
{
  var cl_random_state& randomstate = cl_default_random_state;
  var uint32 ran = random32(randomstate);
  var cl_boolean negative = (cl_boolean)(ran & 1);
  var cl_boolean algo = (cl_boolean)((ran>>1) & 1);
  ran = ran >> 2;
  ran = ran & ((1<<8)-1);
  var uintC len =
    (ran == 0 ? 0 :
     ran <= 80 ? 1 :
     ran <= 128 ? 2 :
     ran <= 158 ? 3 :
     ran <= 172 ? 4 :
     ran <= 200 ? (ran-153)/4 : // 5..11
     ran-189 // 12..66
    );
  SAVE_NUM_STACK // num_stack retten
  var uintD* MSDptr;
  num_stack_alloc_1(len,MSDptr=,);
  if (algo)
    { testrandom_UDS(randomstate,MSDptr,len); }
  else
    { random_UDS(randomstate,MSDptr,len); }
  var cl_I x = UDS_to_I(MSDptr,len);
  return (negative ? -x : x);
}

#ifdef TEST

#include <cl_io.h>

main ()
{
	for (;;) {
		fprintbinary(cl_stdout,testrandom_I());
		fprint(cl_stdout,"\n");
	}
}
#endif

