#ifndef XORSHIFT_HPP_INCLUDED #define XORSHIFT_HPP_INCLUDED 1 /* * A C++ implementation of a family of truncated XorShift* generators. * * The MIT License (MIT) * * Copyright (c) 2017-19 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. */ #include namespace xorshift_detail { template class xorshift { protected: itype state_; static constexpr unsigned int ITYPE_BITS = 8*sizeof(itype); static constexpr unsigned int RTYPE_BITS = 8*sizeof(rtype); public: using result_type = rtype; using state_type = itype; static constexpr result_type min() { return 0; } static constexpr result_type max() { return result_type(~ result_type(0)); } xorshift(itype state = itype(0xc1f651c67c62c6e0)) : state_(state) { // Nothing (else) to do. } void advance() { state_ ^= state_ >> a; state_ ^= state_ << b; state_ ^= state_ >> c; } rtype operator()() { const rtype result = state_; advance(); return result; } bool operator==(const xorshift& rhs) { return state_ == rhs.state_; } bool operator!=(const xorshift& rhs) { return !operator==(rhs); } // Not (yet) implemented: // - arbitrary jumpahead (doable, but annoying to write). // - I/O // - Seeding from a seed_seq. }; template class xorshiftstar :public base { static constexpr unsigned int ITYPE_BITS = 8*sizeof(typename base::state_type); static constexpr unsigned int RTYPE_BITS = 8*sizeof(rtype); public: using base::base; using base::advance; using result_type = rtype; static constexpr result_type min() { return 0; } static constexpr result_type max() { return result_type(~ result_type(0)); } result_type operator()() { auto result = base::state_ * multiplier; advance(); return result >> (ITYPE_BITS - RTYPE_BITS); } }; } // end of namespace ///// ---- Plain XorShift Generators ---- //// // // In the declarations below, the ...plain... versions are pure // XorShift only, which is known to fail a number of statistical // tests. Also, every output only occurs once. But they will run // faster, if you are willing to sacrifice quality for speed. // // These form the base classes for the XorShift* generators below. // None of them are intended for general-purpose use, but they may // be useful in some specialized situations. // // Each size has four variations corresponding to different parameter // sets. Each will create a distinct (and hopefully statistically // independent) sequence. // // - 128 state bits, __uint128_t output, period 2^128 - 1 // (These constants have been verified as full period.) #if __SIZEOF_INT128__ using xorshift128plain128a = xorshift_detail::xorshift<__uint128_t, __uint128_t, 24, 69, 35>; using xorshift128plain128b = xorshift_detail::xorshift<__uint128_t, __uint128_t, 26, 61, 37>; using xorshift128plain128c = xorshift_detail::xorshift<__uint128_t, __uint128_t, 45, 61, 11>; using xorshift128plain128d = xorshift_detail::xorshift<__uint128_t, __uint128_t, 41, 63, 1>; #endif // - 64 state bits, uint64_t output, period 2^64 - 1 using xorshift64plain64a = xorshift_detail::xorshift; using xorshift64plain64b = xorshift_detail::xorshift; using xorshift64plain64c = xorshift_detail::xorshift; using xorshift64plain64d = xorshift_detail::xorshift; // - 32 state bits, uint32_t output, period 2^32 - 1 using xorshift32plain32a = xorshift_detail::xorshift; using xorshift32plain32b = xorshift_detail::xorshift; using xorshift32plain32c = xorshift_detail::xorshift; using xorshift32plain32d = xorshift_detail::xorshift; // Note: {5, 21, 12} was tried as a constant, and although it was full // period, it had poor statistical results and was retired. // - 16 state bits, uint16_t output, period 2^16 - 1 using xorshift16plain16a = xorshift_detail::xorshift; using xorshift16plain16b = xorshift_detail::xorshift; using xorshift16plain16c = xorshift_detail::xorshift; using xorshift16plain16d = xorshift_detail::xorshift; // Note: {2, 5, 1} was tried as a constant, and although it was full // period, it had poor statistical results and was retired. // - 8 state bits, uint8_t output, period 2^8 - 1 using xorshift8plain8a = xorshift_detail::xorshift; using xorshift8plain8b = xorshift_detail::xorshift; using xorshift8plain8c = xorshift_detail::xorshift; using xorshift8plain8d = xorshift_detail::xorshift; ///// ---- Truncated XorShift* Generators ---- //// // // These ...star... versions are truncated XorShift* generators. They // should have excellent statistical qualities. The multiplicative // constants have been chosen to have good scores under the spectral // test for LCG multiplicative constants. // // Only the XorShift* 128/64 and XorShift* 64/32 generators are // intended for general-purpose use. The smaller variants may have // specialized uses, including exploring the behavior of XorShift* at // its limits. // // Each size has four variations corresponding to different parameter // sets. Each will create a distinct (and hopefully statistically // independent) sequence. // // - 128 state bits, uint64_t output, period 2^128 - 1 #if __SIZEOF_INT128__ using xorshift128star64a = xorshift_detail::xorshiftstar; using xorshift128star64b = xorshift_detail::xorshiftstar; using xorshift128star64c = xorshift_detail::xorshiftstar; using xorshift128star64d = xorshift_detail::xorshiftstar; #endif // - 64 state bits, uint32_t output, period 2^64 - 1 using xorshift64star32a = xorshift_detail::xorshiftstar; using xorshift64star32b = xorshift_detail::xorshiftstar; using xorshift64star32c = xorshift_detail::xorshiftstar; using xorshift64star32d = xorshift_detail::xorshiftstar; // - 32 state bits, uint16_t output, period 2^32 - 1 using xorshift32star16a = xorshift_detail::xorshiftstar; using xorshift32star16b = xorshift_detail::xorshiftstar; using xorshift32star16c = xorshift_detail::xorshiftstar; using xorshift32star16d = xorshift_detail::xorshiftstar; // - 16 state bits, uint8_t output, period 2^16 - 1 using xorshift16star8a = xorshift_detail::xorshiftstar; using xorshift16star8b = xorshift_detail::xorshiftstar; using xorshift16star8c = xorshift_detail::xorshiftstar; using xorshift16star8d = xorshift_detail::xorshiftstar; #endif // XORSHIFT_HPP_INCLUDED