Commit 25a95c73 authored by Christoph Conrads's avatar Christoph Conrads

Avoid accidentally using optimized AWC/SWB PRNGs

parent cac49cf7
......@@ -12,6 +12,7 @@ SOURCES := \
batch-vs-sequential.cpp \
benchmark.cpp \
conditional-vs-promotion.cpp \
prng-optimization.cpp \
rlxt-vs-std.cpp print-random.cpp \
swc24-vs-native-ints.cpp
EXECUTABLES := $(patsubst %.cpp,%.bin,$(SOURCES))
......
// Copyright 2019 Christoph Conrads
//
// This Source Code Form is subject to the terms of the Mozilla Public
// 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/.
// RANLUX Tools versus C++ Standard Library
//
// The code in this file compares the running time and throughput of the
// ranlux-tools subtract-with-borrow implementation with the C++11 standard
// library class `std::subtract_with_carry_engine`.
#include "benchmark.hpp"
#include <cassert>
#include <cstdio>
#include <cstdint>
#include <ctime>
#include <limits>
#include <random>
#include <string>
#include <type_traits>
namespace rlxt = ranlux_tools;
/*template<>
struct add_with_carry_engine<std::uint16_t, 16u, 2u, 9u>*/
struct add_with_carry_engine
{
static constexpr auto w = std::size_t{16};
static constexpr auto r = std::size_t{9};
static constexpr auto s = std::size_t{2};
static constexpr auto long_lag = r;
static constexpr auto short_lag = s;
static constexpr auto word_size = w;
using T = std::uint16_t;
using result_type = T;
static constexpr auto default_seed = std::uint32_t{387853};
static constexpr T max() { return std::numeric_limits<T>::max(); }
static constexpr T min() { return std::numeric_limits<T>::min(); }
explicit add_with_carry_engine(std::uint64_t seed=default_seed)
{
auto gen = rlxt::xoshiro128plus(seed);
for(auto& x : xs_)
x = gen();
// ensure entering a periodic sequence
discard(r);
}
T operator() ()
{
if(index_ > 0)
{
auto ret = xs_[index_];
index_ = index_ + 1u == r ? 0u : index_ + 1u;
return ret;
}
for(auto i = std::size_t{0}; i+1u < long_lag; i += 2)
{
auto x = std::uint32_t{0};
auto p_x = reinterpret_cast<char*>(xs_ + i);
auto y = std::uint32_t{0};
auto p_y = reinterpret_cast<char*>(xs_ + (i == 0u ? r-s : i-2u));
std::memcpy(&x, p_x, sizeof(x));
std::memcpy(&y, p_y, sizeof(y));
auto z = std::uint64_t{x} + y + carry_;
std::memcpy(p_x, &z, sizeof(x));
carry_ = z >> 32;
}
auto x = std::uint32_t{xs_[r-1]} + std::uint32_t{xs_[r-s-1]} + carry_;
xs_[r-1] = x;
carry_ = x >> w;
index_ = 1u;
return xs_[0];
}
void discard(unsigned long long n)
{
for(auto i = 0ull; i < n; ++i)
(*this)();
}
std::size_t index_ = 0;
T carry_ = 0;
T xs_[r] = { 0 };
};
/*template<>
struct rlxt::subtract_with_borrow_engine<std::uint8_t, 8u, 4u, 7u>*/
struct subtract_with_borrow_engine_847
{
static constexpr auto w = std::size_t{8};
static constexpr auto r = std::size_t{7};
static constexpr auto s = std::size_t{4};
static constexpr auto long_lag = r;
static constexpr auto short_lag = s;
static constexpr auto word_size = w;
using T = std::uint8_t;
using result_type = T;
static constexpr auto default_seed = std::uint32_t{387853};
static constexpr T max() { return std::numeric_limits<T>::max(); }
static constexpr T min() { return std::numeric_limits<T>::min(); }
explicit subtract_with_borrow_engine_847(std::uint64_t seed=default_seed)
{
auto gen = rlxt::xoshiro128plus(seed);
auto init = (std::uint64_t{gen()} << 32) | gen();
std::memcpy(xs_, &init, r);
auto carry = xs_[0] == 0 and xs_[1] == 0 ? 1u : 0u;
xs_[r] = carry;
// ensure entering a periodic sequence
discard(r);
}
result_type operator() ()
{
if(index_ > 0)
{
auto ret = xs_[index_];
index_ = index_ + 1u == r ? 0u : index_ + 1u;
return ret;
}
auto x = std::uint32_t{0};
auto p_x = reinterpret_cast<char*>(xs_ + 0);
auto y = std::uint32_t{0};
auto p_y = reinterpret_cast<char*>(xs_ + r - s);
static_assert(sizeof(x) == s * sizeof(result_type), "");
std::memcpy(&x, p_x, sizeof(x));
std::memcpy(&y, p_y, sizeof(y));
auto carry = std::uint32_t{xs_[r]};
auto z = std::uint64_t{y} - x - carry;
std::memcpy(p_x, &z, sizeof(x));
carry = -std::uint32_t(z >> 32);
y = std::uint32_t(z) & ((std::uint32_t{1} << 24) - 1u);
xs_[r] = 0;
std::memcpy(&x, p_x + s, sizeof(x));
z = std::uint64_t{y} - x - carry;
std::memcpy(p_x + s, &z, sizeof(x));
xs_[r] = -std::uint32_t(z >> 24);
index_ = 1u;
return xs_[0];
}
void discard(unsigned long long n)
{
for(auto i = 0ull; i < n; ++i)
(*this)();
}
std::size_t index_ = 0;
std::uint8_t xs_[r+1] = { 0 };
};
/*template<>
struct rlxt::subtract_with_borrow_engine<std::uint8_t, 8u, 5u, 8u>*/
struct subtract_with_borrow_engine_858
{
static constexpr auto w = std::size_t{8};
static constexpr auto r = std::size_t{8};
static constexpr auto s = std::size_t{5};
static constexpr auto long_lag = r;
static constexpr auto short_lag = s;
static constexpr auto word_size = w;
using T = std::uint8_t;
using result_type = T;
static constexpr auto default_seed = std::uint32_t{387853};
static constexpr T max() { return std::numeric_limits<T>::max(); }
static constexpr T min() { return std::numeric_limits<T>::min(); }
explicit subtract_with_borrow_engine_858(std::uint64_t seed=default_seed)
{
auto gen = rlxt::xoshiro128plus(seed);
auto init = (std::uint64_t{gen()} << 32) | gen();
std::memcpy(xs_, &init, r);
carry_ = init == 0 ? 1u : 0u;
// ensure entering a periodic sequence
discard(r);
}
result_type operator() ()
{
if(index_ > 0)
{
auto ret = xs_[index_];
index_ = (index_ + 1u) & 7u;
return ret;
}
// bytes 0..3
auto x = std::uint32_t{0};
auto p_x = reinterpret_cast<char*>(xs_ + 0);
auto y = std::uint32_t{0};
auto p_y = reinterpret_cast<char*>(xs_ + r - s);
std::memcpy(&x, p_x, sizeof(x));
std::memcpy(&y, p_y, sizeof(y));
auto z = std::uint64_t{y} - x - carry_;
std::memcpy(p_x, &z, sizeof(x));
carry_ = -std::uint32_t(z >> 32);
// bytes 4..7
std::memcpy(&x, p_x + 4, sizeof(x));
std::memcpy(&y, p_x + 0, sizeof(y));
y = (y << 8) | xs_[r-1];
z = std::uint64_t{y} - x - carry_;
std::memcpy(p_x + 4, &z, sizeof(x));
carry_ = -std::uint32_t(z >> 32);
index_ = 1u;
return xs_[0];
}
void discard(unsigned long long n)
{
for(auto i = 0ull; i < n; ++i)
(*this)();
}
std::size_t index_ = 0;
std::uint8_t xs_[8] = { 0 };
std::uint32_t carry_ = 0;
};
std::string get_name(const add_with_carry_engine&) { return "AWC16-special"; }
std::string get_name(const subtract_with_borrow_engine_847&) { return "SWB847";}
std::string get_name(const subtract_with_borrow_engine_858&) { return "SWB858";}
using ranlux847_base =
std::subtract_with_carry_engine<std::uint8_t, 8, 4, 7>;
using ranlux858_base =
std::subtract_with_carry_engine<std::uint8_t, 8, 5, 8>;
using ranlux16_base =
std::subtract_with_carry_engine<std::uint16_t, 16, 3, 11>;
using ranlux847_swb_base = subtract_with_borrow_engine_847;
using ranlux858_swb_base = subtract_with_borrow_engine_858;
using ranlux16_awc_base = add_with_carry_engine;
int main()
{
constexpr auto num_draws = std::uintmax_t{1000} * 1000u * 1000u;
std::printf(
"%-25s | %10s | %20s | %s\n",
"generator", "time(sec)", "throughput(byte/sec)", "dummy"
);
rlxt::run<rlxt::dummy_engine>(num_draws);
rlxt::run<ranlux847_base>(num_draws);
rlxt::run<ranlux847_swb_base>(num_draws);
rlxt::run<ranlux858_base>(num_draws);
rlxt::run<ranlux858_swb_base>(num_draws);
rlxt::run<ranlux16_base>(num_draws);
rlxt::run<ranlux16_awc_base>(num_draws);
}
......@@ -210,91 +210,6 @@ struct add_with_carry_engine
};
template<>
struct add_with_carry_engine<std::uint16_t, 16u, 2u, 9u>
{
static constexpr auto w = std::size_t{16};
static constexpr auto r = std::size_t{9};
static constexpr auto s = std::size_t{2};
static constexpr auto long_lag = r;
static constexpr auto short_lag = s;
static constexpr auto word_size = w;
using T = std::uint16_t;
using result_type = T;
static constexpr auto default_seed = std::uint32_t{387853};
static constexpr T max() { return std::numeric_limits<T>::max(); }
static constexpr T min() { return std::numeric_limits<T>::min(); }
explicit add_with_carry_engine(std::uint64_t seed=default_seed)
{
auto gen = xoshiro128plus(seed);
for(auto& x : xs_)
x = gen();
// ensure entering a periodic sequence
discard(r);
}
T operator() ()
{
if(index_ > 0)
{
auto ret = xs_[index_];
index_ = index_ + 1u == r ? 0u : index_ + 1u;
return ret;
}
for(auto i = std::size_t{0}; i+1u < long_lag; i += 2)
{
auto x = std::uint32_t{0};
auto p_x = reinterpret_cast<char*>(xs_ + i);
auto y = std::uint32_t{0};
auto p_y = reinterpret_cast<char*>(xs_ + (i == 0u ? r-s : i-2u));
std::memcpy(&x, p_x, sizeof(x));
std::memcpy(&y, p_y, sizeof(y));
auto z = std::uint64_t{x} + y + carry_;
std::memcpy(p_x, &z, sizeof(x));
carry_ = z >> 32;
}
auto x = std::uint32_t{xs_[r-1]} + std::uint32_t{xs_[r-s-1]} + carry_;
xs_[r-1] = x;
carry_ = x >> w;
index_ = 1u;
return xs_[0];
}
void discard(unsigned long long n)
{
for(auto i = 0ull; i < n; ++i)
(*this)();
}
std::size_t index_ = 0;
T carry_ = 0;
T xs_[r] = { 0 };
};
template<typename T, std::size_t w, std::size_t p, std::size_t q>
struct subtract_with_borrow_engine
......@@ -376,189 +291,6 @@ struct subtract_with_borrow_engine
};
template<>
struct subtract_with_borrow_engine<std::uint8_t, 8u, 4u, 7u>
{
static constexpr auto w = std::size_t{8};
static constexpr auto r = std::size_t{7};
static constexpr auto s = std::size_t{4};
static constexpr auto long_lag = r;
static constexpr auto short_lag = s;
static constexpr auto word_size = w;
using T = std::uint8_t;
using result_type = T;
static constexpr auto default_seed = std::uint32_t{387853};
static constexpr T max() { return std::numeric_limits<T>::max(); }
static constexpr T min() { return std::numeric_limits<T>::min(); }
explicit subtract_with_borrow_engine(std::uint64_t seed=default_seed)
{
auto gen = xoshiro128plus(seed);
auto init = (std::uint64_t{gen()} << 32) | gen();
std::memcpy(xs_, &init, r);
auto carry = xs_[0] == 0 and xs_[1] == 0 ? 1u : 0u;
xs_[r] = carry;
// ensure entering a periodic sequence
discard(r);
}
result_type operator() ()
{
if(index_ > 0)
{
auto ret = xs_[index_];
index_ = index_ + 1u == r ? 0u : index_ + 1u;
return ret;
}
auto x = std::uint32_t{0};
auto p_x = reinterpret_cast<char*>(xs_ + 0);
auto y = std::uint32_t{0};
auto p_y = reinterpret_cast<char*>(xs_ + r - s);
static_assert(sizeof(x) == s * sizeof(result_type), "");
std::memcpy(&x, p_x, sizeof(x));
std::memcpy(&y, p_y, sizeof(y));
auto carry = std::uint32_t{xs_[r]};
auto z = std::uint64_t{y} - x - carry;
std::memcpy(p_x, &z, sizeof(x));
carry = -std::uint32_t(z >> 32);
y = std::uint32_t(z) & ((std::uint32_t{1} << 24) - 1u);
xs_[r] = 0;
std::memcpy(&x, p_x + s, sizeof(x));
z = std::uint64_t{y} - x - carry;
std::memcpy(p_x + s, &z, sizeof(x));
xs_[r] = -std::uint32_t(z >> 24);
index_ = 1u;
return xs_[0];
}
void discard(unsigned long long n)
{
for(auto i = 0ull; i < n; ++i)
(*this)();
}
std::size_t index_ = 0;
std::uint8_t xs_[r+1] = { 0 };
};
template<>
struct subtract_with_borrow_engine<std::uint8_t, 8u, 5u, 8u>
{
static constexpr auto w = std::size_t{8};
static constexpr auto r = std::size_t{8};
static constexpr auto s = std::size_t{5};
static constexpr auto long_lag = r;
static constexpr auto short_lag = s;
static constexpr auto word_size = w;
using T = std::uint8_t;
using result_type = T;
static constexpr auto default_seed = std::uint32_t{387853};
static constexpr T max() { return std::numeric_limits<T>::max(); }
static constexpr T min() { return std::numeric_limits<T>::min(); }
explicit subtract_with_borrow_engine(std::uint64_t seed=default_seed)
{
auto gen = xoshiro128plus(seed);
auto init = (std::uint64_t{gen()} << 32) | gen();
std::memcpy(xs_, &init, r);
carry_ = init == 0 ? 1u : 0u;
// ensure entering a periodic sequence
discard(r);
}
result_type operator() ()
{
if(index_ > 0)
{
auto ret = xs_[index_];
index_ = (index_ + 1u) & 7u;
return ret;
}
// bytes 0..3
auto x = std::uint32_t{0};
auto p_x = reinterpret_cast<char*>(xs_ + 0);
auto y = std::uint32_t{0};
auto p_y = reinterpret_cast<char*>(xs_ + r - s);
std::memcpy(&x, p_x, sizeof(x));
std::memcpy(&y, p_y, sizeof(y));
auto z = std::uint64_t{y} - x - carry_;
std::memcpy(p_x, &z, sizeof(x));
carry_ = -std::uint32_t(z >> 32);
// bytes 4..7
std::memcpy(&x, p_x + 4, sizeof(x));
std::memcpy(&y, p_x + 0, sizeof(y));
y = (y << 8) | xs_[r-1];
z = std::uint64_t{y} - x - carry_;
std::memcpy(p_x + 4, &z, sizeof(x));
carry_ = -std::uint32_t(z >> 32);
index_ = 1u;
return xs_[0];
}
void discard(unsigned long long n)
{
for(auto i = 0ull; i < n; ++i)
(*this)();
}
std::size_t index_ = 0;
std::uint8_t xs_[8] = { 0 };
std::uint32_t carry_ = 0;
};
using ranlux8_base = subtract_with_borrow_engine<std::uint8_t, 8u, 5u, 8u>;
using ranlux8 = std::discard_block_engine<ranlux8_base, 67u, 8u>;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment