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
randitemplate 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
randitemplate function in this post.Why a new review is being asked for?
Please review the implementation of
randitemplate function and its tests.
std::vectoror something similar across your whole library, then you have a consistent API and have a lot fewer overloads. \$\endgroup\$