-/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----\r
-\r
- Copyright (c) 2014-2015 Datalight, Inc.\r
- All Rights Reserved Worldwide.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU General Public License as published by\r
- the Free Software Foundation; use version 2 of the License.\r
-\r
- This program is distributed in the hope that it will be useful,\r
- but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty\r
- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
-\r
- You should have received a copy of the GNU General Public License along\r
- with this program; if not, write to the Free Software Foundation, Inc.,\r
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
-*/\r
-/* Businesses and individuals that for commercial or other reasons cannot\r
- comply with the terms of the GPLv2 license may obtain a commercial license\r
- before incorporating Reliance Edge into proprietary software for\r
- distribution in any form. Visit http://www.datalight.com/reliance-edge for\r
- more information.\r
-*/\r
-/** @file\r
- @brief Implements a random number generator.\r
-*/\r
-#include <redfs.h>\r
-#include <redtestutils.h>\r
-\r
-\r
-/* This is the global seed used by the random number generator when the caller\r
- has not provided a seed to either the RedRand32() or RedRand64() functions.\r
-*/\r
-static uint64_t ullGlobalRandomNumberSeed;\r
-\r
-/* Whether the above seed has been initialized.\r
-*/\r
-static bool fGlobalSeedInited;\r
-\r
-\r
-/** @brief Set the global seed used by the random number generator.\r
-\r
- The global seed gets used when RedRand64() or RedRand32() are called with\r
- a NULL seed argument.\r
-\r
- @param ullSeed The value to use as the global RNG seed.\r
-*/\r
-void RedRandSeed(\r
- uint64_t ullSeed)\r
-{\r
- ullGlobalRandomNumberSeed = ullSeed;\r
- fGlobalSeedInited = true;\r
-}\r
-\r
-\r
-/** @brief Generate a 64-bit pseudo-random number.\r
-\r
- The period of this random number generator is 2^64 (1.8 x 1019). These\r
- parameters are the same as the default one-stream SPRNG lcg64 generator and\r
- it satisfies the requirements for a maximal period.\r
-\r
- The tempering value is used and an AND mask and is specifically selected to\r
- favor the distribution of lower bits.\r
-\r
- @param pullSeed A pointer to the seed to use. Set this value to NULL to\r
- use the internal global seed value.\r
-\r
- @return A pseudo-random number in the range [0, UINT64_MAX].\r
-*/\r
-uint64_t RedRand64(\r
- uint64_t *pullSeed)\r
-{\r
- const uint64_t ullA = UINT64_SUFFIX(2862933555777941757);\r
- const uint64_t ullC = UINT64_SUFFIX(3037000493);\r
- const uint64_t ullT = UINT64_SUFFIX(4921441182957829599);\r
- uint64_t ullN;\r
- uint64_t *pullSeedPtr;\r
- uint64_t ullLocalSeed;\r
-\r
- if(pullSeed != NULL)\r
- {\r
- ullLocalSeed = *pullSeed;\r
- pullSeedPtr = pullSeed;\r
- }\r
- else\r
- {\r
- if(!fGlobalSeedInited)\r
- {\r
- /* Unfortunately, the Reliance Edge OS services don't give us much\r
- to work with to initialize the global seed. There is no entropy\r
- abstraction, no tick count abstraction, and the timestamp\r
- abstraction uses an opaque type which is not guaranteed to be an\r
- integer. The best we can do is use the RTC.\r
-\r
- Tests using the RNG should be supplying a seed anyway, for\r
- reproducibility.\r
- */\r
- RedRandSeed((uint64_t)RedOsClockGetTime());\r
- }\r
-\r
- ullLocalSeed = ullGlobalRandomNumberSeed;\r
- pullSeedPtr = &ullGlobalRandomNumberSeed;\r
- }\r
-\r
- ullN = (ullLocalSeed * ullA) + ullC;\r
-\r
- *pullSeedPtr = ullN;\r
-\r
- /* The linear congruential generator used above produces good psuedo-random\r
- 64-bit number sequences, however, as with any LCG, the period of the\r
- lower order bits is much shorter resulting in alternately odd/even pairs\r
- in bit zero.\r
-\r
- The result of the LGC above is tempered below with a series of XOR and\r
- shift operations to produce a more acceptable equidistribution of bits\r
- throughout the 64-bit range.\r
- */\r
- ullN ^= (ullN >> 21U) & ullT;\r
- ullN ^= (ullN >> 43U) & ullT;\r
- ullN ^= (ullN << 23U) & ~ullT;\r
- ullN ^= (ullN << 31U) & ~ullT;\r
-\r
- return ullN;\r
-}\r
-\r
-\r
-/** @brief Generate a 32-bit pseudo-random number.\r
-\r
- @note The 32-bit random number generator internally uses the 64-bit random\r
- number generator, returning the low 32-bits of the pseudo-random\r
- 64-bit value.\r
-\r
- @param pulSeed A pointer to the seed to use. Set this value to NULL to use\r
- the internal global seed value.\r
-\r
- @return A pseudo-random number in the range [0, UINT32_MAX].\r
-*/\r
-uint32_t RedRand32(\r
- uint32_t *pulSeed)\r
-{\r
- uint64_t ullN;\r
-\r
- if(pulSeed != NULL)\r
- {\r
- uint64_t ullLocalSeed;\r
-\r
- ullLocalSeed = *pulSeed;\r
- ullN = RedRand64(&ullLocalSeed);\r
- *pulSeed = (uint32_t)ullLocalSeed;\r
- }\r
- else\r
- {\r
- ullN = RedRand64(NULL);\r
- }\r
-\r
- return (uint32_t)ullN;\r
-}\r
-\r
+/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
+
+ Copyright (c) 2014-2015 Datalight, Inc.
+ All Rights Reserved Worldwide.
+
+ 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; use version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but "AS-IS," 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.
+*/
+/* Businesses and individuals that for commercial or other reasons cannot
+ comply with the terms of the GPLv2 license may obtain a commercial license
+ before incorporating Reliance Edge into proprietary software for
+ distribution in any form. Visit http://www.datalight.com/reliance-edge for
+ more information.
+*/
+/** @file
+ @brief Implements a random number generator.
+*/
+#include <redfs.h>
+#include <redtestutils.h>
+
+
+/* This is the global seed used by the random number generator when the caller
+ has not provided a seed to either the RedRand32() or RedRand64() functions.
+*/
+static uint64_t ullGlobalRandomNumberSeed;
+
+/* Whether the above seed has been initialized.
+*/
+static bool fGlobalSeedInited;
+
+
+/** @brief Set the global seed used by the random number generator.
+
+ The global seed gets used when RedRand64() or RedRand32() are called with
+ a NULL seed argument.
+
+ @param ullSeed The value to use as the global RNG seed.
+*/
+void RedRandSeed(
+ uint64_t ullSeed)
+{
+ ullGlobalRandomNumberSeed = ullSeed;
+ fGlobalSeedInited = true;
+}
+
+
+/** @brief Generate a 64-bit pseudo-random number.
+
+ The period of this random number generator is 2^64 (1.8 x 1019). These
+ parameters are the same as the default one-stream SPRNG lcg64 generator and
+ it satisfies the requirements for a maximal period.
+
+ The tempering value is used and an AND mask and is specifically selected to
+ favor the distribution of lower bits.
+
+ @param pullSeed A pointer to the seed to use. Set this value to NULL to
+ use the internal global seed value.
+
+ @return A pseudo-random number in the range [0, UINT64_MAX].
+*/
+uint64_t RedRand64(
+ uint64_t *pullSeed)
+{
+ const uint64_t ullA = UINT64_SUFFIX(2862933555777941757);
+ const uint64_t ullC = UINT64_SUFFIX(3037000493);
+ const uint64_t ullT = UINT64_SUFFIX(4921441182957829599);
+ uint64_t ullN;
+ uint64_t *pullSeedPtr;
+ uint64_t ullLocalSeed;
+
+ if(pullSeed != NULL)
+ {
+ ullLocalSeed = *pullSeed;
+ pullSeedPtr = pullSeed;
+ }
+ else
+ {
+ if(!fGlobalSeedInited)
+ {
+ /* Unfortunately, the Reliance Edge OS services don't give us much
+ to work with to initialize the global seed. There is no entropy
+ abstraction, no tick count abstraction, and the timestamp
+ abstraction uses an opaque type which is not guaranteed to be an
+ integer. The best we can do is use the RTC.
+
+ Tests using the RNG should be supplying a seed anyway, for
+ reproducibility.
+ */
+ RedRandSeed((uint64_t)RedOsClockGetTime());
+ }
+
+ ullLocalSeed = ullGlobalRandomNumberSeed;
+ pullSeedPtr = &ullGlobalRandomNumberSeed;
+ }
+
+ ullN = (ullLocalSeed * ullA) + ullC;
+
+ *pullSeedPtr = ullN;
+
+ /* The linear congruential generator used above produces good psuedo-random
+ 64-bit number sequences, however, as with any LCG, the period of the
+ lower order bits is much shorter resulting in alternately odd/even pairs
+ in bit zero.
+
+ The result of the LGC above is tempered below with a series of XOR and
+ shift operations to produce a more acceptable equidistribution of bits
+ throughout the 64-bit range.
+ */
+ ullN ^= (ullN >> 21U) & ullT;
+ ullN ^= (ullN >> 43U) & ullT;
+ ullN ^= (ullN << 23U) & ~ullT;
+ ullN ^= (ullN << 31U) & ~ullT;
+
+ return ullN;
+}
+
+
+/** @brief Generate a 32-bit pseudo-random number.
+
+ @note The 32-bit random number generator internally uses the 64-bit random
+ number generator, returning the low 32-bits of the pseudo-random
+ 64-bit value.
+
+ @param pulSeed A pointer to the seed to use. Set this value to NULL to use
+ the internal global seed value.
+
+ @return A pseudo-random number in the range [0, UINT32_MAX].
+*/
+uint32_t RedRand32(
+ uint32_t *pulSeed)
+{
+ uint64_t ullN;
+
+ if(pulSeed != NULL)
+ {
+ uint64_t ullLocalSeed;
+
+ ullLocalSeed = *pulSeed;
+ ullN = RedRand64(&ullLocalSeed);
+ *pulSeed = (uint32_t)ullLocalSeed;
+ }
+ else
+ {
+ ullN = RedRand64(NULL);
+ }
+
+ return (uint32_t)ullN;
+}
+