Changeset 08be4a4 in mainline


Ignore:
Timestamp:
2018-07-05T21:41:22Z (6 years ago)
Author:
Dzejrou <dzejrou@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
e7a4f41
Parents:
3f3514aa
git-author:
Dzejrou <dzejrou@…> (2018-05-02 17:33:18)
git-committer:
Dzejrou <dzejrou@…> (2018-07-05 21:41:22)
Message:

cpp: used constexpr builtin wrappers to avoid reallocation of the helper array in congruential engine, fixed compile time bugs and added mersenne_twister_engine

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/cpp/include/impl/random.hpp

    r3f3514aa r08be4a4  
    8989            static constexpr result_type modulus = m;
    9090
    91             static constexpr min()
     91            static constexpr result_type min()
    9292            {
    9393                return c == 0U ? 1U : 0U;
    9494            }
    9595
    96             static constexpr max()
     96            static constexpr result_type max()
    9797            {
    9898                return m - 1U;
     
    133133            )
    134134            {
    135                 size_t k = static_cast<size_t>(aux::ceil(aux::log2(modulus_) / 32));
    136                 auto arr = new result_type[k + 3];
    137 
    138                 q.generate(arr, arr + k + 3);
     135                q.generate(arr_, arr_ + k_ + 3);
    139136
    140137                result_type s{};
    141                 for (size_t j = 0; j < k; ++j)
    142                     s += a[j + 3] * aux::pow2(32U * j);
     138                for (size_t j = 0; j < k_; ++j)
     139                    s += arr_[j + 3] * aux::pow2(32U * j);
    143140                s = s % modulus_;
    144141
     
    201198                (m == 0) ? (numeric_limits<result_type>::max() + 1) : m;
    202199
     200            /**
     201             * We use constexpr builtins to keep this array
     202             * between calls to seed(Seq&), which means we don't
     203             * have to keep allocating and deleting it.
     204             */
     205            static constexpr size_t k_ = static_cast<size_t>(aux::ceil(aux::log2(modulus_) / 32));
     206            result_type arr_[k_ + 3];
     207
    203208            void transition_()
    204209            {
     
    223228        UIntType b, size_t t, UIntType c, size_t l, UIntType f
    224229    >
    225     class mersenne_twister_engine;
     230    class mersenne_twister_engine
     231    {
     232        // TODO: fix these
     233        /* static_assert(0 < m && m <= n); */
     234        /* static_assert(2 * u < w); */
     235        /* static_assert(r <= w && u <= w && s <= w && t <= w && l <= w); */
     236        /* /1* static_assert(w <= numeric_limits<UIntType>::digits); *1/ */
     237        /* static_assert(a <= (1U << w) - 1U); */
     238        /* static_assert(b <= (1U << w) - 1U); */
     239        /* static_assert(c <= (1U << w) - 1U); */
     240        /* static_assert(d <= (1U << w) - 1U); */
     241        /* static_assert(f <= (1U << w) - 1U); */
     242
     243        public:
     244            using result_type = UIntType;
     245
     246            static constexpr size_t word_size = w;
     247            static constexpr size_t state_size = n;
     248            static constexpr size_t shift_size = m;
     249            static constexpr size_t mask_bits = r;
     250            static constexpr UIntType xor_mask = a;
     251
     252            static constexpr size_t tempering_u = u;
     253            static constexpr UIntType tempering_d = d;
     254            static constexpr size_t tempering_s = s;
     255            static constexpr UIntType tempering_b = b;
     256            static constexpr size_t tempering_t = t;
     257            static constexpr UIntType tempering_c = c;
     258            static constexpr size_t tempering_l = l;
     259
     260            static constexpr UIntType initialization_multiplier = f;
     261
     262            static constexpr result_type min()
     263            {
     264                return result_type{};
     265            }
     266
     267            static constexpr result_type max()
     268            {
     269                return static_cast<result_type>(aux::pow2(w)) - 1U;
     270            }
     271
     272            static constexpr result_type default_seed = 5489U;
     273
     274            explicit mersenne_twister_engine(result_type value = default_seed)
     275                : state_{}, i_{}
     276            {
     277                seed(value);
     278            }
     279
     280            template<class Seq>
     281            explicit mersenne_twister_engine(
     282                enable_if_t<aux::is_seed_sequence_v<Seq, result_type>, Seq&> q
     283            )
     284                : state_{}, i_{}
     285            {
     286                seed(q);
     287            }
     288
     289            void seed(result_type value = default_seed)
     290            {
     291                state_[idx_(-n)] = value % aux::pow2u(w);;
     292
     293                for (long long i = 1 - n; i <= -1; ++i)
     294                {
     295                    state_[idx_(i)] = (f * (state_[idx_(i - 1)] ^
     296                                      (state_[idx_(i - 1)] >> (w - 2))) + 1 % n) % aux::pow2u(w);
     297                }
     298            }
     299
     300            template<class Seq>
     301            void seed(
     302                enable_if_t<aux::is_seed_sequence_v<Seq, result_type>, Seq&> q
     303            )
     304            {
     305                q.generate(arr_, arr_ + n * k_);
     306
     307                for (long long i = -n; i <= -1; ++i)
     308                {
     309                    state_[idx_(i)] = result_type{};
     310                    for (long long j = 0; j < k_; ++j)
     311                        state_[idx_(i)] += arr_[k_ * (i + n) + j] * aux::pow2(32 * j);
     312                    state_[idx_(i)] %= aux::pow2(w);
     313                }
     314            }
     315
     316            result_type operator()()
     317            {
     318                return generate_();
     319            }
     320
     321            void discard(unsigned long long z)
     322            {
     323                for (unsigned long long i = 0ULL; i < z; ++i)
     324                    transition_();
     325            }
     326
     327            bool operator==(const mersenne_twister_engine& rhs) const
     328            {
     329                for (size_t i = 0; i < n; ++i)
     330                {
     331                    if (state_[i] != rhs.state_[i])
     332                        return false;
     333                }
     334
     335                return true;
     336            }
     337
     338            bool operator!=(const mersenne_twister_engine& rhs) const
     339            {
     340                return !(*this == rhs);
     341            }
     342
     343            template<class Char, class Traits>
     344            basic_ostream<Char, Traits>& operator<<(basic_ostream<Char, Traits>& os) const
     345            {
     346                auto flags = os.flags();
     347                os.flags(ios_base::dec | ios_base::left);
     348
     349                for (size_t j = n + 1; j > 1; --j)
     350                {
     351                    os << state_[idx_(i_ - j - 1)];
     352
     353                    if (j > 2)
     354                        os << os.widen(' ');
     355                }
     356
     357                os.flags(flags);
     358                return os;
     359            }
     360
     361            template<class Char, class Traits>
     362            basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is) const
     363            {
     364                auto flags = is.flags();
     365                is.flags(ios_base::dec);
     366
     367                for (size_t j = n + 1; j > 1; --j)
     368                {
     369                    if (!(is >> state_[idx_(i_ - j - 1)]))
     370                    {
     371                        is.setstate(ios::failbit);
     372                        break;
     373                    }
     374                }
     375
     376                is.flags(flags);
     377                return is;
     378            }
     379
     380        private:
     381            result_type state_[n];
     382            size_t i_;
     383
     384            static constexpr size_t k_ = static_cast<size_t>(w / 32);
     385            result_type arr_[n * k_];
     386
     387            void transition_()
     388            {
     389                auto mask = (result_type{1} << r) - 1;
     390                auto y = (state_[idx_(i_ - n)] & ~mask) | (state_[idx_(i_ + 1 - n)] & mask);
     391                auto alpha = a * (y & 1);
     392                state_[i_] = state_[idx_(i_ + m - n)] ^ (y >> 1) ^ alpha;
     393
     394                i_ = (i_ + 1) % n;
     395            }
     396
     397            result_type generate_()
     398            {
     399                auto z1 = state_[i_] ^ ((state_[i_] >> u) & d);
     400                auto z2 = z1 ^ (lshift_(z1, s) & b);
     401                auto z3 = z2 ^ (lshift_(z2, t) & c);
     402                auto z4 = z3 ^ (z3 >> l);
     403
     404                transition_();
     405
     406                return z4;
     407            }
     408
     409            size_t idx_(size_t idx) const
     410            {
     411                return idx % n;
     412            }
     413
     414            result_type lshift_(result_type val, size_t count)
     415            {
     416                return (val << count) % aux::pow2u(w);
     417            }
     418    };
    226419
    227420    /**
Note: See TracChangeset for help on using the changeset viewer.