diff options
author | Gael Guennebaud <g.gael@free.fr> | 2015-03-19 15:10:36 +0100 |
---|---|---|
committer | Gael Guennebaud <g.gael@free.fr> | 2015-03-19 15:10:36 +0100 |
commit | f329d0908af35fd17bdc4dfeb87046dcaa6e6937 (patch) | |
tree | 7544488c7ffe9e2ea4ee8be1f45847bd41fc67f4 | |
parent | cc0f89eb3b07c65efb2b73890e4e7ac83525700a (diff) |
Improve random number generation for integer and add unit test
-rw-r--r-- | Eigen/src/Core/MathFunctions.h | 34 | ||||
-rw-r--r-- | test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | test/rand.cpp | 88 |
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)); +} |