Created
December 11, 2011 04:57
-
-
Save Slipyx/1458441 to your computer and use it in GitHub Desktop.
LCMWC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
** lcmwc | |
** A Complimentary-Multiply-With-Carry Random Number Generator library for Lua | |
** | |
** Copyright (C) 2011-2012 Josh Koch. | |
** | |
** 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. | |
*/ | |
#include <lauxlib.h> | |
#include <time.h> | |
/* Custom integer types */ | |
#include <limits.h> | |
#define UINT32_MAX ULONG_MAX | |
typedef unsigned char uint8_t; | |
typedef unsigned short uint16_t; | |
typedef long int32_t; | |
typedef unsigned long uint32_t; | |
typedef unsigned long long uint64_t; | |
/* Global states */ | |
static uint32_t Q[4096] = {0}, c = 362436, id = 4095; | |
/* Random unsigned 32bit integer */ | |
static uint32_t CMWC4096( void ) { | |
uint64_t t = 0; | |
uint32_t x = 0; | |
id = (id + 1) & 4095; | |
t = 18782LL * Q[id] + c; | |
c = (t >> 32); | |
x = (uint32_t)(t + c); | |
if ( x < c ) { | |
++x; | |
++c; | |
} | |
return (Q[id] = 0xFFFFFFFE - x); | |
} | |
/* Gets a "random" seed based on hash of current time or something */ | |
static uint32_t TimeSeed( void ) { | |
time_t now = time( NULL ); | |
uint8_t* p = (uint8_t*)&now; | |
uint32_t seed = 0; | |
size_t i = 0; | |
for ( i = 0; i < sizeof(now); ++i ) { | |
seed = seed * (0xFF + 2U) + p[i]; | |
} | |
return seed; | |
} | |
/* | |
** The functions for Lua | |
*/ | |
/* Seed the random generator */ | |
static int lcmwc_seed( lua_State* L ) { | |
int32_t argc = lua_gettop( L ); /* Get number of arguments */ | |
uint16_t i = 0; | |
uint32_t seed = 0; | |
/* No seed specified, so use the time hash thing */ | |
if ( argc < 1 ) { | |
seed = TimeSeed(); | |
/* Is first argument a number? */ | |
} else if ( lua_isnumber( L, 1 ) == 0 ) { | |
lua_pushstring( L, "bad argument #1 to 'seed' (number expected)" ); | |
lua_error( L ); | |
/* Use the seed given */ | |
} else { | |
seed = (uint32_t)lua_tonumber( L, 1 ); | |
} | |
/* Do the actual seeding and state initialization */ | |
Q[0] = seed; | |
for ( i = 1; i < 4096; ++i ) { | |
Q[i] = 1812433253 * (Q[i - 1] ^ (Q[i - 1] >> 30)) + i; | |
} | |
c = Q[4095] % 809430660; | |
id = 4095; | |
return 0; /* No return values */ | |
} | |
/* Return a random number depending on range specified */ | |
static int32_t lcmwc_random( lua_State* L ) { | |
int32_t argc = lua_gettop( L ); /* Get number of arguments */ | |
/* Random lua_Number in range [0.0 - 1.0], not quite inclusive */ | |
if ( argc < 1 ) { | |
lua_pushnumber( L, CMWC4096() / (lua_Number)UINT32_MAX ); | |
} else { | |
int32_t min = 0, max = 0; | |
/* Is there at least one number given? */ | |
if ( lua_isnumber( L, 1 ) == 0 ) { | |
lua_pushstring( L, "bad argument #1 to 'random' " | |
"(number expected)" ); | |
lua_error( L ); | |
} | |
/* Random integer in range [1 - max], inclusive */ | |
if ( argc == 1 ) { | |
min = 1; | |
max = (int32_t)lua_tonumber( L, 1 ); | |
/* For a single negative argument, range is [(max + 1) - 0] */ | |
if ( max < 0 ) { | |
min = max + 1; | |
max = 0; | |
} | |
/* Random integer in range [min - max], inclusive */ | |
} else if ( lua_isnumber( L, 2 ) ) { | |
min = (int32_t)lua_tonumber( L, 1 ); | |
max = (int32_t)lua_tonumber( L, 2 ); | |
/* If first argument isn't the minimum, swap the two */ | |
if ( min > max ) { | |
int32_t tmp = min; | |
min = max; max = tmp; | |
} | |
/* Second argument is not a number */ | |
} else { | |
lua_pushstring( L, "bad argument #2 to 'random' " | |
"(number expected)" ); | |
lua_error( L ); | |
} | |
/* Get random number in range */ | |
lua_pushnumber( L, (int32_t)(CMWC4096() % (max - min + 1) + min) ); | |
} | |
return 1; /* One random number is returned */ | |
} | |
/* The table of registered functions */ | |
static const struct luaL_Reg lcmwc_reg[] = { | |
{"seed", lcmwc_seed}, | |
{"random", lcmwc_random}, | |
{NULL, NULL} | |
}; | |
/* Open the lib and register the functions */ | |
#if defined(_WIN32) || defined(WIN32) | |
__declspec(dllexport) | |
#endif | |
int32_t luaopen_lcmwc( lua_State* L ) { | |
luaL_register( L, "lcmwc", lcmwc_reg ); | |
/* Seed and initialize the PRNG on lib open */ | |
lua_pushcfunction( L, lcmwc_seed ); | |
lua_call( L, 0, 0 ); | |
return 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment