Commit 601c9ef8 authored by Christoph Conrads's avatar Christoph Conrads

Implement alternative to __int128-based code

64-bit PRNG have the highest throughput even on ARMv7-A with its 32-bit
word size.
parent 25a95c73
......@@ -164,21 +164,15 @@ int main()
run<rlxt::ranlux8_base>(num_draws);
run<rlxt::ranlux16_base>(num_draws);
run<rlxt::ranlux32_base>(num_draws);
#if RANLUX_TOOLS_HAS_INT128
run<rlxt::ranlux64_base>(num_draws);
#endif
run<rlxt::fast_ranlux8>(num_draws);
run<rlxt::fast_ranlux16>(num_draws);
run<rlxt::fast_ranlux32>(num_draws);
#if RANLUX_TOOLS_HAS_INT128
run<rlxt::fast_ranlux64>(num_draws);
#endif
run<rlxt::ranlux8>(num_draws);
run<rlxt::ranlux16>(num_draws);
run<rlxt::ranlux32>(num_draws);
#if RANLUX_TOOLS_HAS_INT128
run<rlxt::ranlux64>(num_draws);
#endif
run<std::ranlux24>(num_draws);
run<std::ranlux48>(num_draws);
run<std::mt19937>(num_draws);
......
......@@ -85,9 +85,7 @@ int main(int argc, const char** argv)
COMPARE_AND_CALL(ranlux32_base)
COMPARE_AND_CALL(fast_ranlux32)
COMPARE_AND_CALL(ranlux32)
#if RANLUX_TOOLS_HAS_INT128
COMPARE_AND_CALL(ranlux64_base)
COMPARE_AND_CALL(fast_ranlux64)
COMPARE_AND_CALL(ranlux64)
#endif
}
......@@ -30,6 +30,26 @@ namespace impl_random_number_engine
return (x << k) | (x >> (32 - k));
}
// minimize the amount of code needed to switch between AWC/SWB
// implementations by providing a dummy integer to be used whenever int128
// is unavailable.
// this type allows us to use a simple if statement to switch the
// implementation and the optimizer should take care of the rest.
struct dummy_integer_t
{
dummy_integer_t(std::uintmax_t) {}
operator std::uintmax_t() const { return 0; }
};
dummy_integer_t operator+ (dummy_integer_t, dummy_integer_t) { return 0; }
dummy_integer_t operator+ (dummy_integer_t, std::uintmax_t) { return 0; }
dummy_integer_t operator- (dummy_integer_t, dummy_integer_t) { return 0; }
dummy_integer_t operator- (dummy_integer_t, std::uintmax_t) { return 0; }
dummy_integer_t operator>> (dummy_integer_t, std::size_t) { return 0;}
#if RANLUX_TOOLS_HAS_INT128
#if __GNUC__
#pragma GCC diagnostic push
......@@ -40,7 +60,7 @@ namespace impl_random_number_engine
w == 8u, std::uint16_t, typename std::conditional<
w == 16u, std::uint32_t, typename std::conditional<
w == 32u, std::uint64_t, typename std::conditional<
w == 64u, unsigned __int128, void
w == 64u, unsigned __int128, dummy_integer_t
>::type>::type>::type>::type;
#if __GNUC__
#pragma GCC diagnostic pop
......@@ -50,7 +70,7 @@ namespace impl_random_number_engine
using big_integer_t = typename std::conditional<
w == 8u, std::uint16_t, typename std::conditional<
w == 16u, std::uint32_t, typename std::conditional<
w == 32u, std::uint64_t, void
w == 32u, std::uint64_t, dummy_integer_t
>::type>::type>::type;
#endif
......@@ -180,19 +200,33 @@ struct add_with_carry_engine
T operator() ()
{
using BigInt = impl_random_number_engine::big_integer_t<w>;
using DummyInt = impl_random_number_engine::dummy_integer_t;
auto i = index_;
auto j = index_ >= s ? index_ - s : index_ + r - s;
assert(carry_ == 0 or carry_ == 1);
auto x = BigInt{xs_[i]} + xs_[j] + carry_;
if(std::is_same<BigInt, DummyInt>::value)
{
auto x = xs_[i];
auto y = T(x + xs_[j]);
auto z = T(y + carry_);
xs_[i] = z;
carry_ = y < x or z < y ? 1u : 0u;
}
else
{
auto x = BigInt{xs_[i]} + xs_[j] + carry_;
xs_[i] = x;
carry_ = x >> w;
}
xs_[i] = x;
carry_ = x >> w;
index_ = index_ + 1u == r ? 0u : index_ + 1u;
return x;
return xs_[i];
}
......@@ -230,7 +264,7 @@ struct subtract_with_borrow_engine
// prototype implementation
static_assert(w == std::numeric_limits<T>::digits, "");
static_assert(w == 16u or w == 32u or w == 64u, "");
static_assert(w == 8u or w == 16u or w == 32u or w == 64u, "");
using result_type = T;
......@@ -259,22 +293,37 @@ struct subtract_with_borrow_engine
T operator() ()
{
using BigInt = impl_random_number_engine::big_integer_t<w>;
using DummyInt = impl_random_number_engine::dummy_integer_t;
auto i = index_;
auto j = index_ >= s ? index_ - s : index_ + r - s;
auto u = xs_[i];
auto v = xs_[j];
assert(carry_ == 0 or carry_ == 1);
auto x = p > q ? BigInt{u} - v - carry_ : BigInt{v} - u - carry_;
auto c = -T(x >> w);
if(std::is_same<BigInt, DummyInt>::value)
{
auto x = p > q ? xs_[i] : xs_[j];
auto y = p > q ? T(x - xs_[j]) : T(x - xs_[i]);
auto z = T(y - carry_);
xs_[i] = z;
carry_ = y > x or z > y ? 1u : 0u;
}
else
{
auto x = p > q
? BigInt{xs_[i]} - xs_[j] - carry_
: BigInt{xs_[j]} - xs_[i] - carry_
;
auto c = -T(x >> w);
xs_[i] = x;
carry_ = c;
}
xs_[i] = x;
carry_ = c;
index_ = index_ + 1u == r ? 0u : index_ + 1u;
return x;
return xs_[i];
}
......@@ -304,11 +353,9 @@ using ranlux32_base = add_with_carry_engine<std::uint32_t, 32u, 3u, 16u>;
using ranlux32 = std::discard_block_engine<ranlux32_base, 277u, 16u>;
using fast_ranlux32 = std::discard_block_engine<ranlux32_base, 71u, 16u>;
#if RANLUX_TOOLS_HAS_INT128
using ranlux64_base = subtract_with_borrow_engine<std::uint64_t, 64u, 62u, 3u>;
using ranlux64 = std::discard_block_engine<ranlux64_base, 1303u, 62u>;
using fast_ranlux64 = std::discard_block_engine<ranlux64_base, 331u, 62u>;
#endif
}
......
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