From 2d67f4040f6eecd41f1b864b43c62823ed75aff0 Mon Sep 17 00:00:00 2001 From: tylov Date: Fri, 21 Jul 2023 00:37:28 +0200 Subject: Renamed badly abbreviated names in crand.h. Moved coroutine.h from algo subfolder to stc. Updated coroutine.h and docs. --- include/stc/algo/coroutine.h | 274 ------------------------------------------- include/stc/algorithm.h | 8 ++ include/stc/calgo.h | 9 -- include/stc/coroutine.h | 273 ++++++++++++++++++++++++++++++++++++++++++ include/stc/crand.h | 43 ++++--- 5 files changed, 302 insertions(+), 305 deletions(-) delete mode 100644 include/stc/algo/coroutine.h create mode 100644 include/stc/algorithm.h delete mode 100644 include/stc/calgo.h create mode 100644 include/stc/coroutine.h (limited to 'include') diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h deleted file mode 100644 index 7c6989c3..00000000 --- a/include/stc/algo/coroutine.h +++ /dev/null @@ -1,274 +0,0 @@ -/* MIT License - * - * Copyright (c) 2023 Tyge Løvset - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef STC_COROUTINE_INCLUDED -#define STC_COROUTINE_INCLUDED -/* -#include -#include - -struct iterpair { - int max_x, max_y; - int x, y; - int cco_state; // required member -}; - -int iterpair(struct iterpair* I) { - cco_routine(I) { - for (I->x = 0; I->x < I->max_x; I->x++) - for (I->y = 0; I->y < I->max_y; I->y++) - cco_yield(); - - cco_cleanup: // required if there is cleanup code - puts("final"); - } - return 0; // CCO_DONE -} - -int main(void) { - struct iterpair it = {.max_x=3, .max_y=3}; - int n = 0; - while (iterpair(&it)) - { - printf("%d %d\n", it.x, it.y); - // example of early stop: - if (++n == 7) cco_stop(&it); // signal to stop/finalize in next - } - return 0; -} -*/ -#include "../ccommon.h" - -enum { - CCO_STATE_CLEANUP = -1, - CCO_STATE_DONE = -2, -}; -typedef enum { - CCO_DONE = 0, - CCO_AWAIT = 1<<0, - CCO_YIELD = 1<<1, -} cco_result; - -#define cco_initial(co) ((co)->cco_state == 0) -#define cco_suspended(co) ((co)->cco_state > 0) -#define cco_done(co) ((co)->cco_state == CCO_STATE_DONE) - -#define cco_routine(co) \ - for (int *_state = &(co)->cco_state; *_state != CCO_STATE_DONE; *_state = CCO_STATE_DONE) \ - _resume: switch (*_state) case 0: // thanks, @liigo! - -#define cco_yield() cco_yield_v(CCO_YIELD) -#define cco_yield_v(ret) \ - do { \ - *_state = __LINE__; return ret; goto _resume; \ - case __LINE__:; \ - } while (0) - -#define cco_await(promise) cco_await_v_2(promise, CCO_AWAIT) -#define cco_await_v(...) c_MACRO_OVERLOAD(cco_await_v, __VA_ARGS__) -#define cco_await_v_1(promise) cco_await_v_2(promise, ) -#define cco_await_v_2(promise, ret) \ - do { \ - *_state = __LINE__; \ - case __LINE__: if (!(promise)) {return ret; goto _resume;} \ - } while (0) - -/* cco_await_on(): assumes coroutine returns a cco_result value (int) */ -#define cco_await_on(corocall) \ - do { \ - *_state = __LINE__; \ - case __LINE__: { int _r = corocall; if (_r != CCO_DONE) {return _r; goto _resume;} } \ - } while (0) - -/* cco_block_on(): assumes coroutine returns a cco_result value (int) */ -#define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__) -#define cco_block_on_1(corocall) while ((corocall) != CCO_DONE) -#define cco_block_on_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) - -#define cco_cleanup \ - *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP - -#define cco_return \ - do { \ - *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ - goto _resume; \ - } while (0) - -#define cco_yield_final() cco_yield_final_v(CCO_YIELD) -#define cco_yield_final_v(value) \ - do { \ - *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ - return value; \ - } while (0) - -#define cco_stop(co) \ - do { \ - int* _s = &(co)->cco_state; \ - if (*_s > 0) *_s = CCO_STATE_CLEANUP; \ - else if (*_s == 0) *_s = CCO_STATE_DONE; \ - } while (0) - -#define cco_reset(co) \ - (void)((co)->cco_state = 0) - -/* - * Tasks (optional) - */ - -struct cco_runtime; - -#define cco_task_struct(Name, ...) \ - struct Name { \ - int (*cco_fn)(struct Name*, struct cco_runtime*); \ - int cco_state, cco_expect; \ - __VA_ARGS__ \ - } - -typedef cco_task_struct(cco_task, /**/) cco_task; - -typedef struct cco_runtime { - int result, top; - cco_task* stack[]; -} cco_runtime; - -#define cco_cast_task(task) \ - ((cco_task *)(task) + 0*sizeof((task)->cco_fn(task, (cco_runtime*)0) + ((int*)0 == &(task)->cco_state))) - -#define cco_resume(task, rt) \ - (task)->cco_fn(task, rt) - -#define cco_block_task(...) c_MACRO_OVERLOAD(cco_block_task, __VA_ARGS__) -#define cco_block_task_1(task) cco_block_task_3(task, rt, 16) -#define cco_block_task_3(task, rt, STACKDEPTH) \ - for (struct { int result, top; cco_task* stack[STACKDEPTH]; } rt = {.stack={cco_cast_task(task)}}; \ - (((rt.result = cco_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & rt.stack[rt.top]->cco_expect) || --rt.top >= 0); ) - -#define cco_await_task(...) c_MACRO_OVERLOAD(cco_await_task, __VA_ARGS__) -#define cco_await_task_2(task, rt) cco_await_task_3(task, rt, CCO_DONE) -#define cco_await_task_3(task, rt, resultbits) \ - do { \ - cco_runtime* _rt = rt; \ - (_rt->stack[++_rt->top] = cco_cast_task(task))->cco_expect = ~(resultbits); \ - cco_yield_v(CCO_AWAIT); \ - } while (0) - -/* - * Semaphore - */ - -typedef struct { intptr_t count; } cco_sem; - -#define cco_sem_await(sem) cco_sem_await_v_2(sem, CCO_AWAIT) -#define cco_sem_await_v(...) c_MACRO_OVERLOAD(cco_sem_await_v, __VA_ARGS__) -#define cco_sem_await_v_1(sem) cco_sem_await_v_2(sem, ) -#define cco_sem_await_v_2(sem, ret) \ - do { \ - cco_await_v_2((sem)->count > 0, ret); \ - --(sem)->count; \ - } while (0) - -#define cco_sem_release(sem) ++(sem)->count -#define cco_sem_from(value) ((cco_sem){value}) -#define cco_sem_set(sem, value) ((sem)->count = value) - -/* - * Timer - */ - -#ifdef _WIN32 - #ifdef __cplusplus - #define _c_LINKC extern "C" __declspec(dllimport) - #else - #define _c_LINKC __declspec(dllimport) - #endif - #if 1 // _WIN32_WINNT < _WIN32_WINNT_WIN8 || defined __TINYC__ - #define _c_getsystime GetSystemTimeAsFileTime - #else - #define _c_getsystime GetSystemTimePreciseAsFileTime - #endif - struct _FILETIME; - _c_LINKC void _c_getsystime(struct _FILETIME*); - _c_LINKC void Sleep(unsigned long); - - static inline double cco_time(void) { /* seconds since epoch */ - unsigned long long quad; /* 64-bit value representing 1/10th usecs since Jan 1 1601, 00:00 UTC */ - _c_getsystime((struct _FILETIME*)&quad); - return (double)(quad - 116444736000000000ULL)*1e-7; /* time diff Jan 1 1601-Jan 1 1970 in 1/10th usecs */ - } - - static inline void cco_sleep(double sec) { - Sleep((unsigned long)(sec*1000.0)); - } -#else - #include - static inline double cco_time(void) { /* seconds since epoch */ - struct timeval tv; - gettimeofday(&tv, NULL); - return (double)tv.tv_sec + (double)tv.tv_usec*1e-6; - } - - static inline void cco_sleep(double sec) { - struct timeval tv; - tv.tv_sec = (time_t)sec; - tv.tv_usec = (suseconds_t)((sec - (double)(long)sec)*1e6); - select(0, NULL, NULL, NULL, &tv); - } -#endif - -typedef struct { double interval, start; } cco_timer; - -#define cco_timer_await(tm, sec) cco_timer_await_v_3(tm, sec, CCO_AWAIT) -#define cco_timer_await_v(...) c_MACRO_OVERLOAD(cco_timer_await_v, __VA_ARGS__) -#define cco_timer_await_v_2(tm, sec) cco_timer_await_v_3(tm, sec, ) -#define cco_timer_await_v_3(tm, sec, ret) \ - do { \ - cco_timer_start(tm, sec); \ - cco_await_v_2(cco_timer_expired(tm), ret); \ - } while (0) - -static inline void cco_timer_start(cco_timer* tm, double sec) { - tm->interval = sec; - tm->start = cco_time(); -} - -static inline cco_timer cco_timer_from(double sec) { - cco_timer tm = {.interval=sec, .start=cco_time()}; - return tm; -} - -static inline void cco_timer_restart(cco_timer* tm) { - tm->start = cco_time(); -} - -static inline bool cco_timer_expired(cco_timer* tm) { - return cco_time() - tm->start >= tm->interval; -} - -static inline double cco_timer_elapsed(cco_timer* tm) { - return cco_time() - tm->start; -} - -static inline double cco_timer_remaining(cco_timer* tm) { - return tm->start + tm->interval - cco_time(); -} - -#endif diff --git a/include/stc/algorithm.h b/include/stc/algorithm.h new file mode 100644 index 00000000..cf3ab328 --- /dev/null +++ b/include/stc/algorithm.h @@ -0,0 +1,8 @@ +#ifndef STC_CALGO_INCLUDED +#define STC_CALGO_INCLUDED + +#include "algo/raii.h" +#include "algo/crange.h" +#include "algo/filter.h" + +#endif diff --git a/include/stc/calgo.h b/include/stc/calgo.h deleted file mode 100644 index 63ef97b9..00000000 --- a/include/stc/calgo.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef STC_CALGO_INCLUDED -#define STC_CALGO_INCLUDED - -#include "algo/raii.h" -#include "algo/crange.h" -#include "algo/filter.h" -#include "algo/coroutine.h" - -#endif diff --git a/include/stc/coroutine.h b/include/stc/coroutine.h new file mode 100644 index 00000000..f89d20af --- /dev/null +++ b/include/stc/coroutine.h @@ -0,0 +1,273 @@ +/* MIT License + * + * Copyright (c) 2023 Tyge Løvset + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef STC_COROUTINE_INCLUDED +#define STC_COROUTINE_INCLUDED +/* +#include +#include + +struct iterpair { + int max_x, max_y; + int x, y; + int cco_state; // required member +}; + +int iterpair(struct iterpair* I) { + cco_routine(I) { + for (I->x = 0; I->x < I->max_x; I->x++) + for (I->y = 0; I->y < I->max_y; I->y++) + cco_yield(); + + cco_cleanup: // required if there is cleanup code + puts("final"); + } + return 0; // CCO_DONE +} + +int main(void) { + struct iterpair it = {.max_x=3, .max_y=3}; + int n = 0; + while (iterpair(&it)) + { + printf("%d %d\n", it.x, it.y); + // example of early stop: + if (++n == 7) cco_stop(&it); // signal to stop/finalize in next + } + return 0; +} +*/ +#include "ccommon.h" + +enum { + CCO_STATE_CLEANUP = -1, + CCO_STATE_DONE = -2, +}; +typedef enum { + CCO_DONE = 0, + CCO_AWAIT = 1<<0, + CCO_YIELD = 1<<1, +} cco_result; + +#define cco_initial(co) ((co)->cco_state == 0) +#define cco_suspended(co) ((co)->cco_state > 0) +#define cco_done(co) ((co)->cco_state == CCO_STATE_DONE) + +#define cco_routine(co) \ + for (int* _state = &(co)->cco_state; *_state != CCO_STATE_DONE; *_state = CCO_STATE_DONE) \ + _resume: switch (*_state) case 0: // thanks, @liigo! + +#define cco_yield() cco_yield_v(CCO_YIELD) +#define cco_yield_v(ret) \ + do { \ + *_state = __LINE__; return ret; goto _resume; \ + case __LINE__:; \ + } while (0) + +#define cco_await(promise) cco_await_v_2(promise, CCO_AWAIT) +#define cco_await_v(...) c_MACRO_OVERLOAD(cco_await_v, __VA_ARGS__) +#define cco_await_v_1(promise) cco_await_v_2(promise, ) +#define cco_await_v_2(promise, ret) \ + do { \ + *_state = __LINE__; \ + case __LINE__: if (!(promise)) {return ret; goto _resume;} \ + } while (0) + +/* cco_await_on(): assumes coroutine returns a cco_result value (int) */ +#define cco_await_on(corocall) \ + do { \ + *_state = __LINE__; \ + case __LINE__: { int _r = corocall; if (_r != CCO_DONE) {return _r; goto _resume;} } \ + } while (0) + +/* cco_block_on(): assumes coroutine returns a cco_result value (int) */ +#define cco_block_on(...) c_MACRO_OVERLOAD(cco_block_on, __VA_ARGS__) +#define cco_block_on_1(corocall) while ((corocall) != CCO_DONE) +#define cco_block_on_2(corocall, result) while ((*(result) = (corocall)) != CCO_DONE) + +#define cco_cleanup \ + *_state = CCO_STATE_CLEANUP; case CCO_STATE_CLEANUP + +#define cco_return \ + do { \ + *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ + goto _resume; \ + } while (0) + +#define cco_yield_final() cco_yield_final_v(CCO_YIELD) +#define cco_yield_final_v(value) \ + do { \ + *_state = *_state >= 0 ? CCO_STATE_CLEANUP : CCO_STATE_DONE; \ + return value; \ + } while (0) + +#define cco_stop(co) \ + do { \ + int* _s = &(co)->cco_state; \ + if (*_s > 0) *_s = CCO_STATE_CLEANUP; \ + else if (*_s == 0) *_s = CCO_STATE_DONE; \ + } while (0) + +#define cco_reset(co) \ + (void)((co)->cco_state = 0) + +/* + * Tasks (optional) + */ + +struct cco_runtime; + +#define cco_task_struct(Name, ...) \ + struct Name { \ + int (*cco_func)(struct Name*, struct cco_runtime*); \ + int cco_state, cco_expect; \ + __VA_ARGS__ \ + } + +typedef cco_task_struct(cco_task, /**/) cco_task; + +typedef struct cco_runtime { + int result, top; cco_task* stack[]; +} cco_runtime; + +#define cco_cast_task(task) \ + ((cco_task *)(task) + 0*sizeof((task)->cco_func(task, (cco_runtime*)0) + ((int*)0 == &(task)->cco_state))) + +#define cco_resume(task, rt) \ + (task)->cco_func(task, rt) + +#define cco_task_await(...) c_MACRO_OVERLOAD(cco_task_await, __VA_ARGS__) +#define cco_task_await_2(task, rt) cco_task_await_3(task, rt, CCO_DONE) +#define cco_task_await_3(task, rt, resultbits) \ + do { \ + cco_runtime* _rt = rt; \ + (_rt->stack[++_rt->top] = cco_cast_task(task))->cco_expect = (resultbits); \ + cco_yield_v(CCO_AWAIT); \ + } while (0) + +#define cco_task_block_on(...) c_MACRO_OVERLOAD(cco_task_block_on, __VA_ARGS__) +#define cco_task_block_on_1(task) cco_task_block_on_3(task, _rt, 16) +#define cco_task_block_on_3(task, rt, STACKDEPTH) \ + for (struct { int result, top; cco_task* stack[STACKDEPTH]; } rt = {.stack={cco_cast_task(task)}}; \ + (((rt.result = cco_resume(rt.stack[rt.top], (cco_runtime*)&rt)) & ~rt.stack[rt.top]->cco_expect) || --rt.top >= 0); ) + +/* + * Semaphore + */ + +typedef struct { intptr_t count; } cco_sem; + +#define cco_sem_await(sem) cco_sem_await_v_2(sem, CCO_AWAIT) +#define cco_sem_await_v(...) c_MACRO_OVERLOAD(cco_sem_await_v, __VA_ARGS__) +#define cco_sem_await_v_1(sem) cco_sem_await_v_2(sem, ) +#define cco_sem_await_v_2(sem, ret) \ + do { \ + cco_await_v_2((sem)->count > 0, ret); \ + --(sem)->count; \ + } while (0) + +#define cco_sem_release(sem) ++(sem)->count +#define cco_sem_from(value) ((cco_sem){value}) +#define cco_sem_set(sem, value) ((sem)->count = value) + +/* + * Timer + */ + +#ifdef _WIN32 + #ifdef __cplusplus + #define _c_LINKC extern "C" __declspec(dllimport) + #else + #define _c_LINKC __declspec(dllimport) + #endif + #if 1 // _WIN32_WINNT < _WIN32_WINNT_WIN8 || defined __TINYC__ + #define _c_getsystime GetSystemTimeAsFileTime + #else + #define _c_getsystime GetSystemTimePreciseAsFileTime + #endif + struct _FILETIME; + _c_LINKC void _c_getsystime(struct _FILETIME*); + _c_LINKC void Sleep(unsigned long); + + static inline double cco_time(void) { /* seconds since epoch */ + unsigned long long quad; /* 64-bit value representing 1/10th usecs since Jan 1 1601, 00:00 UTC */ + _c_getsystime((struct _FILETIME*)&quad); + return (double)(quad - 116444736000000000ULL)*1e-7; /* time diff Jan 1 1601-Jan 1 1970 in 1/10th usecs */ + } + + static inline void cco_sleep(double sec) { + Sleep((unsigned long)(sec*1000.0)); + } +#else + #include + static inline double cco_time(void) { /* seconds since epoch */ + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec*1e-6; + } + + static inline void cco_sleep(double sec) { + struct timeval tv; + tv.tv_sec = (time_t)sec; + tv.tv_usec = (suseconds_t)((sec - (double)(long)sec)*1e6); + select(0, NULL, NULL, NULL, &tv); + } +#endif + +typedef struct { double interval, start; } cco_timer; + +#define cco_timer_await(tm, sec) cco_timer_await_v_3(tm, sec, CCO_AWAIT) +#define cco_timer_await_v(...) c_MACRO_OVERLOAD(cco_timer_await_v, __VA_ARGS__) +#define cco_timer_await_v_2(tm, sec) cco_timer_await_v_3(tm, sec, ) +#define cco_timer_await_v_3(tm, sec, ret) \ + do { \ + cco_timer_start(tm, sec); \ + cco_await_v_2(cco_timer_expired(tm), ret); \ + } while (0) + +static inline void cco_timer_start(cco_timer* tm, double sec) { + tm->interval = sec; + tm->start = cco_time(); +} + +static inline cco_timer cco_timer_from(double sec) { + cco_timer tm = {.interval=sec, .start=cco_time()}; + return tm; +} + +static inline void cco_timer_restart(cco_timer* tm) { + tm->start = cco_time(); +} + +static inline bool cco_timer_expired(cco_timer* tm) { + return cco_time() - tm->start >= tm->interval; +} + +static inline double cco_timer_elapsed(cco_timer* tm) { + return cco_time() - tm->start; +} + +static inline double cco_timer_remaining(cco_timer* tm) { + return tm->start + tm->interval - cco_time(); +} + +#endif diff --git a/include/stc/crand.h b/include/stc/crand.h index 0a6aa9e0..32722762 100644 --- a/include/stc/crand.h +++ b/include/stc/crand.h @@ -32,20 +32,20 @@ int main(void) { uint64_t seed = 123456789; crand_t rng = crand_init(seed); - crand_unif_t dist1 = crand_unif_init(1, 6); - crand_norm_t dist3 = crand_norm_init(1.0, 10.0); + crand_uniform_t dist1 = crand_uniform_init(1, 6); + crand_normal_t dist3 = crand_normal_init(1.0, 10.0); uint64_t i = crand_u64(&rng); - int64_t iu = crand_unif(&rng, &dist1); - double xn = crand_norm(&rng, &dist3); + int64_t iu = crand_uniform(&rng, &dist1); + double xn = crand_normal(&rng, &dist3); } */ #include #include typedef struct crand { uint64_t state[5]; } crand_t; -typedef struct crand_unif { int64_t lower; uint64_t range, threshold; } crand_unif_t; -typedef struct crand_norm { double mean, stddev, next; int has_next; } crand_norm_t; +typedef struct crand_uniform { int64_t lower; uint64_t range, threshold; } crand_uniform_t; +typedef struct crand_normal { double mean, stddev, next; int has_next; } crand_normal_t; /* PRNG crand_t. * Very fast PRNG suited for parallel usage with Weyl-sequence parameter. @@ -67,14 +67,14 @@ STC_API double crandf(void); STC_API crand_t crand_init(uint64_t seed); /* Unbiased bounded uniform distribution. range [low, high] */ -STC_API crand_unif_t crand_unif_init(int64_t low, int64_t high); -STC_API int64_t crand_unif(crand_t* rng, crand_unif_t* dist); +STC_API crand_uniform_t crand_uniform_init(int64_t low, int64_t high); +STC_API int64_t crand_uniform(crand_t* rng, crand_uniform_t* dist); /* Normal/gaussian distribution. */ -STC_INLINE crand_norm_t crand_norm_init(double mean, double stddev) - { crand_norm_t r = {mean, stddev, 0.0, 0}; return r; } +STC_INLINE crand_normal_t crand_normal_init(double mean, double stddev) + { crand_normal_t r = {mean, stddev, 0.0, 0}; return r; } -STC_API double crand_norm(crand_t* rng, crand_norm_t* dist); +STC_API double crand_normal(crand_t* rng, crand_normal_t* dist); /* Main crand_t prng */ STC_INLINE uint64_t crand_u64(crand_t* rng) { @@ -95,11 +95,10 @@ STC_INLINE double crand_f64(crand_t* rng) { /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined(i_implement) || defined(i_static) -/* Global random() */ -static crand_t crand_global = {{ - 0x26aa069ea2fb1a4d, 0x70c72c95cd592d04, - 0x504f333d3aa0b359, 0x9e3779b97f4a7c15, - 0x6a09e667a754166b +/* Global random seed */ +static crand_t crand_global = {{ // csrand(0) + 0x9e3779b97f4a7c15, 0x6f68261b57e7a770, + 0xe220a838bf5c9dde, 0x7c17d1800457b1ba, 0x1, }}; STC_DEF void csrand(uint64_t seed) @@ -116,20 +115,20 @@ STC_DEF crand_t crand_init(uint64_t seed) { s[0] = seed + 0x9e3779b97f4a7c15; s[1] = (s[0] ^ (s[0] >> 30))*0xbf58476d1ce4e5b9; s[2] = (s[1] ^ (s[1] >> 27))*0x94d049bb133111eb; - s[3] = (s[2] ^ (s[2] >> 31)); - s[4] = ((seed + 0x6aa069ea2fb1a4d) << 1) | 1; + s[3] = s[0] ^ s[2] ^ (s[2] >> 31); + s[4] = (seed << 1) | 1; return rng; } /* Init unbiased uniform uint RNG with bounds [low, high] */ -STC_DEF crand_unif_t crand_unif_init(int64_t low, int64_t high) { - crand_unif_t dist = {low, (uint64_t) (high - low + 1)}; +STC_DEF crand_uniform_t crand_uniform_init(int64_t low, int64_t high) { + crand_uniform_t dist = {low, (uint64_t) (high - low + 1)}; dist.threshold = (uint64_t)(0 - dist.range) % dist.range; return dist; } /* Int64 uniform distributed RNG, range [low, high]. */ -STC_DEF int64_t crand_unif(crand_t* rng, crand_unif_t* d) { +STC_DEF int64_t crand_uniform(crand_t* rng, crand_uniform_t* d) { uint64_t lo, hi; #ifdef c_umul128 do { c_umul128(crand_u64(rng), d->range, &lo, &hi); } while (lo < d->threshold); @@ -140,7 +139,7 @@ STC_DEF int64_t crand_unif(crand_t* rng, crand_unif_t* d) { } /* Normal distribution PRNG. Marsaglia polar method */ -STC_DEF double crand_norm(crand_t* rng, crand_norm_t* dist) { +STC_DEF double crand_normal(crand_t* rng, crand_normal_t* dist) { double u1, u2, s, m; if (dist->has_next++ & 1) return dist->next*dist->stddev + dist->mean; -- cgit v1.2.3