lcg_engine.h 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. #pragma once
  2. #include <utility>
  3. #include <util/generic/typetraits.h>
  4. // common engine for lcg-based RNG's
  5. // http://en.wikipedia.org/wiki/Linear_congruential_generator
  6. namespace NPrivate {
  7. template <typename T>
  8. T LcgAdvance(T seed, T lcgBase, T lcgAddend, T delta) noexcept;
  9. }
  10. template <typename T, T A, T C>
  11. struct TFastLcgIterator {
  12. static_assert(C % 2 == 1, "C must be odd");
  13. static constexpr T Iterate(T x) noexcept {
  14. return x * A + C;
  15. }
  16. static inline T IterateMultiple(T x, T delta) noexcept {
  17. return ::NPrivate::LcgAdvance(x, A, C, delta);
  18. }
  19. };
  20. template <typename T, T A>
  21. struct TLcgIterator {
  22. inline TLcgIterator(T seq) noexcept
  23. : C((seq << 1u) | (T)1) // C must be odd
  24. {
  25. }
  26. inline T Iterate(T x) noexcept {
  27. return x * A + C;
  28. }
  29. inline T IterateMultiple(T x, T delta) noexcept {
  30. return ::NPrivate::LcgAdvance(x, A, C, delta);
  31. }
  32. const T C;
  33. };
  34. template <class TIterator, class TMixer>
  35. struct TLcgRngBase: public TIterator, public TMixer {
  36. using TStateType = decltype(std::declval<TIterator>().Iterate(0));
  37. using TResultType = decltype(std::declval<TMixer>().Mix(TStateType()));
  38. template <typename... Args>
  39. inline TLcgRngBase(TStateType seed, Args&&... args)
  40. : TIterator(std::forward<Args>(args)...)
  41. , X(seed)
  42. {
  43. }
  44. inline TResultType GenRand() noexcept {
  45. return this->Mix(X = this->Iterate(X));
  46. }
  47. inline void Advance(TStateType delta) noexcept {
  48. X = this->IterateMultiple(X, delta);
  49. }
  50. TStateType X;
  51. };