/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * Copyright owned by the Transaction Processing Performance Council.
 *
 * A copy of the license is included under extension/tpch/dbgen/LICENSE
 * in this repository.
 *
 * You may not use this file except in compliance with the License.
 *
 * THE TPC SOFTWARE IS AVAILABLE WITHOUT CHARGE FROM TPC.
 */
/*
 * $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 "dbgen/rng64.h" // @manual

#include <stdio.h>
#include <stdlib.h>

namespace facebook::velox::tpch::dbgen {

void dss_random64(DSS_HUGE* tgt, DSS_HUGE nLow, DSS_HUGE nHigh, seed_t* seed) {
  DSS_HUGE nTemp;

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

  seed->value = NextRand64(seed->value);
  nTemp = seed->value;
  if (nTemp < 0)
    nTemp = -nTemp;
  nTemp %= (nHigh - nLow + 1);
  *tgt = nLow + nTemp;
  seed->usage += 1;
#ifdef RNG_TEST
  seed->nCalls += 1;
#endif

  return;
}

DSS_HUGE
NextRand64(DSS_HUGE nSeed) {
  DSS_HUGE a = static_cast<unsigned DSS_HUGE>(RNG_A);
  DSS_HUGE c = static_cast<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 */
  /* */
  /* explicitly: */
  /* 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;
}

} // namespace facebook::velox::tpch::dbgen
