#include <visp3/core/vpConfig.h>
#if defined(VISP_HAVE_CATCH2)
#include <catch_amalgamated.hpp>
#include <visp3/core/vpGaussRand.h>
#include <visp3/core/vpMath.h>
#include <visp3/core/vpTime.h>
#ifdef ENABLE_VISP_NAMESPACE
#endif
namespace
{
class vpUniRandOld
{
long a;
long m;
long q;
long r;
double normalizer;
private:
inline void draw0()
{
long k = x / q;
x = a * (x - k * q) - k * r;
if (x < 0)
x += m;
}
protected:
long x;
double draw1()
{
const long ntab = 33;
const long modulo = ntab - 2;
static long y = 0;
static long T[ntab];
long j;
if (!y) {
for (j = 0; j < ntab; j++) {
draw0();
T[j] = x;
}
y = T[ntab - 1];
}
j = y & modulo;
y = T[j];
double ans = (double)y / normalizer;
draw0();
T[j] = x;
return ans;
}
public:
VP_EXPLICIT vpUniRandOld(const long seed = 0)
: a(16807), m(2147483647), q(127773), r(2836), normalizer(2147484721.0), x((seed) ? seed : 739806647)
{ }
virtual ~vpUniRandOld() { };
double operator()() { return draw1(); }
};
}
TEST_CASE("Check Gaussian draw", "[visp_rand]")
{
std::vector<double> vec(100000);
const double sigma = 5.0, mean = -7.5;
for (size_t i = 0; i < vec.size(); i++) {
vec[i] = rng();
}
std::cout << vec.size() <<
" Gaussian draw performed in " << chrono.
getDurationMs() <<
" ms" << std::endl;
std::cout << "Calculated sigma: " << calculated_sigma << std::endl;
std::cout << "Calculated mean: " << calculated_mean << std::endl;
CHECK(calculated_sigma == Catch::Approx(sigma).epsilon(0.01));
CHECK(calculated_mean == Catch::Approx(mean).epsilon(0.01));
}
TEST_CASE("Check Gaussian draw independance", "[visp_rand]")
{
const double sigma = 5.0, mean = -7.5;
SECTION("Two simultaneous vpGaussRand instances with the same seed should produce the same results")
{
for (int i = 0; i < 10; i++) {
CHECK(rng1() == Catch::Approx(rng2()).margin(1e-6));
}
}
SECTION("Two vpGaussRand instances with the same seed should produce the same results")
{
std::vector<double> vec1, vec2;
{
for (int i = 0; i < 10; i++) {
vec1.push_back(rng());
}
}
{
for (int i = 0; i < 10; i++) {
vec2.push_back(rng());
}
}
REQUIRE(vec1.size() == vec2.size());
for (size_t i = 0; i < vec1.size(); i++) {
CHECK(vec1[i] == Catch::Approx(vec2[i]).margin(1e-6));
}
}
}
TEST_CASE("Check uniform draw", "[visp_rand]")
{
const int niters = 500000;
SECTION("vpUniRand")
{
int inside = 0;
for (int i = 0; i < niters; i++) {
double x = rng();
double y = rng();
if (sqrt(x * x + y * y) <= 1.0) {
inside++;
}
}
double pi = 4.0 * inside / niters;
double pi_error = pi - M_PI;
std::cout <<
"vpUniRand calculated pi: " << pi <<
" in " << chrono.
getDurationMs() <<
" ms" << std::endl;
std::cout << "pi error: " << pi_error << std::endl;
CHECK(pi == Catch::Approx(M_PI).margin(0.005));
}
SECTION("C++ rand()")
{
srand(0);
int inside = 0;
for (int i = 0; i < niters; i++) {
double x = static_cast<double>(rand()) / RAND_MAX;
double y = static_cast<double>(rand()) / RAND_MAX;
if (sqrt(x * x + y * y) <= 1.0) {
inside++;
}
}
double pi = 4.0 * inside / niters;
double pi_error = pi - M_PI;
std::cout <<
"C++ rand() calculated pi: " << pi <<
" in " << chrono.
getDurationMs() <<
" ms" << std::endl;
std::cout << "pi error: " << pi_error << std::endl;
CHECK(pi == Catch::Approx(M_PI).margin(0.01));
}
SECTION("Old ViSP vpUniRand implementation")
{
int inside = 0;
for (int i = 0; i < niters; i++) {
double x = rng();
double y = rng();
if (sqrt(x * x + y * y) <= 1.0) {
inside++;
}
}
double pi = 4.0 * inside / niters;
double pi_error = pi - M_PI;
std::cout <<
"Old ViSP vpUniRand implementation calculated pi: " << pi <<
" in " << chrono.
getDurationMs() <<
" ms"
<< std::endl;
std::cout << "pi error: " << pi_error << std::endl;
CHECK(pi == Catch::Approx(M_PI).margin(0.005));
}
}
TEST_CASE("Check uniform draw range", "[visp_rand]")
{
const int niters = 1000;
SECTION("Check[0.0, 1.0) range")
{
for (int i = 0; i < niters; i++) {
double r = rng();
CHECK(r >= 0.0);
CHECK(r < 1.0);
}
}
SECTION("Check[-7, 10) range")
{
const int a = -7, b = 10;
for (int i = 0; i < niters; i++) {
CHECK(r >= a);
CHECK(r < b);
}
}
SECTION("Check[-4.5f, 105.3f) range")
{
const float a = -4.5f, b = 105.3f;
for (int i = 0; i < niters; i++) {
CHECK(r >= a);
CHECK(r < b);
}
}
SECTION("Check[14.6, 56.78) range")
{
const double a = 14.6, b = 56.78;
for (int i = 0; i < niters; i++) {
CHECK(r >= a);
CHECK(r < b);
}
}
}
TEST_CASE("Check uniform draw independance", "[visp_rand]")
{
SECTION("Two simultaneous vpUniRand instances with the same seed should produce the same results")
{
{
for (int i = 0; i < 10; i++) {
}
}
{
for (int i = 0; i < 10; i++) {
CHECK(rng1.
uniform(-1.0, 1.0) == Catch::Approx(rng2.
uniform(-1.0, 1.0)).margin(1e-6));
}
}
}
SECTION("Two vpUniRand instances with the same seed should produce the same results")
{
{
std::vector<uint32_t> vec1, vec2;
{
for (int i = 0; i < 10; i++) {
vec1.push_back(rng.
next());
}
}
{
for (int i = 0; i < 10; i++) {
vec2.push_back(rng.
next());
}
}
REQUIRE(vec1.size() == vec2.size());
for (size_t i = 0; i < vec1.size(); i++) {
CHECK(vec1[i] == vec2[i]);
}
}
{
std::vector<double> vec1, vec2;
{
for (int i = 0; i < 10; i++) {
vec1.push_back(rng.
uniform(-1.0, 2.0));
}
}
{
for (int i = 0; i < 10; i++) {
vec2.push_back(rng.
uniform(-1.0, 2.0));
}
}
REQUIRE(vec1.size() == vec2.size());
for (size_t i = 0; i < vec1.size(); i++) {
CHECK(vec1[i] == Catch::Approx(vec2[i]).margin(1e-6));
}
}
}
}
int main(int argc, char *argv[])
{
Catch::Session session;
session.applyCommandLine(argc, argv);
int numFailed = session.run();
return numFailed;
}
#else
int main() { return EXIT_SUCCESS; }
#endif
void start(bool reset=true)
Class for generating random number with normal probability density.
static double getStdev(const std::vector< double > &v, bool useBesselCorrection=false)
static double getMean(const std::vector< double > &v)
Class for generating random numbers with uniform probability density.
int uniform(int a, int b)