Program Listing for File Xoroshiro256plus.h

Return to documentation for file (necsim/Xoroshiro256plus.h)

//This file is part of necsim project which is released under MIT license.
//See file **LICENSE.txt** or visit https://opensource.org/licenses/MIT) for full license details.

#ifndef NECSIM_XOROSHIRO256PLUS_H
#define NECSIM_XOROSHIRO256PLUS_H

#include <iostream>
#include <cstdint>
#include <array>
namespace random_numbers
{
    static inline uint64_t rotl(const uint64_t &value, int bits)
    {
        return (value << bits) | (value >> (64 - bits));
    }

    static inline double intToDouble(const uint64_t &i)
    {
        union Conversion
        {
            uint64_t i;
            double d;
        };
        Conversion conversion{};
        conversion.i = UINT64_C(0x3FF) << 52 | i >> 12;
        return conversion.d - 1.0;
    }

    class SplitMix64
    {
    private:
        uint64_t x; /* The state can be seeded with any value. */

    public:

        explicit SplitMix64(uint64_t seed) : x(seed)
        { }

        uint64_t next()
        {
            uint64_t z = (x += UINT64_C(0x9E3779B97F4A7C15));
            z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9);
            z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB);
            return z ^ (z >> 31);
        }

        void shuffle()
        {
            for(unsigned int i = 0; i < 8; i++)
            {
                next();
            }
        }

        double d01()
        {
            return intToDouble(next());
        }
    };

    class Xoroshiro256plus
    {
    protected:
        std::array<uint64_t, 4> shuffle_table;
    public:

        Xoroshiro256plus() : shuffle_table()
        {

        }

        virtual ~Xoroshiro256plus() = default;

        explicit Xoroshiro256plus(uint64_t seed) : shuffle_table()
        {
            setSeed(seed);
        }

        virtual void setSeed(uint64_t seed)
        {
            SplitMix64 seed_generator(seed);
            // Shuffle the seed generator 8 times
            seed_generator.shuffle();
            for(auto &item : shuffle_table)
            {
                item = seed_generator.next();
            }
        }

        uint64_t next()
        {
            const uint64_t result_plus = shuffle_table[0] + shuffle_table[3];

            const uint64_t t = shuffle_table[1] << 17;

            shuffle_table[2] ^= shuffle_table[0];
            shuffle_table[3] ^= shuffle_table[1];
            shuffle_table[1] ^= shuffle_table[2];
            shuffle_table[0] ^= shuffle_table[3];

            shuffle_table[2] ^= t;

            shuffle_table[3] = rotl(shuffle_table[3], 45);

            return result_plus;

        }

        double d01()
        {
            return intToDouble(next());
        }

        void jump()
        {
            static const uint64_t JUMP[] = {0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, 0xa9582618e03fc9aa,
                                            0x39abdc4529b1661c};

            uint64_t s0 = 0;
            uint64_t s1 = 0;
            uint64_t s2 = 0;
            uint64_t s3 = 0;
            for(unsigned long i : JUMP)
                for(int b = 0; b < 64; b++)
                {
                    if(i & UINT64_C(1) << b)
                    {
                        s0 ^= shuffle_table[0];
                        s1 ^= shuffle_table[1];
                        s2 ^= shuffle_table[2];
                        s3 ^= shuffle_table[3];
                    }
                    next();
                }

            shuffle_table[0] = s0;
            shuffle_table[1] = s1;
            shuffle_table[2] = s2;
            shuffle_table[3] = s3;
        }

        friend std::ostream &operator<<(std::ostream &os, const Xoroshiro256plus &x)
        {
            for(const auto &item: x.shuffle_table)
            {
                os << item << ",";
            }
            return os;
        }

        friend std::istream &operator>>(std::istream &is, Xoroshiro256plus &x)
        {
            char delim;
            for(auto &i : x.shuffle_table)
            {
                is >> i >> delim;
            }
            return is;
        }
    };
}
#endif //NECSIM_XOROSHIRO256PLUS_H