/*
* $Id: rng64.c,v 1.7 2008/03/21 17:38:39 jms Exp $
*
* This software contains proprietary and confidential information of Gradient
* Systems Inc.  By accepting transfer of this copy, Recipient agrees
* to retain this software in confidence, to prevent disclosure to others, and
* to make no use of this software other than that for which it was delivered.
* This is an unpublished copyright work Gradient Systems, Inc.  Execpt as
* permitted by federal law, 17 USC 117, copying is strictly prohibited.
*
* Gradient Systems Inc. CONFIDENTIAL - (Gradient Systems Inc. Confidential
* when combined with the aggregated modules for this product)
* OBJECT CODE ONLY SOURCE MATERIALS
* (C) COPYRIGHT Gradient Systems Inc. 2003
*
* All Rights Reserved  
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF GRADIENT SYSTEMS, INC.
* The copyright notice above does not evidence any   
* actual or intended publication of such source code.
*
* Revision History
* ===================
* $Log: rng64.c,v $
* Revision 1.7  2008/03/21 17:38:39  jms
* changes for 2.6.3
*
* Revision 1.6  2006/04/26 23:20:05  jms
* Data type clenaup for qgen
*
* Revision 1.5  2006/03/08 21:25:27  jms
* change to RNG64 to address overflow/underflow issues
*
* Revision 1.4  2005/10/25 17:26:38  jms
* check in integration between microsoft changes and baseline code
*
* Revision 1.3  2005/03/04 19:48:39  jms
* Changes from Doug Johnson to address very large scale factors
*
* Revision 1.2  2005/01/03 20:08:59  jms
* change line terminations
*
* Revision 1.1.1.1  2004/11/24 23:31:47  jms
* re-establish external server
*
* Revision 1.2  2004/02/18 16:45:30  jms
* remove C++ style comments for AIX compiler
*
* Revision 1.1.1.1  2003/08/08 21:57:34  jms
* recreation after CVS crash
*
* Revision 1.1  2003/08/08 21:57:34  jms
* first integration of rng64 for o_custkey and l_partkey
*
*/
#include "config.h"
#include "dss.h"
#include <stdio.h>
#include <stdlib.h>
#include "rng64.h"
extern double dM;

extern seed_t Seed[];

void
dss_random64(DSS_HUGE *tgt, DSS_HUGE nLow, DSS_HUGE nHigh, long nStream)
{
    DSS_HUGE            nTemp;

    if (nStream < 0 || nStream > MAX_STREAM)
        nStream = 0;

    if (nLow > nHigh)
    {
        nTemp = nLow;
        nLow = nHigh;
        nHigh = nTemp;
    }

    Seed[nStream].value = NextRand64(Seed[nStream].value);
    nTemp = Seed[nStream].value;
    if (nTemp < 0) 
	nTemp = -nTemp;
    nTemp %= (nHigh - nLow + 1);
    *tgt = nLow + nTemp;
    Seed[nStream].usage += 1;
#ifdef RNG_TEST
   Seed[nStream].nCalls += 1;
#endif

	return;
}

DSS_HUGE
NextRand64(DSS_HUGE nSeed){
	
	DSS_HUGE a = (unsigned DSS_HUGE) RNG_A;
    DSS_HUGE c = (unsigned DSS_HUGE) RNG_C;
    nSeed = (nSeed * a + c); /* implicitely truncated to 64bits */
	
    return (nSeed);
}

DSS_HUGE AdvanceRand64( DSS_HUGE nSeed,
				  DSS_HUGE nCount) {
  unsigned DSS_HUGE a = RNG_A ;
  unsigned DSS_HUGE c = RNG_C ;
  int nBit;
  unsigned DSS_HUGE Apow=a, Dsum=c;

  /* if nothing to do, do nothing ! */
  if( nCount == 0 ) return nSeed;

  /* Recursively compute X(n) = A * X(n-1) + C */
  /* */
  /* explicitely: */
  /* X(n) = A^n * X(0) + { A^(n-1) + A^(n-2) + ... A + 1 } * C */
  /* */
  /* we write this as: */
  /* X(n) = Apow(n) * X(0) + Dsum(n) * C */
  /* */
  /* we use the following relations: */
  /* Apow(n) = A^(n%2)*Apow(n/2)*Apow(n/2) */
  /* Dsum(n) =   (n%2)*Apow(n/2)*Apow(n/2) + (Apow(n/2) + 1) * Dsum(n/2) */
  /* */

  /* first get the highest non-zero bit */
  for( nBit = 0; (nCount >> nBit) != RNG_C ; nBit ++){}
  
  /* go 1 bit at the time */
  while( --nBit >= 0 ) {
    Dsum *= (Apow + 1);
    Apow = Apow * Apow;
    if( ((nCount >> nBit) % 2) == 1 ) { /* odd value */
      Dsum += Apow;
      Apow *= a;
    }
  }
  nSeed = nSeed * Apow + Dsum * c;
  return nSeed;
}
