0/**********************************************************************************************
1*
2* rprand v1.0 - A simple and easy-to-use pseudo-random numbers generator (PRNG)
3*
4* FEATURES:
5* - Pseudo-random values generation, 32 bits: [0..4294967295]
6* - Sequence generation avoiding duplicate values
7* - Using standard and proven prng algorithm (Xoshiro128**)
8* - State initialized with a separate generator (SplitMix64)
9*
10* LIMITATIONS:
11* - No negative numbers, up to the user to manage them
12*
13* POSSIBLE IMPROVEMENTS:
14* - Support 64 bits generation
15*
16* ADDITIONAL NOTES:
17* This library implements two pseudo-random number generation algorithms:
18*
19* - Xoshiro128** : https://prng.di.unimi.it/xoshiro128starstar.c
20* - SplitMix64 : https://prng.di.unimi.it/splitmix64.c
21*
22* SplitMix64 is used to initialize the Xoshiro128** state, from a provided seed
23*
24* It's suggested to use SplitMix64 to initialize the state of the generators starting from
25* a 64-bit seed, as research has shown that initialization must be performed with a generator
26* radically different in nature from the one initialized to avoid correlation on similar seeds.
27*
28* CONFIGURATION:
29* #define RPRAND_IMPLEMENTATION
30* Generates the implementation of the library into the included file.
31* If not defined, the library is in header only mode and can be included in other headers
32* or source files without problems. But only ONE file should hold the implementation.
33*
34* DEPENDENCIES: none
35*
36* VERSIONS HISTORY:
37* 1.0 (01-Jun-2023) First version
38*
39*
40* LICENSE: zlib/libpng
41*
42* Copyright (c) 2023 Ramon Santamaria (@raysan5)
43*
44* This software is provided "as-is", without any express or implied warranty. In no event
45* will the authors be held liable for any damages arising from the use of this software.
46*
47* Permission is granted to anyone to use this software for any purpose, including commercial
48* applications, and to alter it and redistribute it freely, subject to the following restrictions:
49*
50* 1. The origin of this software must not be misrepresented; you must not claim that you
51* wrote the original software. If you use this software in a product, an acknowledgment
52* in the product documentation would be appreciated but is not required.
53*
54* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
55* as being the original software.
56*
57* 3. This notice may not be removed or altered from any source distribution.
58*
59**********************************************************************************************/
61#ifndef RPRAND_H
62#define RPRAND_H
64#define RPRAND_VERSION "1.0"
66// Function specifiers in case library is build/used as a shared library (Windows)
67// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
68#if defined(_WIN32)
69 #if defined(BUILD_LIBTYPE_SHARED)
70 #define RPRAND __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
71 #elif defined(USE_LIBTYPE_SHARED)
72 #define RPRAND __declspec(dllimport) // We are using the library as a Win32 shared library (.dll)
73 #endif
74#endif
76// Function specifiers definition
77#ifndef RPRANDAPI
78 #define RPRANDAPI // Functions defined as 'extern' by default (implicit specifiers)
79#endif
81//----------------------------------------------------------------------------------
82// Defines and Macros
83//----------------------------------------------------------------------------------
84// Allow custom memory allocators
85#ifndef RPRAND_CALLOC
86 #define RPRAND_CALLOC(ptr,sz) calloc(ptr,sz)
87#endif
88#ifndef RPRAND_FREE
89 #define RPRAND_FREE(ptr) free(ptr)
90#endif
92// Simple log system to avoid log calls if required
93// NOTE: Avoiding those calls, also avoids const strings memory usage
94#define RPRAND_SHOW_LOG_INFO
95#if defined(RPNG_SHOW_LOG_INFO)
96 #define RPRAND_LOG(...) printf(__VA_ARGS__)
97#else
98 #define RPRAND_LOG(...)
99#endif
101//----------------------------------------------------------------------------------
102// Types and Structures Definition
103//----------------------------------------------------------------------------------
104//...
106#ifdef __cplusplus
107extern "C" { // Prevents name mangling of functions
108#endif
110//----------------------------------------------------------------------------------
111// Global Variables Definition
112//----------------------------------------------------------------------------------
113//...
115//----------------------------------------------------------------------------------
116// Module Functions Declaration
117//----------------------------------------------------------------------------------
118RPRANDAPI void rprand_set_seed(unsigned long long seed); // Set rprand_state for Xoshiro128**, seed is 64bit
119RPRANDAPI int rprand_get_value(int min, int max); // Get random value within a range, min and max included
121RPRANDAPI int *rprand_load_sequence(unsigned int count, int min, int max); // Load pseudo-random numbers sequence with no duplicates
122RPRANDAPI void rprand_unload_sequence(int *sequence); // Unload pseudo-random numbers sequence
124#ifdef __cplusplus
125}
126#endif
128#endif // RPRAND_H
130/***********************************************************************************
131*
132* RPRAND IMPLEMENTATION
133*
134************************************************************************************/
136#if defined(RPRAND_IMPLEMENTATION)
138#include <stdlib.h> // Required for: calloc(), free(), abs()
139#include <stdint.h> // Required for data types: uint32_t, uint64_t
141//----------------------------------------------------------------------------------
142// Types and Structures Definition
143//----------------------------------------------------------------------------------
144// ...
146//----------------------------------------------------------------------------------
147// Global Variables Definition
148//----------------------------------------------------------------------------------
149static uint64_t rprand_seed = 0xAABBCCDD; // SplitMix64 default seed (aligned to rprand_state)
150static uint32_t rprand_state[4] = { // Xoshiro128** state, initialized by SplitMix64
151 0x96ea83c1,
152 0x218b21e5,
153 0xaa91febd,
154 0x976414d4
155};
157//----------------------------------------------------------------------------------
158// Module Internal Functions Declaration
159//----------------------------------------------------------------------------------
160static uint32_t rprand_xoshiro(void); // Xoshiro128** generator (uses global rprand_state)
161static uint64_t rprand_splitmix64(void); // SplitMix64 generator (uses seed to generate rprand_state)
163//----------------------------------------------------------------------------------
164// Module Functions Definition
165//----------------------------------------------------------------------------------
166// Set rprand_state for Xoshiro128**
167// NOTE: We use a custom generation algorithm using SplitMix64
168void rprand_set_seed(unsigned long long seed)
169{
170 rprand_seed = (uint64_t)seed; // Set SplitMix64 seed for further use
172 // To generate the Xoshiro128** state, we use SplitMix64 generator first
173 // We generate 4 pseudo-random 64bit numbers that we combine using their LSB|MSB
174 rprand_state[0] = (uint32_t)(rprand_splitmix64() & 0xffffffff);
175 rprand_state[1] = (uint32_t)((rprand_splitmix64() & 0xffffffff00000000) >> 32);
176 rprand_state[2] = (uint32_t)(rprand_splitmix64() & 0xffffffff);
177 rprand_state[3] = (uint32_t)((rprand_splitmix64() & 0xffffffff00000000) >> 32);
178}
180// Get random value within a range, min and max included
181int rprand_get_value(int min, int max)
182{
183 int value = rprand_xoshiro()%(abs(max - min) + 1) + min;
185 return value;
186}
188// Load pseudo-random numbers sequence with no duplicates, min and max included
189int *rprand_load_sequence(unsigned int count, int min, int max)
190{
191 int *sequence = NULL;
193 if (count > (unsigned int)(abs(max - min) + 1))
194 {
195 RPRAND_LOG("WARNING: Sequence count required is greater than range provided\n");
196 //count = (max - min);
197 return sequence;
198 }
200 sequence = (int *)RPRAND_CALLOC(count, sizeof(int));
202 int value = 0;
203 bool value_is_dup = false;
205 for (unsigned int i = 0; i < count;)
206 {
207 value = ((unsigned int)rprand_xoshiro()%(abs(max - min) + 1)) + min;
209 for (unsigned int j = 0; j < i; j++)
210 {
211 if (sequence[j] == value)
212 {
213 value_is_dup = true;
214 break;
215 }
216 }
218 if (!value_is_dup)
219 {
220 sequence[i] = value;
221 i++;
222 }
224 value_is_dup = false;
225 }
227 return sequence;
228}
230// Unload pseudo-random numbers sequence
231void rprand_unload_sequence(int *sequence)
232{
233 RPRAND_FREE(sequence);
234 sequence = NULL;
235}
237//----------------------------------------------------------------------------------
238// Module Internal Functions Definition
239//----------------------------------------------------------------------------------
240static inline uint32_t rprand_rotate_left(const uint32_t x, int k)
241{
242 return (x << k) | (x >> (32 - k));
243}
245// Xoshiro128** generator info:
246//
247// Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
248//
249// To the extent possible under law, the author has dedicated all copyright
250// and related and neighboring rights to this software to the public domain
251// worldwide. This software is distributed without any warranty.
252//
253// See <http://creativecommons.org/publicdomain/zero/1.0/>.
254//
255// This is xoshiro128** 1.1, one of our 32-bit all-purpose, rock-solid
256// generators. It has excellent speed, a state size (128 bits) that is
257// large enough for mild parallelism, and it passes all tests we are aware
258// of.
259//
260// Note that version 1.0 had mistakenly s[0] instead of s[1] as state
261// word passed to the scrambler.
262//
263// For generating just single-precision (i.e., 32-bit) floating-point
264// numbers, xoshiro128+ is even faster.
265//
266// The state must be seeded so that it is not everywhere zero.
267//
268uint32_t rprand_xoshiro(void)
269{
270 const uint32_t result = rprand_rotate_left(rprand_state[1]*5, 7)*9;
271 const uint32_t t = rprand_state[1] << 9;
273 rprand_state[2] ^= rprand_state[0];
274 rprand_state[3] ^= rprand_state[1];
275 rprand_state[1] ^= rprand_state[2];
276 rprand_state[0] ^= rprand_state[3];
278 rprand_state[2] ^= t;
280 rprand_state[3] = rprand_rotate_left(rprand_state[3], 11);
282 return result;
283}
285// SplitMix64 generator info:
286//
287// Written in 2015 by Sebastiano Vigna (vigna@acm.org)
288//
289// To the extent possible under law, the author has dedicated all copyright
290// and related and neighboring rights to this software to the public domain
291// worldwide. This software is distributed without any warranty.
292//
293// See <http://creativecommons.org/publicdomain/zero/1.0/>.
294//
295//
296// This is a fixed-increment version of Java 8's SplittableRandom generator
297// See http://dx.doi.org/10.1145/2714064.2660195 and
298// http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html
299//
300// It is a very fast generator passing BigCrush, and it can be useful if
301// for some reason you absolutely want 64 bits of state.
302uint64_t rprand_splitmix64()
303{
304 uint64_t z = (rprand_seed += 0x9e3779b97f4a7c15);
305 z = (z ^ (z >> 30))*0xbf58476d1ce4e5b9;
306 z = (z ^ (z >> 27))*0x94d049bb133111eb;
307 return z ^ (z >> 31);
308}
310#endif // RPRAND_IMPLEMENTATION
index : raylib-jai
---