This is a follow-up question for An Updated Multi-dimensional Image Data Structure with Variadic Template Functions in C++ and rand Template Function Implementation for Image in C++. I implemented randi
template function which usage is like Matlab's randi
function in this post.
Description
X = TinyDIP::randi(imax)
returns a pseudorandom scalar integer between 1 and imax.X = TinyDIP::randi(std::make_pair(imin, imax))
returns a pseudorandom scalar integer between imin and imax.X = TinyDIP::randi(imax, n)
returns an n-by-n matrix of pseudorandom integers between 1 and imax.X = TinyDIP::randi(std::make_pair(imin, imax), n)
returns an n-by-n matrix of pseudorandom integers between imin and imax.X = TinyDIP::randi(imax, sz1, ..., szN)
returns an sz1-by-...-by-szN Image where sz1,...,szN indicates the size of each dimension. For example,TinyDIP::randi(10,3,4)
returns a 3-by-4 Image of pseudorandom integers between 1 and 10.X = TinyDIP::randi(std::make_pair(imin, imax), sz1, ..., szN)
returns an sz1-by-...-by-szN Image where sz1,...,szN indicates the size of each dimension. For example,TinyDIP::randi(std::make_pair(10,100),3,4)
returns a 3-by-4 Image of pseudorandom integers between 10 and 100.
The experimental implementation
randi
template function implementationnamespace TinyDIP { // randi template function implementation template<std::integral ElementT = int, typename Urbg, std::same_as<std::size_t>... Sizes> requires std::uniform_random_bit_generator<std::remove_reference_t<Urbg>> constexpr static auto randi(Urbg&& urbg, std::pair<ElementT, ElementT> min_and_max, Sizes... sizes) { if constexpr (sizeof...(Sizes) == 1) { return randi(std::forward<Urbg>(urbg), min_and_max, sizes..., sizes...); } else { std::vector<ElementT> image_data((... * sizes)); auto dist = std::uniform_int_distribution<ElementT>{ min_and_max.first, min_and_max.second }; std::ranges::generate(image_data, [&dist, &urbg]() { return dist(urbg); }); return Image<ElementT>{std::move(image_data), sizes...}; } } // randi template function implementation template<std::integral ElementT = int, std::same_as<std::size_t>... Size> inline auto randi(std::pair<ElementT, ElementT> min_and_max, Size... size) { return randi<ElementT>(std::mt19937{std::random_device{}()}, min_and_max, size...); } // randi template function implementation template<std::integral ElementT = int, std::same_as<std::size_t>... Size> inline auto randi(ElementT max, Size... size) { return randi<ElementT>(std::mt19937{ std::random_device{}() }, std::make_pair(1, max), size...); } // randi template function implementation template<std::integral ElementT = int, typename Urbg> requires std::uniform_random_bit_generator<std::remove_reference_t<Urbg>> constexpr auto randi(Urbg&& urbg, std::pair<ElementT, ElementT> min_and_max) -> ElementT { auto dist = std::uniform_int_distribution<ElementT>{ min_and_max.first, min_and_max.second }; return dist(urbg); } // randi template function implementation template<std::integral ElementT = int, typename Urbg> requires std::uniform_random_bit_generator<std::remove_reference_t<Urbg>> constexpr auto randi(Urbg&& urbg, ElementT max) -> ElementT { return randi(urbg, std::make_pair(static_cast<ElementT>(1), max)); } // randi template function implementation template<std::integral ElementT = int> inline auto randi(ElementT max) { return randi<ElementT>(std::mt19937{std::random_device{}()}, max); } }
The usage of randi
template function:
/* Developed by Jimmy Hu */ #include <chrono> #include "../base_types.h" #include "../basic_functions.h" #include "../image.h" #include "../image_operations.h" #include "../timer.h" void randiFunctionTest( const std::size_t sizex = 3, const std::size_t sizey = 2) { // Single Random Integer auto randi_output1 = TinyDIP::randi(10); std::cout << "Single Random Integer: " << randi_output1 << '\n'; // Single Random Integer with Specified Range auto randi_output2 = TinyDIP::randi(std::make_pair(10, 100)); std::cout << "Single Random Integer with Specified Range: " << randi_output2 << '\n'; // Square Matrix of Random Integers auto randi_output3 = TinyDIP::randi(10, sizex); std::cout << "Square Matrix of Random Integers: \n"; randi_output3.print(); // sizex-by-sizey image of pseudorandom integers auto randi_output4 = TinyDIP::randi(10, sizex, sizey); std::cout << "sizex-by-sizey image of pseudorandom integers: \n"; randi_output4.print(); // Square Matrix of Random Integers with Specified Range auto randi_output5 = TinyDIP::randi(std::make_pair(10, 100), sizex); std::cout << "Square Matrix of Random Integers with Specified Range: \n"; randi_output5.print(); // sizex-by-sizey image of pseudorandom integers with specified range auto randi_output6 = TinyDIP::randi(std::make_pair(10, 100), sizex, sizey); std::cout << "sizex-by-sizey image of pseudorandom integers with specified range: \n"; randi_output6.print(); return; } int main() { TinyDIP::Timer timer1; randiFunctionTest(); return EXIT_SUCCESS; }
The output of the test code above:
Single Random Integer: 4 Single Random Integer with Specified Range: 23 Square Matrix of Random Integers: 9 7 5 9 5 8 3 2 8 sizex-by-sizey image of pseudorandom integers: 5 8 2 5 1 9 Square Matrix of Random Integers with Specified Range: 51 45 96 25 83 93 89 29 11 sizex-by-sizey image of pseudorandom integers with specified range: 85 91 59 58 98 44 Computation finished at Sat Mar 8 20:21:52 2025 elapsed time: 0.0265732 seconds.
All suggestions are welcome.
The summary information:
Which question it is a follow-up to?
An Updated Multi-dimensional Image Data Structure with Variadic Template Functions in C++ and
What changes has been made in the code since last question?
I implemented
randi
template function in this post.Why a new review is being asked for?
Please review the implementation of
randi
template function and its tests.
std::vector
or something similar across your whole library, then you have a consistent API and have a lot fewer overloads.\$\endgroup\$