Skip to content

Instantly share code, notes, and snippets.

@imneme
Created June 9, 2018 20:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save imneme/09ef03fd1ebde6f72dc1bb9dd9c5b61d to your computer and use it in GitHub Desktop.
Save imneme/09ef03fd1ebde6f72dc1bb9dd9c5b61d to your computer and use it in GitHub Desktop.
A C++ implementation of a set of PRNG adapters
#ifndef RND_ADAPTERS_HPP_INCLUDED
#define RND_ADAPTERS_HPP_INCLUDED 1
/*
* A C++ implementation of a set of PRNG adapters.
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Melissa E. O'Neill
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
// regularized_rng -- set min() to always be zero, use an appropriate type
//
// (the other adapters require sensible generators with a integer output and a
// min of zero, this adapter allows whacky generators to be used with those
// adapters)
template <typename RNG, typename rtype = typename RNG::result_type,
auto SCALE = 1>
struct regularized_rng : public RNG {
using RNG::RNG;
using result_type = rtype;
static constexpr result_type min() { return result_type(0); }
static constexpr result_type max()
{
return result_type((RNG::max()*SCALE) - result_type(RNG::min()*SCALE));
}
result_type operator()()
{
return result_type(RNG::operator()()*SCALE)
- result_type(RNG::min()*SCALE);
}
};
// divided_rng -- divide the output by a constant
template <typename RNG, unsigned int DIVISOR,
typename rtype = typename RNG::result_type>
struct divided_rng : public RNG {
using RNG::RNG;
using result_type = rtype;
static_assert(RNG::min() == 0, "Requires sane PRNG");
static constexpr result_type min() { return RNG::min() / DIVISOR; }
static constexpr result_type max() { return RNG::max() / DIVISOR; }
result_type operator()() { return RNG::operator()() / DIVISOR; }
};
// skipping_rng - divide the output by a constant, skipping all outputs
// that don't have a desired remainder (reduces the period of the PRNG by
// discarding output)
template <typename RNG, typename RNG::result_type DIVISOR,
typename RNG::result_type LOW_ORDER_MATCH = 0,
typename rtype = typename RNG::result_type>
struct skipping_rng : public RNG {
using RNG::RNG;
using result_type = rtype;
static_assert(RNG::min() == 0, "Requires sane PRNG");
static constexpr result_type min() { return RNG::min() / DIVISOR; }
static constexpr result_type max() { return RNG::max() / DIVISOR; }
result_type operator()() {
for(;;) {
result_type rval = RNG::operator()();
if ((rval % result_type(DIVISOR)) == result_type(LOW_ORDER_MATCH)) {
return rval / result_type(DIVISOR);
}
}
}
};
// doubled_rng - group pairs of outputs into a single output
template <typename RNG, typename rtype>
struct doubled_rng : public RNG {
public:
using RNG::RNG;
using result_type = rtype;
static_assert(RNG::min() == 0, "Requires sane PRNG");
static constexpr result_type min()
{
return combine2(RNG::min(), RNG::min());
}
static constexpr result_type max()
{
return combine2(RNG::max(), RNG::max());
}
result_type operator()()
{
auto first = RNG::operator()();
auto second = RNG::operator()();
return combine2(first,second);
}
protected:
static constexpr result_type combine2(typename RNG::result_type first,
typename RNG::result_type second)
{
return (result_type(second) * (result_type(RNG::max())+1))
+ result_type(first);
}
};
#endif // RND_ADAPTERS_HPP_INCLUDED
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment