#ifndef VALIB_RNG_H
#define VALIB_RNG_H

#include "defs.h"



class RNG
{
protected:
  uint32_t z;

public:
  RNG();
  RNG(int seed);
  RNG(const RNG &rng);
  RNG &operator =(const RNG &rng);
  
  RNG &seed(int seed);
  RNG &randomize();

  inline uint32_t next();
  inline uint32_t get_range(uint32_t range);
  inline sample_t get_sample();

  void fill_raw(void *data, size_t size);
  void fill_samples(sample_t *sample, size_t size);
};



inline uint32_t
RNG::next()
{
  static const uint32_t a = 16807;
  uint32_t hi = a * (z >> 15);
  uint32_t lo = a * (z & 0x7fff);
  z = (hi >> 16) + ((hi << 15) & 0x7fffffff) + lo;
  z = (z & 0x7fffffff) + (z >> 31);
  return z;
}

inline uint32_t
RNG::get_range(uint32_t range)
{
  uint32_t t = next();
  uint32_t hi1 = t >> 16;
  uint32_t lo1 = t & 0xffff;
  uint32_t hi2 = range >> 16;
  uint32_t lo2 = range & 0xffff;
  return hi1*hi2 + ((hi1*lo2) >> 16) + ((hi2*lo1) >> 16);
}

inline sample_t
RNG::get_sample()
{
  static const sample_t inv = 2.0 / 2147483646.0; 
  return (next() - 1) * inv - 1.0;
}

#endif
