psemek/libs/random/include/psemek/random/uniform.hpp

66 lines
1.5 KiB
C++

#pragma once
#include <psemek/random/uniform_int.hpp>
#include <psemek/random/uniform_real.hpp>
#include <psemek/geom/constants.hpp>
#include <psemek/geom/box.hpp>
#include <type_traits>
#include <stdexcept>
namespace psemek::random
{
template <typename T>
using uniform_distribution = std::conditional_t<std::is_floating_point_v<T>, uniform_real_distribution<T>, uniform_int_distribution<T>>;
template <typename T, typename RNG>
T uniform(RNG && rng, geom::interval<T> const & range)
{
return uniform_distribution<T>{range}(rng);
}
template <typename T, typename RNG>
T uniform(RNG && rng, T min, T max)
{
return uniform<T>(rng, {min, max});
}
template <typename T, typename RNG>
T uniform(RNG && rng)
{
if constexpr (std::is_same_v<T, bool>)
{
return uniform<char>(rng, 0, 1) == 1;
}
else
{
return uniform<T>(rng, T{0}, T{1});
}
}
template <typename T, std::size_t N, typename RNG>
geom::point<T, N> uniform(RNG && rng, geom::box<T, N> const & box)
{
geom::point<T, N> result;
for (std::size_t i = 0; i < N; ++i)
result[i] = uniform<T>(rng, box[i]);
return result;
}
template <typename T, typename RNG>
T uniform_angle(RNG && rng)
{
return uniform(rng, T{0}, T{2 * geom::pi});
}
template <typename RNG, typename Container>
auto & uniform_from(RNG && rng, Container & container)
{
if (container.empty())
throw std::runtime_error("cannot sample from empty container");
return container[uniform<std::size_t>(rng, 0, container.size() - 1)];
}
}