/* misc.cc
 * Daniel S. Roche, January 2011
 * See COPYING.txt for permissions
 *
 * Miscellaneous utilities for the interpolation code.
 * Implementation file
 */

#include <cmath>
#include <iostream>
#include <fstream>
#include <NTL/ZZ.h>
#include "misc.h"

// Constants
long double PI_LD = std::acos(-1.0L);
double PI_D = acos(-1.0);
float PI_F = acos(-1.0F);

// Get Pi in the given floating point type
template<>
double getPi() { return PI_D; }

template<>
long double getPi() { return PI_LD; }

template<>
float getPi() { return PI_F; }

/* Seed NTL's random generator from an unsigned long long */
void ullseed (unsigned long long seed) {
  NTL::SetSeed (NTL::ZZFromBytes (reinterpret_cast<unsigned char*>(&seed),
                        sizeof(unsigned long long)));
}

/* Initialize NTL's random seed from /dev/urandom and
 * (optionally) print its value to stdout.
 */
void randseed (bool printit) {
  unsigned long long seed;
  std::ifstream randin ("/dev/urandom");
  //FILE *randin = fopen ("/dev/urandom", "r");
  randin.read ((char*)(&seed), sizeof(unsigned long long)); 
  //fread (&seed, sizeof(unsigned long long), 1, randin);
  randin.close();
  //fclose (randin);
  ullseed (seed);
  if (printit) {
    std::cout << "--------------------------------------------------------------------------------" << std::endl 
              << "The pseudo-random number generator has been seeded from /dev/urandom." << std::endl
              << "If something interesting happens and you want to re-create it, replace" << std::endl
              << "the call to randseed() with "
              << "ullseed(0x" << std::hex << seed << std::dec
              << ");" << std::endl
              << "--------------------------------------------------------------------------------" << std::endl;
  }
}

/* Computes a lower bound on lambda so that at least half the primes
 * between lambda and 2*lambda are good.
 * See Lemma 3.1 from Giesbrecht & Roche (2011).
 */
long goodp_bound (const NTL::ZZ& D, long T) {
  long lambda = (long) std::ceil 
    ((5.0/3.0) * T * (T-1) * NTL::log(D));
  if (lambda < 21) lambda = 21;
  return lambda;
}

/* Computes a "best guess" bound on a small number to start searching
 *  for good primes.
 * This bound is based on the birthday problem, assuming the exponents
 * are randomly distributed in the range [0,...,p-1] (they are not!), 
 * how large does p have to be in order to make them all distinct w.h.p.
 * The returned value is based on the exponential approximation to the
 * birthday problem.
 */
long guessp_bound (const NTL::ZZ& D, long T) {
  double dubT = (double) T;
  return std::ceil(dubT*(dubT-1)/std::log(4.0));
}
