From 9819425ba099cb533d5eff4be56a39b4a1234d71 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Wed, 27 Feb 2013 09:25:47 +0000 Subject: [PATCH] math: replace RandF() with a more generic rand() template function that lets us draw integer random values too. --- src/easymesh/easymesh.cpp | 2 +- src/numeric.h | 72 ++++++++++++++++++++++++++++++++++----- src/scene.cpp | 2 +- src/ticker.cpp | 2 +- test/benchmark/half.cpp | 4 +-- test/benchmark/trig.cpp | 6 ++-- test/benchmark/vector.cpp | 2 +- test/physicobject.h | 12 +++---- test/unit/build.cpp | 4 +-- 9 files changed, 80 insertions(+), 26 deletions(-) diff --git a/src/easymesh/easymesh.cpp b/src/easymesh/easymesh.cpp index 9d778fda..55bacdee 100644 --- a/src/easymesh/easymesh.cpp +++ b/src/easymesh/easymesh.cpp @@ -1212,7 +1212,7 @@ void EasyMesh::RadialJitter(float r) for (i = m_cursors.Last().m1, j = 0; i < m_vert.Count(); i++, j++) { if(Welded[j] == -1) - m_vert[i].m_coord *= 1.0f + RandF(r); + m_vert[i].m_coord *= 1.0f + rand(r); else m_vert[i].m_coord = m_vert[Welded[j]].m_coord; } diff --git a/src/numeric.h b/src/numeric.h index 9c9d18af..79edea7a 100644 --- a/src/numeric.h +++ b/src/numeric.h @@ -1,7 +1,7 @@ // // Lol Engine // -// Copyright: (c) 2010-2011 Sam Hocevar +// 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 @@ -22,23 +22,77 @@ namespace lol { -/* Random float value */ -static inline float RandF() +/* 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) { - using namespace std; - return (float)std::rand() / RAND_MAX; + return rand() % a; } -static inline float RandF(float val) +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 RandF() * val; + return a + rand(b - a); } -static inline float RandF(float min, float max) +/* Default random number generator */ +template static inline T rand() { - return min + RandF() * (max - min); + 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/src/scene.cpp b/src/scene.cpp index 6a4ea7e3..0270493b 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -216,7 +216,7 @@ void Scene::Render() // XXX: rename to Blit() for (int i = 0; i < data->m_tiles.Count(); i++) { Tile tmp = data->m_tiles[i]; - int j = std::rand() % data->m_tiles.Count(); + int j = rand() % data->m_tiles.Count(); data->m_tiles[i] = data->m_tiles[j]; data->m_tiles[j] = tmp; } diff --git a/src/ticker.cpp b/src/ticker.cpp index baf3fc8e..c6a4c400 100644 --- a/src/ticker.cpp +++ b/src/ticker.cpp @@ -185,7 +185,7 @@ void *TickerData::GameThreadMain(void * /* p */) data->frame++; /* Ensure some randomness */ - (void)std::rand(); + rand(); /* If recording with fixed framerate, set deltatime to a fixed value */ if (data->recording && data->fps) diff --git a/test/benchmark/half.cpp b/test/benchmark/half.cpp index 721b5493..400a93f6 100644 --- a/test/benchmark/half.cpp +++ b/test/benchmark/half.cpp @@ -37,11 +37,11 @@ void bench_half(int mode) { case 1: for (size_t i = 0; i < HALF_TABLE_SIZE + 1; i++) - ph[i] = half::makebits(rand()); + ph[i] = half::makebits(rand()); break; case 2: for (size_t i = 0; i < HALF_TABLE_SIZE + 1; i++) - ph[i] = RandF(-2.0f, 2.0f); + ph[i] = rand(-2.0f, 2.0f); break; } diff --git a/test/benchmark/trig.cpp b/test/benchmark/trig.cpp index d2f8bf4e..e388a725 100644 --- a/test/benchmark/trig.cpp +++ b/test/benchmark/trig.cpp @@ -51,15 +51,15 @@ void bench_trig(int mode) { case 1: for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) - pf[i] = RandF(-1e5f, 1e5f); + pf[i] = rand(-1e5f, 1e5f); break; case 2: for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) - pf[i] = RandF(-M_PI, M_PI); + pf[i] = rand(-M_PI, M_PI); break; case 3: for (size_t i = 0; i < TRIG_TABLE_SIZE; i++) - pf[i] = RandF(-1e-2f, 1e-2f); + pf[i] = rand(-1e-2f, 1e-2f); break; } diff --git a/test/benchmark/vector.cpp b/test/benchmark/vector.cpp index 276fb657..84d128db 100644 --- a/test/benchmark/vector.cpp +++ b/test/benchmark/vector.cpp @@ -39,7 +39,7 @@ void bench_matrix(int mode) for (size_t i = 0; i < MATRIX_TABLE_SIZE; i++) for (int j = 0; j < 4; j++) for (int k = 0; k < 4; k++) - pm[i][j][k] = RandF(-2.0f, 2.0f); + pm[i][j][k] = rand(-2.0f, 2.0f); break; } diff --git a/test/physicobject.h b/test/physicobject.h index bbbd334a..d03efca8 100644 --- a/test/physicobject.h +++ b/test/physicobject.h @@ -157,32 +157,32 @@ public: { case 0: { - RandValue = (int)(lol::RandF() * (SphereLimit - 1)); + RandValue = rand(SphereLimit); break; } case 1: { - RandValue = SphereLimit + (int)(lol::RandF() * ((ConeLimit - SphereLimit) - 1)); + RandValue = rand(SphereLimit, ConeLimit); break; } case 2: { - RandValue = ConeLimit + (int)(lol::RandF() * ((CylLimit - ConeLimit) - 1)); + RandValue = rand(ConeLimit, CylLimit); break; } case 3: { - RandValue = CylLimit + (int)(lol::RandF() * ((CapsLimit - CylLimit) - 1)); + RandValue = rand(CylLimit, CapsLimit); break; } case 4: { - RandValue = CapsLimit + (int)(lol::RandF() * ((MeshRand.Count() - CapsLimit) - 1)); + RandValue = rand(CapsLimit, MeshRand.Count()); break; } default: { - RandValue = (int)(lol::RandF() * (MeshRand.Count() - 1)); + RandValue = rand(MeshRand.Count()); } } diff --git a/test/unit/build.cpp b/test/unit/build.cpp index b9d1f062..ffddc14a 100644 --- a/test/unit/build.cpp +++ b/test/unit/build.cpp @@ -132,7 +132,7 @@ LOLUNIT_FIXTURE(BuildTest) { double x, y; - y = x = 1.0 + RandF(0.1f, 0.2f); + y = x = 1.0 + rand(0.1f, 0.2f); y += 4503599627370496.0; /* The compiler should optimise this away */ y -= 4503599627370496.0; @@ -145,7 +145,7 @@ LOLUNIT_FIXTURE(BuildTest) { double x, y; - y = x = 1.0 + RandF(0.1f, 0.2f); + y = x = 1.0 + rand(0.1f, 0.2f); y += 4503599627370496.0; FP_USE(y); /* The compiler should not optimise this away */