rand: conform to the std generator concept

This commit is contained in:
Danny Robson 2019-02-21 20:53:07 +11:00
parent 7746463c5a
commit 8f88569f61
7 changed files with 39 additions and 75 deletions

View File

@ -3,7 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
* *
* Copyright 2015 Danny Robson <danny@nerdcruft.net> * Copyright 2015-2019 Danny Robson <danny@nerdcruft.net>
*/ */
#include "lcg.hpp" #include "lcg.hpp"
@ -50,24 +50,6 @@ lcg<T,M,A,C>::operator() (void)
} }
///////////////////////////////////////////////////////////////////////////////
template <typename T, T M, T A, T C>
typename lcg<T,M,A,C>::result_type
lcg<T,M,A,C>::min (void)
{
return std::numeric_limits<result_type>::min ();
}
//-----------------------------------------------------------------------------
template <typename T, T M, T A, T C>
typename lcg<T,M,A,C>::result_type
lcg<T,M,A,C>::max (void)
{
return std::numeric_limits<result_type>::max ();
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
template <typename T, T M, T A, T C> template <typename T, T M, T A, T C>
void void

View File

@ -3,14 +3,15 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
* *
* Copyright 2015 Danny Robson <danny@nerdcruft.net> * Copyright 2015-2019 Danny Robson <danny@nerdcruft.net>
*/ */
#ifndef __UTIL_RAND_LCG_HPP #pragma once
#define __UTIL_RAND_LCG_HPP
#include "../std.hpp"
#include <cstdint>
#include <type_traits> #include <type_traits>
#include <limits>
namespace cruft::rand { namespace cruft::rand {
@ -25,14 +26,13 @@ namespace cruft::rand {
public: public:
using result_type = T; using result_type = T;
static_assert (std::is_unsigned<T>::value, static_assert (std::is_unsigned_v<T>);
"LCG generates integer overflow which is undefined behaviour for signed types");
explicit lcg (T seed); explicit lcg (T seed);
result_type operator() (void); result_type operator() (void);
static result_type min (void); static constexpr auto min (void) { return std::numeric_limits<T>::min (); }
static result_type max (void); static constexpr auto max (void) { return std::numeric_limits<T>::max (); }
void discard (unsigned); void discard (unsigned);
@ -40,8 +40,6 @@ namespace cruft::rand {
T m_x; T m_x;
}; };
// glibc: typedef lcg<uint32_t, pow2(31), 1103515245, 12345> lcg_t; // glibc: typedef lcg<u64, pow2(31), 1103515245, 12345> lcg_t;
using lcg_t = lcg<uint64_t,0u,6364136223846793005ul, 1ul>; using lcg_t = lcg<u64,0u,6364136223846793005ul, 1ul>;
} }
#endif

View File

@ -23,7 +23,7 @@ mwc64x::mwc64x (seed_type _seed):
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
mwc64x::value_type mwc64x::result_type
mwc64x::operator() (void) mwc64x::operator() (void)
{ {
CHECK_NEZ (m_state); CHECK_NEZ (m_state);

View File

@ -3,13 +3,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
* *
* Copyright 2016 Danny Robson <danny@nerdcruft.net> * Copyright 2016-2019 Danny Robson <danny@nerdcruft.net>
*/ */
#ifndef __UTIL_RAND_MWC64X_HPP #pragma once
#define __UTIL_RAND_MWC64X_HPP
#include "../std.hpp"
#include <cstdint> #include <cstdint>
#include <limits>
namespace cruft::rand { namespace cruft::rand {
// multiply-with-carry style generator suitable for rapid seeking and // multiply-with-carry style generator suitable for rapid seeking and
@ -19,17 +22,17 @@ namespace cruft::rand {
// don't allow either half of the uint64_t to be zero. // don't allow either half of the uint64_t to be zero.
struct mwc64x { struct mwc64x {
public: public:
using value_type = uint32_t; using result_type = u32;
using seed_type = uint64_t; using seed_type = u64;
explicit mwc64x (seed_type); explicit mwc64x (seed_type);
value_type operator() (void); result_type operator() (void);
static constexpr auto max (void) noexcept { return std::numeric_limits<result_type>::max (); }
static constexpr auto min (void) noexcept { return std::numeric_limits<result_type>::min (); }
private: private:
uint64_t m_state; uint64_t m_state;
}; };
} }
#endif

View File

@ -3,7 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
* *
* Copyright 2015-2016 Danny Robson <danny@nerdcruft.net> * Copyright 2015-2019 Danny Robson <danny@nerdcruft.net>
*/ */
#include "xorshift.hpp" #include "xorshift.hpp"
@ -63,23 +63,6 @@ xorshift<T>::operator() (void)
CHECK_NEZ (m_state); CHECK_NEZ (m_state);
return m_state; return m_state;
};
///////////////////////////////////////////////////////////////////////////////
template <typename T>
typename xorshift<T>::result_type
xorshift<T>::min (void)
{
return 1u;
}
//-----------------------------------------------------------------------------
template <typename T>
typename xorshift<T>::result_type
xorshift<T>::max (void)
{
return std::numeric_limits<T>::max ();
} }

View File

@ -3,35 +3,33 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
* *
* Copyright 2015-2016 Danny Robson <danny@nerdcruft.net> * Copyright 2015-2019 Danny Robson <danny@nerdcruft.net>
*/ */
#ifndef __UTIL_RAND_XORSHIFT_HPP #pragma once
#define __UTIL_RAND_XORSHIFT_HPP
#include <limits>
namespace cruft::rand { namespace cruft::rand {
// implements a naive xorshift random generator. // implements a naive xorshift random generator.
// //
// * does not comply with the c++11 rng class requirements
// * users may not rely on identical output across executions or library // * users may not rely on identical output across executions or library
// updates. internal constants may change across releases // updates. internal constants may change across releases
template <typename T> template <typename ValueT>
struct xorshift { struct xorshift {
public: public:
using result_type = T; using result_type = ValueT;
explicit xorshift (T seed); explicit xorshift (ValueT seed);
result_type operator() (void); result_type operator() (void);
static result_type min (void); static constexpr result_type min (void) noexcept { return 1u; }
static result_type max (void); static constexpr auto max (void) noexcept { return std::numeric_limits<result_type>::max (); }
void discard (unsigned); void discard (unsigned);
private: private:
T m_state; ValueT m_state;
}; };
} }
#endif

View File

@ -34,15 +34,15 @@ test_buckets (cruft::TAP::logger &tap, Args&& ...args)
{ {
constexpr unsigned BUCKET_BITS = 8u; constexpr unsigned BUCKET_BITS = 8u;
constexpr size_t BUCKET_COUNT = 1u << BUCKET_BITS; constexpr size_t BUCKET_COUNT = 1u << BUCKET_BITS;
constexpr unsigned BUCKET_MASK = BUCKET_COUNT - 1u;
constexpr unsigned EXPECTED = 1024u; constexpr unsigned EXPECTED = 1024u;
constexpr unsigned ITERATIONS = BUCKET_COUNT * EXPECTED; constexpr unsigned ITERATIONS = BUCKET_COUNT * EXPECTED;
unsigned buckets[BUCKET_COUNT] = {};
G gen (std::forward<Args> (args)...); G gen (std::forward<Args> (args)...);
std::uniform_int_distribution<int> dist (0, BUCKET_COUNT - 1);
unsigned buckets[BUCKET_COUNT] = {};
for (unsigned i = 0; i < ITERATIONS; ++i) for (unsigned i = 0; i < ITERATIONS; ++i)
++buckets[gen () & BUCKET_MASK]; ++buckets[dist (gen)];
tap.expect ( tap.expect (
std::find_if (std::cbegin (buckets), std::find_if (std::cbegin (buckets),