From 700520d4d65244c03ef6d90044064a0b1819656c Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Wed, 27 Feb 2013 18:13:22 +0000 Subject: [PATCH] math: move rand() to its own header, ensure it only returns positive values, and add a unit test for rand. --- src/Makefile.am | 13 ++-- src/core.h | 12 ++-- src/lol/base/{base.h => all.h} | 6 +- src/lol/debug/{debug.h => all.h} | 6 +- src/lol/gpu/{gpu.h => all.h} | 6 +- src/lol/image/{image.h => all.h} | 6 +- src/lol/math/{math.h => all.h} | 7 +- src/lol/math/rand.h | 114 +++++++++++++++++++++++++++++++ src/lol/math/vector.h | 1 - src/lol/sys/{sys.h => all.h} | 6 +- src/lolcore.vcxproj | 12 ++-- src/lolcore.vcxproj.filters | 13 ++-- src/numeric.h | 71 ------------------- test/Makefile.am | 3 +- test/testsuite.vcxproj | 1 + test/unit/rand.cpp | 55 +++++++++++++++ 16 files changed, 219 insertions(+), 113 deletions(-) rename src/lol/base/{base.h => all.h} (85%) rename src/lol/debug/{debug.h => all.h} (78%) rename src/lol/gpu/{gpu.h => all.h} (85%) rename src/lol/image/{image.h => all.h} (78%) rename src/lol/math/{math.h => all.h} (81%) create mode 100644 src/lol/math/rand.h rename src/lol/sys/{sys.h => all.h} (84%) create mode 100644 test/unit/rand.cpp diff --git a/src/Makefile.am b/src/Makefile.am index f6fe843d..b5b45e51 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,26 +31,27 @@ EXTRA_DIST = easymesh/easymesh-scanner.l easymesh/easymesh-parser.y \ gpu/lolfx-scanner.l gpu/lolfx-parser.y liblolcore_headers = \ - lol/base/base.h \ + lol/base/all.h \ lol/base/log.h lol/base/array.h lol/base/types.h lol/base/array.h \ lol/base/assert.h lol/base/string.h lol/base/hash.h lol/base/map.h \ \ - lol/math/math.h \ + lol/math/all.h \ lol/math/functions.h lol/math/vector.h lol/math/half.h lol/math/real.h \ lol/math/remez.h lol/math/math.h lol/math/geometry.h lol/math/interp.h \ + lol/math/rand.h \ \ - lol/sys/sys.h \ + lol/sys/all.h \ lol/sys/init.h lol/sys/file.h lol/sys/thread.h lol/sys/atomic.h \ lol/sys/timer.h \ \ - lol/image/image.h \ + lol/image/all.h \ lol/image/color.h \ \ - lol/gpu/gpu.h \ + lol/gpu/all.h \ lol/gpu/shader.h lol/gpu/indexbuffer.h lol/gpu/vertexbuffer.h \ lol/gpu/framebuffer.h lol/gpu/texture.h lol/gpu/lolfx.h \ \ - lol/debug/debug.h \ + lol/debug/all.h \ lol/debug/line.h \ \ lol/unit.h diff --git a/src/core.h b/src/core.h index 78f1aa9a..15710824 100644 --- a/src/core.h +++ b/src/core.h @@ -91,12 +91,12 @@ static inline int isnan(float f) #endif // Base types -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include "numeric.h" diff --git a/src/lol/base/base.h b/src/lol/base/all.h similarity index 85% rename from src/lol/base/base.h rename to src/lol/base/all.h index 7b3925bf..20f42df2 100644 --- a/src/lol/base/base.h +++ b/src/lol/base/all.h @@ -8,8 +8,8 @@ // http://www.wtfpl.net/ for more details. // -#if !defined __LOL_BASE_BASE_H__ -#define __LOL_BASE_BASE_H__ +#if !defined __LOL_BASE_ALL_H__ +#define __LOL_BASE_ALL_H__ #include #include @@ -19,5 +19,5 @@ #include #include -#endif // __LOL_BASE_BASE_H__ +#endif // __LOL_BASE_ALL_H__ diff --git a/src/lol/debug/debug.h b/src/lol/debug/all.h similarity index 78% rename from src/lol/debug/debug.h rename to src/lol/debug/all.h index 5c2532f2..22d772e5 100644 --- a/src/lol/debug/debug.h +++ b/src/lol/debug/all.h @@ -8,10 +8,10 @@ // http://www.wtfpl.net/ for more details. // -#if !defined __LOL_DEBUG_DEBUG_H__ -#define __LOL_DEBUG_DEBUG_H__ +#if !defined __LOL_DEBUG_ALL_H__ +#define __LOL_DEBUG_ALL_H__ #include -#endif // __LOL_DEBUG_DEBUG_H__ +#endif // __LOL_DEBUG_ALL_H__ diff --git a/src/lol/gpu/gpu.h b/src/lol/gpu/all.h similarity index 85% rename from src/lol/gpu/gpu.h rename to src/lol/gpu/all.h index 3010d379..d134f539 100644 --- a/src/lol/gpu/gpu.h +++ b/src/lol/gpu/all.h @@ -8,8 +8,8 @@ // http://www.wtfpl.net/ for more details. // -#if !defined __LOL_GPU_GPU_H__ -#define __LOL_GPU_GPU_H__ +#if !defined __LOL_GPU_ALL_H__ +#define __LOL_GPU_ALL_H__ #include #include @@ -18,5 +18,5 @@ #include #include -#endif // __LOL_GPU_GPU_H__ +#endif // __LOL_GPU_ALL_H__ diff --git a/src/lol/image/image.h b/src/lol/image/all.h similarity index 78% rename from src/lol/image/image.h rename to src/lol/image/all.h index fb4f1e8f..d770b5fb 100644 --- a/src/lol/image/image.h +++ b/src/lol/image/all.h @@ -8,10 +8,10 @@ // http://www.wtfpl.net/ for more details. // -#if !defined __LOL_IMAGE_IMAGE_H__ -#define __LOL_IMAGE_IMAGE_H__ +#if !defined __LOL_IMAGE_ALL_H__ +#define __LOL_IMAGE_ALL_H__ #include -#endif // __LOL_IMAGE_IMAGE_H__ +#endif // __LOL_IMAGE_ALL_H__ diff --git a/src/lol/math/math.h b/src/lol/math/all.h similarity index 81% rename from src/lol/math/math.h rename to src/lol/math/all.h index c5dea454..e0c889d2 100644 --- a/src/lol/math/math.h +++ b/src/lol/math/all.h @@ -8,8 +8,8 @@ // http://www.wtfpl.net/ for more details. // -#if !defined __LOL_MATH_MATH_H__ -#define __LOL_MATH_MATH_H__ +#if !defined __LOL_MATH_ALL_H__ +#define __LOL_MATH_ALL_H__ #include #include @@ -17,6 +17,7 @@ #include #include #include +#include -#endif // __LOL_MATH_MATH_H__ +#endif // __LOL_MATH_ALL_H__ diff --git a/src/lol/math/rand.h b/src/lol/math/rand.h new file mode 100644 index 00000000..8abf7b72 --- /dev/null +++ b/src/lol/math/rand.h @@ -0,0 +1,114 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2013 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +// +// The Random number generators +// ---------------------------- +// + +#if !defined __LOL_MATH_RAND_H__ +#define __LOL_MATH_RAND_H__ + +#include +#include + +namespace lol +{ + +/* Random number generators */ +template static inline T rand(); +template static inline T rand(T a); +template static inline T rand(T a, T b); + +/* One-value random number generators */ +template static inline T rand(T a) +{ + return rand() % a; +} + +template<> +inline half rand(half a) { return a * std::rand() / RAND_MAX; } +template<> +inline float rand(float a) { return a * std::rand() / RAND_MAX; } +template<> +inline double rand(double a) { return a * std::rand() / RAND_MAX; } +template<> +inline ldouble rand(ldouble a) { return a * std::rand() / RAND_MAX; } + +/* Two-value random number generator -- no need for specialisation */ +template static inline T rand(T a, T b) +{ + return a + rand(b - a); +} + +/* Default random number generator */ +template static inline T rand() +{ + switch (sizeof(T)) + { + case 1: + return static_cast(std::rand() & 0x7f); + case 2: + { + uint16_t ret = std::rand(); + if (RAND_MAX < 0x7fff) + ret = (ret << 7) ^ std::rand(); + return static_cast(ret & 0x7fffu); + } + case 4: + { + uint32_t ret = std::rand(); + if (RAND_MAX >= 0xffff) + ret = (ret << 16) ^ std::rand(); + else + { + ret = (ret << 8) ^ std::rand(); + ret = (ret << 8) ^ std::rand(); + ret = (ret << 8) ^ std::rand(); + } + return static_cast(ret & 0x7fffffffu); + } + case 8: + { + uint64_t ret = std::rand(); + if (RAND_MAX >= 0xffff) + { + ret = (ret << 16) ^ std::rand(); + ret = (ret << 16) ^ std::rand(); + ret = (ret << 16) ^ std::rand(); + } + else + { + ret = (ret << 8) ^ std::rand(); + ret = (ret << 8) ^ std::rand(); + ret = (ret << 8) ^ std::rand(); + ret = (ret << 8) ^ std::rand(); + ret = (ret << 8) ^ std::rand(); + ret = (ret << 8) ^ std::rand(); + ret = (ret << 8) ^ std::rand(); + } + return static_cast(ret & 0x7fffffffffffffffllu); + } + default: + ASSERT(false, "rand() doesn’t support types of size %d\n", + (int)sizeof(T)); + return 0; + } +} + +template<> inline half rand() { return rand(1.f); } +template<> inline float rand() { return rand(1.f); } +template<> inline double rand() { return rand(1.0); } +template<> inline ldouble rand() { return rand(1.0); } + +} /* namespace lol */ + +#endif // __LOL_MATH_RAND_H__ + diff --git a/src/lol/math/vector.h b/src/lol/math/vector.h index d164b269..c6451ec0 100644 --- a/src/lol/math/vector.h +++ b/src/lol/math/vector.h @@ -19,7 +19,6 @@ #include #include -#include #include #include diff --git a/src/lol/sys/sys.h b/src/lol/sys/all.h similarity index 84% rename from src/lol/sys/sys.h rename to src/lol/sys/all.h index a43705ef..64c45df8 100644 --- a/src/lol/sys/sys.h +++ b/src/lol/sys/all.h @@ -8,8 +8,8 @@ // http://www.wtfpl.net/ for more details. // -#if !defined __LOL_SYS_SYS_H__ -#define __LOL_SYS_SYS_H__ +#if !defined __LOL_SYS_ALL_H__ +#define __LOL_SYS_ALL_H__ #include #include @@ -17,5 +17,5 @@ #include #include -#endif // __LOL_SYS_SYS_H__ +#endif // __LOL_SYS_ALL_H__ diff --git a/src/lolcore.vcxproj b/src/lolcore.vcxproj index 1fd0da3a..44a051ed 100644 --- a/src/lolcore.vcxproj +++ b/src/lolcore.vcxproj @@ -196,33 +196,35 @@ + - - + + - + - + - + + diff --git a/src/lolcore.vcxproj.filters b/src/lolcore.vcxproj.filters index a2b883d6..c74dfd6c 100644 --- a/src/lolcore.vcxproj.filters +++ b/src/lolcore.vcxproj.filters @@ -326,7 +326,10 @@ lol\math - + + lol\math + + lol\math @@ -521,7 +524,7 @@ easymesh - + lol\base @@ -539,10 +542,10 @@ lol\gpu - + lol\image - + lol\gpu @@ -566,7 +569,7 @@ lol\gpu - + lol\sys diff --git a/src/numeric.h b/src/numeric.h index 79edea7a..04c9259c 100644 --- a/src/numeric.h +++ b/src/numeric.h @@ -22,77 +22,6 @@ namespace lol { -/* Random number generators */ -template static inline T rand(); -template static inline T rand(T a); -template static inline T rand(T a, T b); - -/* One-value random number generators */ -template static inline T rand(T a) -{ - return rand() % a; -} - -template<> -inline half rand(half a) { return a * std::rand() / RAND_MAX; } -template<> -inline float rand(float a) { return a * std::rand() / RAND_MAX; } -template<> -inline double rand(double a) { return a * std::rand() / RAND_MAX; } -template<> -inline ldouble rand(ldouble a) { return a * std::rand() / RAND_MAX; } - -/* Two-value random number generator -- no need for specialisation */ -template static inline T rand(T a, T b) -{ - return a + rand(b - a); -} - -/* Default random number generator */ -template static inline T rand() -{ - switch (sizeof(T)) - { - case 1: - return static_cast(std::rand() & 0xff); - case 2: - if (RAND_MAX >= 0xffff) - return static_cast(std::rand()); - else - return static_cast((std::rand() << 8) ^ std::rand()); - case 4: - if (RAND_MAX >= 0xffff) - return static_cast((std::rand() << 16) ^ std::rand()); - else - return static_cast((std::rand() << 24) ^ (std::rand() << 16) - ^ (std::rand() << 8) ^ std::rand()); - case 8: - if (RAND_MAX >= 0xffff) - return static_cast(((uint64_t)std::rand() << 48) - ^ ((uint64_t)std::rand() << 32) - ^ ((uint64_t)std::rand() << 16) - ^ ((uint64_t)std::rand())); - else - return static_cast(((uint64_t)std::rand() << 56) - ^ ((uint64_t)std::rand() << 48) - ^ ((uint64_t)std::rand() << 40) - ^ ((uint64_t)std::rand() << 32) - ^ ((uint64_t)std::rand() << 24) - ^ ((uint64_t)std::rand() << 16) - ^ ((uint64_t)std::rand() << 8) - ^ ((uint64_t)std::rand())); - default: - ASSERT(false, "rand() doesn’t support types of size %d\n", - (int)sizeof(T)); - } -} - -template<> inline half rand() { return rand(1.f); } -template<> inline float rand() { return rand(1.f); } -template<> inline double rand() { return rand(1.0); } -template<> inline ldouble rand() { return rand(1.0); } - - /* Next power of two. */ template static inline T PotUp(T val) { diff --git a/test/Makefile.am b/test/Makefile.am index ce9611db..f56d499c 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -21,7 +21,8 @@ testsuite_SOURCES = testsuite.cpp \ unit/vector.cpp unit/matrix.cpp unit/half.cpp unit/trig.cpp \ unit/build.cpp unit/real.cpp unit/image.cpp unit/quat.cpp unit/cmplx.cpp \ unit/array.cpp unit/rotation.cpp unit/string.cpp unit/map.cpp \ - unit/color.cpp unit/atomic.cpp unit/interp.cpp unit/box.cpp + unit/color.cpp unit/atomic.cpp unit/interp.cpp unit/box.cpp \ + unit/rand.cpp testsuite_CPPFLAGS = $(AM_CPPFLAGS) testsuite_DEPENDENCIES = @LOL_DEPENDENCIES@ diff --git a/test/testsuite.vcxproj b/test/testsuite.vcxproj index 31d5c116..063fece9 100644 --- a/test/testsuite.vcxproj +++ b/test/testsuite.vcxproj @@ -47,6 +47,7 @@ + diff --git a/test/unit/rand.cpp b/test/unit/rand.cpp new file mode 100644 index 00000000..ccc4b7fc --- /dev/null +++ b/test/unit/rand.cpp @@ -0,0 +1,55 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2013 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" +#include "lol/unit.h" + +namespace lol +{ + +LOLUNIT_FIXTURE(RandTest) +{ + void SetUp() {} + + void TearDown() {} + + LOLUNIT_TEST(Int32Bits) + { + int const rolls = 2000; + + int bits[32]; + memset(bits, 0, sizeof(bits)); + + for (int i = 0; i < rolls; ++i) + { + uint32_t r = rand(); + for (int k = 0; k < 31; k++) + { + bits[k] += r & 1; + r >>= 1; + } + } + + for (int k = 0; k < 31; k++) + { + LOLUNIT_SET_CONTEXT(k); + LOLUNIT_ASSERT_GREATER(bits[k], rolls / 3); + LOLUNIT_ASSERT_LESS(bits[k], rolls * 2 / 3); + LOLUNIT_UNSET_CONTEXT(k); + } + } +}; + +} /* namespace lol */ +