aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Gael Guennebaud <g.gael@free.fr>2015-03-19 15:10:36 +0100
committerGravatar Gael Guennebaud <g.gael@free.fr>2015-03-19 15:10:36 +0100
commitf329d0908af35fd17bdc4dfeb87046dcaa6e6937 (patch)
tree7544488c7ffe9e2ea4ee8be1f45847bd41fc67f4
parentcc0f89eb3b07c65efb2b73890e4e7ac83525700a (diff)
Improve random number generation for integer and add unit test
-rw-r--r--Eigen/src/Core/MathFunctions.h34
-rw-r--r--test/CMakeLists.txt1
-rw-r--r--test/rand.cpp88
3 files changed, 104 insertions, 19 deletions
diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h
index 0fde5c71e..e1b233d82 100644
--- a/Eigen/src/Core/MathFunctions.h
+++ b/Eigen/src/Core/MathFunctions.h
@@ -522,28 +522,24 @@ struct meta_floor_log2<n, lower, upper, meta_floor_log2_bogus>
template<typename Scalar>
struct random_default_impl<Scalar, false, true>
{
- typedef typename NumTraits<Scalar>::NonInteger NonInteger;
-
static inline Scalar run(const Scalar& x, const Scalar& y)
{
using std::max;
- Scalar range = (max)(Scalar(0),Scalar(y-x));
- Scalar offset = 0;
- if(range<=RAND_MAX)
- {
- // rejection sampling
- int divisor = RAND_MAX/(range+1);
-
- do {
- offset = Scalar(std::rand() / divisor);
- } while (offset > range);
- }
- else
- {
- offset = std::rand() * range;
- }
-
- return x + offset;
+ using std::min;
+ typedef typename conditional<NumTraits<Scalar>::IsSigned,std::ptrdiff_t,std::size_t>::type ScalarX;
+ if(y<x)
+ return x;
+ std::size_t range = ScalarX(y)-ScalarX(x);
+ std::size_t offset = 0;
+ // rejection sampling
+ std::size_t divisor = (range+RAND_MAX-1)/(range+1);
+ std::size_t multiplier = (range+RAND_MAX-1)/std::size_t(RAND_MAX);
+
+ do {
+ offset = ( (std::size_t(std::rand()) * multiplier) / divisor );
+ } while (offset > range);
+
+ return Scalar(ScalarX(x) + offset);
}
static inline Scalar run()
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 1712b8718..734a0eb9b 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -139,6 +139,7 @@ endif(TEST_LIB)
set_property(GLOBAL PROPERTY EIGEN_CURRENT_SUBPROJECT "Official")
add_custom_target(BuildOfficial)
+ei_add_test(rand)
ei_add_test(meta)
ei_add_test(sizeof)
ei_add_test(dynalloc)
diff --git a/test/rand.cpp b/test/rand.cpp
new file mode 100644
index 000000000..4e090cbad
--- /dev/null
+++ b/test/rand.cpp
@@ -0,0 +1,88 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2015 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "main.h"
+
+template<typename Scalar> Scalar check_in_range(Scalar x, Scalar y)
+{
+ Scalar r = internal::random<Scalar>(x,y);
+ VERIFY(r>=x);
+ if(y>=x)
+ {
+ VERIFY(r<=y);
+ }
+ return r;
+}
+
+template<typename Scalar> void check_all_in_range(Scalar x, Scalar y)
+{
+ Array<int,1,Dynamic> mask(y-x+1);
+ mask.fill(0);
+ long n = (y-x+1)*32;
+ for(long k=0; k<n; ++k)
+ {
+ mask( check_in_range(x,y)-x )++;
+ }
+ VERIFY( (mask>0).all() );
+}
+
+void test_rand()
+{
+ for(int i = 0; i < g_repeat*10; i++) {
+ CALL_SUBTEST(check_in_range<float>(10,11));
+ CALL_SUBTEST(check_in_range<float>(1.24234523,1.24234523));
+ CALL_SUBTEST(check_in_range<float>(-1,1));
+ CALL_SUBTEST(check_in_range<float>(-1432.2352,-1432.2352));
+
+ CALL_SUBTEST(check_in_range<double>(10,11));
+ CALL_SUBTEST(check_in_range<double>(1.24234523,1.24234523));
+ CALL_SUBTEST(check_in_range<double>(-1,1));
+ CALL_SUBTEST(check_in_range<double>(-1432.2352,-1432.2352));
+
+
+ CALL_SUBTEST(check_in_range<int>(0,-1));
+ CALL_SUBTEST(check_in_range<short>(0,-1));
+ CALL_SUBTEST(check_in_range<long>(0,-1));
+ CALL_SUBTEST(check_in_range<int>(-673456,673456));
+ CALL_SUBTEST(check_in_range<short>(-24345,24345));
+ CALL_SUBTEST(check_in_range<long>(-6734565664234,6734565664234));
+ }
+
+ char char_offset = (std::min)(g_repeat,64);
+ CALL_SUBTEST(check_all_in_range<char>(11,11));
+ CALL_SUBTEST(check_all_in_range<char>(11,11+char_offset));
+ CALL_SUBTEST(check_all_in_range<char>(-5,5));
+ CALL_SUBTEST(check_all_in_range<char>(-11-char_offset,-11));
+ CALL_SUBTEST(check_all_in_range<char>(-126,-126+char_offset));
+ CALL_SUBTEST(check_all_in_range<char>(126-char_offset,126));
+ CALL_SUBTEST(check_all_in_range<char>(-126,126));
+
+ char short_offset = (std::min)(g_repeat,16000);
+ CALL_SUBTEST(check_all_in_range<short>(11,11));
+ CALL_SUBTEST(check_all_in_range<short>(11,11+short_offset));
+ CALL_SUBTEST(check_all_in_range<short>(-5,5));
+ CALL_SUBTEST(check_all_in_range<short>(-11-short_offset,-11));
+ CALL_SUBTEST(check_all_in_range<short>(-24345,-24345+short_offset));
+ CALL_SUBTEST(check_all_in_range<short>(24345,24345+short_offset));
+
+
+ CALL_SUBTEST(check_all_in_range<int>(11,11));
+ CALL_SUBTEST(check_all_in_range<int>(11,11+g_repeat));
+ CALL_SUBTEST(check_all_in_range<int>(-5,5));
+ CALL_SUBTEST(check_all_in_range<int>(-11-g_repeat,-11));
+ CALL_SUBTEST(check_all_in_range<int>(-673456,-673456+g_repeat));
+ CALL_SUBTEST(check_all_in_range<int>(673456,673456+g_repeat));
+
+ CALL_SUBTEST(check_all_in_range<long>(11,11));
+ CALL_SUBTEST(check_all_in_range<long>(11,11+g_repeat));
+ CALL_SUBTEST(check_all_in_range<long>(-5,5));
+ CALL_SUBTEST(check_all_in_range<long>(-11-g_repeat,-11));
+ CALL_SUBTEST(check_all_in_range<long>(-6734565664234,-6734565664234+g_repeat));
+ CALL_SUBTEST(check_all_in_range<long>(6734565664234,6734565664234+g_repeat));
+}