#define NO_ZIPF_SPIKE

//
//  (C)1997 Standard Performance Evaluation Corporation (SPEC)
//
//  This suite contains code acquired from several sources who
//  understand and agree with SPEC's goal of creating fair and
//  objective benchmarks to measure computer performance.
//
//  This copyright notice is placed here only to protect SPEC in the
//  event the source is misused in any manner that is contrary to
//  the spirit, the goals and the intent of SPEC.
//
//  The source code is provided to the user or company under the
//  license agreement for the SPEC Benchmark Suite for this suite.
// 

//////////////////////////////////////////////////////////////////
//                                                               *
//  Copyright 1991,1992  Legato Systems, Inc.                *
//  Copyright 1991,1992  Auspex Systems, Inc.                *
//  Copyright 1991,1992  Data General Corporation            *
//  Copyright 1991,1992  Digital Equipment Corporation       *
//  Copyright 1991,1992  Interphase Corporation              *
//  Copyright 1991,1992  Sun Microsystems, Inc.              *
//                                                               *
/////////////////////////////////////////////////////////////////  

//
// ---------------------- laddis_c_rnd.c ---------------------
//
//      Random number generator.
//
//.Exported_routines
//      double  Spec_random  (RandomState *theState);
//      long    Spec_nrandom (RandomState *theState);
//      void    Spec_srandom (RandomState *theState, int seed);
//
//.Local_routines
//      None
//
//.Revision_History
//  06-Nov-05           Convert to Sing#
//  24-May-97           Re-write to make thread-safe
//  28-Nov-91           ANSI C
//  01-Aug-91           laddis_srandom() and laddis_random()
//                      now use spec_srand() and spec_rand()
//                      instead of srandom() and random().
//  17-Apr-91           Created.
// 

//
// Here's the source for the random number generator that SPEC uses.
// The function to be called is "spec_rand" which returns an integer
// between 1 and MAX_INT-1.
//
// 


//////////////////////////////////////////////////////////////////////////////
// UNIFORM Distribution                                                      *
/////////////////////////////////////////////////////////////////////////////  
using System;
using Singularity.Application.SPECWeb99;

//using Microsoft.Singularity.Math;
//using Microsoft.Singularity;
//using Microsoft.Singularity.Directory;
//using Microsoft.Singularity.V1.Services;
//using Microsoft.Singularity.Io;
#if SINGULARITY
using Microsoft.Contracts;
#endif

namespace Singularity.Application.SPECWeb99.WebFiles
{
    public class Random
    {
        public const int A_MULTIPLIER = 16807;
        public const int M_MODULUS    = 2147483647; // (2**31)-1   
        public const int Q_QUOTIENT   = 127773;     // 2147483647 / 16807   
        public const int R_REMAINDER  = 2836;       // 2147483647 % 16807   
        //
        //Compute the next random number.
          //
        public class RandomState
        {
            public int val;

            public RandomState(int val)
            {
                this.val = val;
            }
        }

        public class ZipfState
        {
            public RandomState rstate;
            public int size;
            public double []table;

#if SINGULARITY
            [NotDelayed]
#endif
            public ZipfState (RandomState rstate, int size)
            {
                this.size   = size;
                this.rstate = rstate;
                table= new double[size+1];
                if (table == null) {
                    Console.WriteLine("ZipfState constructor: can't create {0} entries for table",
                                       size+1);
                }
            }
        } // ZipfState


#if STATIC_NORMAL_DIST
        public class NormalState {
            public RandomState rstate;
            public int size;
            public int []table;
        };
#else
        public class NormalState {
            public RandomState rstate;
            public double mean, stddev, y2;
            public bool use_last;
        };
#endif

        public double Spec_random(RandomState /*!*/ theState)
        // See "Random Number Generators: Good Ones Are Hard To Find",   
        //     Park & Miller, CACM 31#10 October 1988 pages 1192-1201.   
        ///////////////////////////////////////////////////////////  
        // THIS IMPLEMENTATION REQUIRES AT LEAST 32 BIT INTEGERS !   
        ///////////////////////////////////////////////////////////  
        {
            int lo;
            int hi;
            int test;

            hi = theState.val / Q_QUOTIENT;
            lo = theState.val % Q_QUOTIENT;
            test = A_MULTIPLIER * lo - R_REMAINDER * hi;
            if (test > 0) {
                theState.val = test;
            }
            else {
                theState.val = test + M_MODULUS;
            }
            return((float) theState.val / M_MODULUS);
        }

        //
        //Seed the random number generator.
        //
        public void Spec_srandom( RandomState /*!*/ theState, int seed ) {
            theState.val = seed;
        }

        //
        //Returns a random number.
        //
        public int Spec_nrandom( RandomState/*!*/ theState ) {
            Spec_random(theState);
            return(theState.val);
        }

        //////////////////////////////////////////////////////////////////////////////
        //ZIPF Distribution                                                         *
        ////////////////////////////////////////////////////////////////////////////  

        public ZipfState spec_zipf_setup(RandomState rstate, int size, double Z)
        {
            int     i;
            double zipf_sum;

            ZipfState theState = new ZipfState(rstate,  size);
            if (theState == null) return null;

            // compute zipf values for samples 1-n   
            for (i = 1; i <= size; i++) {
                theState.table[i] = Math.Pow(((double)1.0/((double)i)), Z);
                //theState.table[i] = 1;   // SPL TOTAL HACK until POW works!!
            }

            // sum the values so we can compute probabilities.   
            // at the same time, make the values cumulative   
            zipf_sum = 0.0;
            for (i = 1; i <= size; i++) {
                zipf_sum += theState.table[i] ;
                theState.table[i] = zipf_sum;
            }
            theState.table[size] = 0.0;
            theState.table[0] = 0.0;

            // compute probability values by dividing by the sum.   
            // also reverse the table so we have values starting at 1.0   
            //  and descending to 0.0  (this is what spec_zipf needs)   
            for (i = 0; i < size; i++) {
                theState.table[i] = 1.0 - (theState.table[i]/zipf_sum);
            }


            return theState;
        }

        private void spec_zipf_free( ZipfState/*!*/ theState) {
            if (theState.table != null) {
                theState.table = null;
            }
        }

        public int spec_zipf(ZipfState/*!*/ theState) {
            double  r;
            int     i;

#if NO_ZIPF_SPIKE
            do{
#endif
                r = Spec_random(theState.rstate);
                i = 0;
                while (r < theState.table[i]) {
                    i++;
                }
#if NO_ZIPF_SPIKE
            } while (i > theState.size);
#endif
            return i-1;
        }




#if STATIC_NORMAL_DIST
// Right now, mean and stddev are ignored.  If someone has a good function to
// generate the cdf for normal distributions, let me know...   
// size=20, mean = 10, stddev = 3.5, will generate numbers from 0 to 20   
NormalState spec_normal_setup(, RandomState rstate, double mean, double stddev) {

double normal_dist[] = {
    0.002137432,
    0.005064024,
    0.011135458,
    0.022750062,
    0.043238098,
    0.076563771,
    0.126549006,
    0.19568292,
    0.283854542,
    0.387548544,
    0.5,
    0.612451456,
    0.716145458,
    0.80431708,
    0.873450994,
    0.923436229,
    0.956761902,
    0.977249938,
    0.988864542,
    0.994935976,
    1
};
    int i, index = 0;

    theState.size   = 1000;
    theState.rstate = rstate;

    theState.table=(int *)malloc(sizeof(int)*(theState.size+1));
    if (theState.table == NULL) {
    fprintf(stderr, "spec_normal_setup: can't malloc %d bytes for table\n",
        sizeof(double)*theState.size);
    exit (1);
    }

    for (i = 0; i < theState.size; i++) {
    if ((double)i / (double)theState.size > normal_dist[index]) {
        index++;
    }
    theState.table[i] = index;
    }

    return theState;
}

void spec_normal_free(NormalState theState) {
    if (theState.table) {
    free(theState.table);
    }
}

int spec_nnormal(NormalState theState) {
    int rval = spec_nrandom(theState.rstate.val);
    rval = rval % theState.size;
    return theState.table[rval];
}

#else

// Guts of this routine are based on:   
// boxmuller.c           Implements the Polar form of the Box-Muller
   //                    Transformation
//
   //                 (c) Copyright 1994, Everett F. Carter Jr.
   //                     Permission is granted by the author to use
   //                     this software for any application provided this
   //                     copyright notice is preserved.
//
  //

    private NormalState spec_normal_setup(NormalState/*!*/ theState,
                                          RandomState/*!*/ rstate,
                                          double mean,
                                          double stddev)
    {
        theState.mean = mean;
        theState.stddev = stddev;
        theState.rstate = rstate;
        theState.use_last = false;
        return null;
    }

    void spec_normal_free(NormalState theState)
    {
    }

    private double Spec_normal(NormalState/*!*/ theState)
    {
        double x1, x2, w, y1;

        if (theState.use_last) {                // use value from previous call   
            y1 = theState.y2;
        }
        else {
            do {
                x1 = 2.0 * Spec_random(theState.rstate) - 1.0;
                x2 = 2.0 * Spec_random(theState.rstate) - 1.0;
                w = x1 * x1 + x2 * x2;
            } while (w >= 1.0);

            w = Math.Sqrt( (-2.0 * Math.Log( w ) ) / w );
            y1 = x1 * w;
            theState.y2 = x2 * w;
        }
        theState.use_last = !(theState.use_last);
        return( theState.mean + y1 * theState.stddev );
    }

    private int spec_nnormal(NormalState/*!*/ theState)
    {
        return (int)(Spec_normal(theState));
    }
#endif
    } //random
} //namespace
