//-*-c++-*-
// -------------------------------------------
// RCS data:
// $Date: 2003/06/23 14:47:24 $
// $Revision: 1.1.1.1 $
// $Source: /cvsroot/miwm/miwm/miwm/rng.h,v $
// $Id: rng.h,v 1.1.1.1 2003/06/23 14:47:24 bwise837 Exp $
// $RCSfile: rng.h,v $
//
// -------------------------------------------
// Copyright by Ben Paul Wise.
// -------------------------------------------
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// -------------------------------------------
// this is a very basic random number generator
// -------------------------------------------

#ifndef RANDOM_NUMBER_GENERATOR_H
#define RANDOM_NUMBER_GENERATOR_H

// #include <stdio.h>
// #include <iostream.h>
// #include <assert.h>
// #include <math.h>

#include "alpha.h"

// ====================================================
// NOTE WELL: G1, G2, G3, G4 all have strong cycles (a low-amplitude
// short added to a large-amplitude long ) that show
// up very bady in the "normal" function!  
// RAN2 avoids these problems, and I can not find any other problems
// with it. So it is now my standard, rendering the whole RNG
// class somewhat useless.
// ====================================================

// I added these particular constants when I used the previous
// numbers to draw a random bitmap (random draws from the
// color map) and discovered that it was very non-random,
// and even that most of the recommended ones had blatent
// periodicities when used to draw a 2D image by "random" sampling
// from X's color map! 
//
// Of those that had no obvious 2D periodicities (and I have
// no way to evaluate 3D+ periodicities), the other one produced
// severely non-uniform results (that is, it produced almost as 
// many numbers in the bottom 1/3 of its range as it did in the
// top 2/3 of its range).  
//
// The ONLY ones I found that (a) did not require assembly 
// language or other fanciness and (b) did not fail the above
// two simple tests were:
//
//       V := (a * V  +  c  )  %  m, where:
//
//           A             C            M
//  G1   205       29573    139968
//  G2   281       28411    134456
//
//  (These were all tested with the 150-element shuffle array).

// G1 and G2 are both from "Numerical Recipes"
// G1, 457 
// #define RANDOMA 205L
// #define RANDOMC 29573L
// #define RANDOMM 139968L
// #define RANDOMARRAYLENGTH 457

// G2, 457 (a moderately large prime number)
//  #define RANDOMA 281L
//  #define RANDOMC 28411L
//  #define RANDOMM 134456L
//  #define RANDOMARRAYLENGTH 457

// G3, G4 are from Knuth
// G3, 457 
// #define RANDOMA 69069L
// #define RANDOMC 0L
// #define RANDOMM 4294967296L
// #define RANDOMARRAYLENGTH 457

// G4, 457 
// #define RANDOMA 16807L
// #define RANDOMC 0L
// #define RANDOMM 2147483647L
// #define RANDOMARRAYLENGTH 457

// when all the linear congruential generators persisted 
// (despite using a shuffle array) in having these two problems,
//
// (A) showing at least vague repetitive patterns when used
//  to draw "random" 2D images by picking  from the color map, and
//
// (B) making the "normal" deviates show a distinct superposition of
// of small/short and large/long sinusoids (noisy, of course, as the
// period is enormous),
//
// I decided to go with the two ones below.
// ----------------------------------------
// this is the recommended best one from "Numerical Recipes"
#define IM1 2147483563
#define IM2 2147483399
#define AM (1.0/IM1)
#define IMM1 (IM1-1)
#define IA1 40014
#define IA2 40692
#define IQ1 53668
#define IQ2 52774
#define IR1 12211
#define IR2 3791
#define NTAB 32
#define NDIV (1+IMM1/NTAB)
#define EPS 1.2e-7
#define RNMX (1.0-EPS)

// ----------------------------------------

class RNG {
public:
  RNG();         // don't care about repeatability
  RNG(int seed); //   do  care about repeatability
  ~RNG();
  
  // return a random float between 0.0 and 1.0
  // Knuth's funny algorithm of "Seminumerical Algorithms",
  // section 3.2.2,  by Mitchell and Moore
  float fvalue();   

  // return a random float between 0.0 and 1.0
  // this is the one most highly recommended by
  // "Numerical Recipes". its much more elaborate
  // than the Mitchell&Moore algorithm.
  float ran2(long *idum);



  // return a random float between a and b
  // mean is (a+b)/2
  // variance is (b-a)^2 / 12
  float uniform(float a, float b);  

  // return a psuedo-normal with given mean and standard deviation
  float normal(float mean, float stdv);  

  // return a random integer i, with a<=i<=b, assuming a<= b
  int select(int a, int b);

  long ran2seed;

protected:

private:

  void fill_array();


  // see Knuth, section 3.2.2, page 26
  long int Y[55]; // 55 is a magic number. DO NOT change it.
  long nrkSeed;
  int jY;
  int kY;
  long mY;
};

// ----------------------------------------

#endif

// ----------------------------------------
// end of  rng.h
// ----------------------------------------



