From a3b28b4114afaf69e82c203206603a83b5f2db19 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sun, 15 Aug 2021 15:54:42 +0200 Subject: [PATCH] Move PCG RNG implementation out of header, update API --- libs/pbd/pbd/pcg_rand.h | 73 +++++++++++------------------------------ libs/pbd/pcg_rand.cc | 64 ++++++++++++++++++++++++++++++++++++ libs/pbd/wscript | 1 + 3 files changed, 85 insertions(+), 53 deletions(-) create mode 100644 libs/pbd/pcg_rand.cc diff --git a/libs/pbd/pbd/pcg_rand.h b/libs/pbd/pbd/pcg_rand.h index 6096853c4a..271ed17370 100644 --- a/libs/pbd/pbd/pcg_rand.h +++ b/libs/pbd/pbd/pcg_rand.h @@ -19,76 +19,43 @@ #ifndef _pbd_pcg_rand_ #define _pbd_pcg_rand_ -#include #include -#include - -namespace PBD { +namespace PBD +{ /** * *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org * * To be used in cases where an efficient and realtime-safe random * generator is needed. */ -class PCGRand { +class PCGRand +{ public: - PCGRand () - { - int foo = 0; - uint64_t initseq = (intptr_t)&foo; - _state = 0; - _inc = (initseq << 1) | 1; - rand_u32 (); - _state += time (NULL) ^ (intptr_t)this; - rand_u32 (); - } + PCGRand (); - /* unsigned float [0..1] */ - float rand_uf () - { - return rand_u32 () / 4294967295.f; - } + /* 32bit (0 .. 4294967295) */ + uint32_t rand_u32 (); - /* signed float [-1..+1] */ - float rand_sf () - { - return (rand_u32 () / 2147483647.5f) - 1.f; - } + /* uniform integer min <= rand < max */ + int rand (int max, int min = 0); - /* uniform integer min <= rand <= max */ - int rand (int min, int max) + /* unsigned float [0..1] */ + float rand_uf () { - int range; - if (min > max) { - range = 1 + min - max; - min = max; - } else { - range = 1 + max - min; - } - - assert (range < 4294967296); - - while (true) { - uint32_t value = rand_u32 (); - if (value < 4294967296 - 4294967296 % range) { - return min + value % range; - } - } + return rand_u32 () / 4294967295.f; } - uint32_t rand_u32 () - { - uint64_t oldstate = _state; - _state = oldstate * 6364136223846793005ULL + _inc; - uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u; - uint32_t rot = oldstate >> 59u; - return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); - } + /* signed float [-1..+1] */ + float rand_sf () + { + return (rand_u32 () / 2147483647.5f) - 1.f; + } private: - uint64_t _state; - uint64_t _inc; + uint64_t _state; + uint64_t _inc; + int _foo; }; } // namespace PBD diff --git a/libs/pbd/pcg_rand.cc b/libs/pbd/pcg_rand.cc new file mode 100644 index 0000000000..493667aa62 --- /dev/null +++ b/libs/pbd/pcg_rand.cc @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 Robin Gareus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +#include "pbd/pcg_rand.h" + +using namespace PBD; + +PCGRand::PCGRand () +{ + int foo = 0; + uint64_t initseq = (intptr_t)&foo; + _state = 0; + _inc = (initseq << 1) | 1; + rand_u32 (); + _state += time (NULL) ^ (intptr_t)this; + rand_u32 (); +} + +/* uniform integer min <= rand < max */ +int +PCGRand::rand (int max, int min /* = 0 */) +{ + assert (min < max); + assert (min > 0 || max < INT_MAX + min); // max - min overflow + assert (min < 0 || max > INT_MIN + min); // max - min underflow + + const int range = max - min; + + while (true) { + uint32_t value = rand_u32 (); + if (value < 4294967295 - 4294967295 % range) { + return min + value % range; + } + } +} + +uint32_t +PCGRand::rand_u32 () +{ + uint64_t oldstate = _state; + _state = oldstate * 6364136223846793005ULL + _inc; + uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u; + uint32_t rot = oldstate >> 59u; + return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); +} diff --git a/libs/pbd/wscript b/libs/pbd/wscript index d0393b6275..f0e45d7146 100644 --- a/libs/pbd/wscript +++ b/libs/pbd/wscript @@ -62,6 +62,7 @@ libpbd_sources = [ 'openuri.cc', 'pathexpand.cc', 'pbd.cc', + 'pcg_rand.cc', 'pool.cc', 'property_list.cc', 'pthread_utils.cc',