random.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /*++
  2. Copyright (c) 2015 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. random.c
  9. Abstract:
  10. This module implements the random interface, which supplies pseudo-random
  11. numbers via a non-linear additive feedback random number generator.
  12. Author:
  13. Evan Green 9-Mar-2015
  14. Environment:
  15. User Mode C Library
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include "libcp.h"
  21. #include <errno.h>
  22. #include <stdlib.h>
  23. //
  24. // ---------------------------------------------------------------- Definitions
  25. //
  26. #define RANDOM_DEFAULT_STATE_SIZE 128
  27. //
  28. // ------------------------------------------------------ Data Type Definitions
  29. //
  30. typedef enum _RANDOM_TYPE {
  31. RandomType0,
  32. RandomType1,
  33. RandomType2,
  34. RandomType3,
  35. RandomType4,
  36. RandomTypeCount
  37. } RANDOM_TYPE, *PRANDOM_TYPE;
  38. //
  39. // ----------------------------------------------- Internal Function Prototypes
  40. //
  41. //
  42. // -------------------------------------------------------------------- Globals
  43. //
  44. int ClRandomBreaks[RandomTypeCount] = {8, 32, 64, 128, 256};
  45. int ClRandomDegrees[RandomTypeCount] = {0, 7, 15, 31, 63};
  46. int ClRandomSeparations[RandomTypeCount] = {0, 3, 1, 3, 1};
  47. //
  48. // Store the global random state, making the functions that use this state
  49. // not thread-safe and not reentrant.
  50. //
  51. struct random_data ClRandomData;
  52. //
  53. // ------------------------------------------------------------------ Functions
  54. //
  55. LIBC_API
  56. char *
  57. initstate (
  58. unsigned int Seed,
  59. char *State,
  60. size_t Size
  61. )
  62. /*++
  63. Routine Description:
  64. This routine initializes the state of the random number generator using
  65. the given state data. This routine is neither thread-safe nor reentrant.
  66. Arguments:
  67. Seed - Supplies the seed value to use.
  68. State - Supplies a pointer the random state data to use.
  69. Size - Supplies the size of the random state data. Valid values are 8, 32,
  70. 64, 128, and 256. If the value is not one of these values, it will be
  71. truncated down to one of these values. For data sizes less than 32, a
  72. simple linear congruential random number generator is used. The minimum
  73. valid size is 8.
  74. Return Value:
  75. Returns a pointer to the previous state.
  76. --*/
  77. {
  78. void *OriginalState;
  79. OriginalState = ClRandomData.state;
  80. initstate_r(Seed, State, Size, &ClRandomData);
  81. return OriginalState;
  82. }
  83. LIBC_API
  84. char *
  85. setstate (
  86. const char *State
  87. )
  88. /*++
  89. Routine Description:
  90. This routine resets the state of the random number generator to the given
  91. state, previously acquired from initstate. This routine is neither
  92. thread-safe nor reentrant.
  93. Arguments:
  94. State - Supplies a pointer to the state to set.
  95. Return Value:
  96. Returns a pointer to the previous state.
  97. --*/
  98. {
  99. void *OriginalState;
  100. OriginalState = ClRandomData.state;
  101. setstate_r(State, &ClRandomData);
  102. return OriginalState;
  103. }
  104. LIBC_API
  105. void
  106. srandom (
  107. unsigned int Seed
  108. )
  109. /*++
  110. Routine Description:
  111. This routine seeds the non-linear additive feedback random number
  112. generator. This routine is neither thread-safe nor reentrant.
  113. Arguments:
  114. Seed - Supplies the seed value to use.
  115. Return Value:
  116. None.
  117. --*/
  118. {
  119. char *State;
  120. if (ClRandomData.state == NULL) {
  121. State = malloc(RANDOM_DEFAULT_STATE_SIZE);
  122. if (State == NULL) {
  123. return;
  124. }
  125. initstate_r(1, State, RANDOM_DEFAULT_STATE_SIZE, &ClRandomData);
  126. }
  127. srandom_r(Seed, &ClRandomData);
  128. return;
  129. }
  130. LIBC_API
  131. long
  132. random (
  133. void
  134. )
  135. /*++
  136. Routine Description:
  137. This routine returns a random number in the range of 0 to 0x7FFFFFFF,
  138. inclusive. This routine is neither thread-safe nor reentrant.
  139. Arguments:
  140. None.
  141. Return Value:
  142. Returns a pseudo-random number in the range 0 to 2^32 - 1, inclusive.
  143. --*/
  144. {
  145. int32_t Result;
  146. char *State;
  147. if (ClRandomData.state == NULL) {
  148. State = malloc(RANDOM_DEFAULT_STATE_SIZE);
  149. if (State == NULL) {
  150. return -1;
  151. }
  152. initstate_r(1, State, RANDOM_DEFAULT_STATE_SIZE, &ClRandomData);
  153. }
  154. if (random_r(&ClRandomData, &Result) != 0) {
  155. return -1;
  156. }
  157. return Result;
  158. }
  159. LIBC_API
  160. int
  161. initstate_r (
  162. unsigned int Seed,
  163. char *State,
  164. size_t Size,
  165. struct random_data *RandomData
  166. )
  167. /*++
  168. Routine Description:
  169. This routine initializes the state of the random number generator using
  170. the given state data.
  171. Arguments:
  172. Seed - Supplies the seed value to use.
  173. State - Supplies a pointer the random state data to use.
  174. Size - Supplies the size of the random state data. Valid values are 8, 32,
  175. 64, 128, and 256. If the value is not one of these values, it will be
  176. truncated down to one of these values. For data sizes less than 32, a
  177. simple linear congruential random number generator is used. The minimum
  178. valid size is 8.
  179. RandomData - Supplies a pointer to the random state context.
  180. Return Value:
  181. 0 on success.
  182. -1 on failure.
  183. --*/
  184. {
  185. int Degree;
  186. int32_t *OriginalState;
  187. int OriginalType;
  188. int Separation;
  189. int Type;
  190. if (RandomData == NULL) {
  191. errno = EINVAL;
  192. return -1;
  193. }
  194. OriginalState = RandomData->state;
  195. if (OriginalState != NULL) {
  196. OriginalType = RandomData->rand_type;
  197. if (OriginalType == RandomType0) {
  198. *(OriginalState - 1) = RandomType0;
  199. } else {
  200. *(OriginalState - 1) = (RandomTypeCount *
  201. (RandomData->rptr - OriginalState)) +
  202. OriginalType;
  203. }
  204. }
  205. if (Size < ClRandomBreaks[RandomType0]) {
  206. errno = EINVAL;
  207. return -1;
  208. }
  209. for (Type = RandomType0; Type < RandomType4 - 1; Type += 1) {
  210. if (Size < ClRandomBreaks[Type + 1]) {
  211. break;
  212. }
  213. }
  214. Degree = ClRandomDegrees[Type];
  215. Separation = ClRandomSeparations[Type];
  216. RandomData->rand_type = Type;
  217. RandomData->rand_deg = Degree;
  218. RandomData->rand_sep = Separation;
  219. RandomData->state = ((int32_t *)State) + 1;
  220. RandomData->end_ptr = &(RandomData->state[Degree]);
  221. srandom_r(Seed, RandomData);
  222. *(RandomData->state - 1) = RandomType0;
  223. if (Type != RandomType0) {
  224. *(RandomData->state - 1) = ((RandomData->rptr - RandomData->state) *
  225. RandomTypeCount) + Type;
  226. }
  227. return 0;
  228. }
  229. LIBC_API
  230. int
  231. setstate_r (
  232. const char *State,
  233. struct random_data *RandomData
  234. )
  235. /*++
  236. Routine Description:
  237. This routine resets the state of the random number generator to the given
  238. state.
  239. Arguments:
  240. State - Supplies a pointer to the state to set.
  241. RandomData - Supplies a pointer to the random state to use.
  242. Return Value:
  243. 0 on success.
  244. -1 on failure.
  245. --*/
  246. {
  247. int Degree;
  248. int32_t *NewState;
  249. int32_t *OriginalState;
  250. int OriginalType;
  251. UINTN RearIndex;
  252. int Separation;
  253. int Type;
  254. if ((State == NULL) || (RandomData == NULL)) {
  255. errno = EINVAL;
  256. return -1;
  257. }
  258. NewState = ((int32_t *)State) + 1;
  259. OriginalType = RandomData->rand_type;
  260. OriginalState = RandomData->state;
  261. if (OriginalType == RandomType0) {
  262. *(OriginalState - 1) = RandomType0;
  263. } else {
  264. *(OriginalState - 1) = ((RandomData->rptr - OriginalState) *
  265. RandomTypeCount) + OriginalType;
  266. }
  267. Type = *(NewState - 1) % RandomTypeCount;
  268. if ((Type < RandomType0) || (Type >= RandomTypeCount)) {
  269. errno = EINVAL;
  270. return -1;
  271. }
  272. Degree = ClRandomDegrees[Type];
  273. Separation = ClRandomSeparations[Type];
  274. RandomData->rand_deg = Degree;
  275. RandomData->rand_sep = Separation;
  276. RandomData->rand_type = Type;
  277. if (Type != RandomType0) {
  278. RearIndex = *(NewState - 1) / RandomTypeCount;
  279. RandomData->rptr = &(NewState[RearIndex]);
  280. RandomData->fptr = &(NewState[(RearIndex + Separation) % Degree]);
  281. }
  282. RandomData->state = NewState;
  283. RandomData->end_ptr = &(NewState[Degree]);
  284. return 0;
  285. }
  286. LIBC_API
  287. int
  288. srandom_r (
  289. unsigned int Seed,
  290. struct random_data *RandomData
  291. )
  292. /*++
  293. Routine Description:
  294. This routine seeds the non-linear additive feedback random number generator.
  295. Arguments:
  296. Seed - Supplies the seed value to use.
  297. RandomData - Supplies a pointer to the random state to use.
  298. Return Value:
  299. 0 on success.
  300. -1 on failure.
  301. --*/
  302. {
  303. INTN Degree;
  304. int32_t *Destination;
  305. LONG High;
  306. UINTN Index;
  307. LONG Low;
  308. int32_t *State;
  309. int Type;
  310. int32_t UnusedValue;
  311. int32_t Word;
  312. if ((RandomData == NULL) || (RandomData->rand_type >= RandomTypeCount)) {
  313. errno = EINVAL;
  314. return -1;
  315. }
  316. State = RandomData->state;
  317. Type = RandomData->rand_type;
  318. if (Seed == 0) {
  319. Seed = 1;
  320. }
  321. State[0] = Seed;
  322. if (Type == RandomType0) {
  323. return 0;
  324. }
  325. Destination = State;
  326. Word = Seed;
  327. Degree = RandomData->rand_deg;
  328. for (Index = 1; Index < Degree; Index += 1) {
  329. //
  330. // Set State[i] equal to (State[i - 1] * 16807) % 0x7FFFFFFF.
  331. //
  332. High = Word / 127773;
  333. Low = Word % 127773;
  334. Word = (16807 * Low) - (2836 * High);
  335. if (Word < 0) {
  336. Word += 0x7FFFFFFF;
  337. }
  338. Destination += 1;
  339. *Destination = Word;
  340. }
  341. RandomData->fptr = &(State[RandomData->rand_sep]);
  342. RandomData->rptr = &(State[0]);
  343. Degree *= 10;
  344. while (Degree > 0) {
  345. Degree -= 1;
  346. random_r(RandomData, &UnusedValue);
  347. }
  348. return 0;
  349. }
  350. LIBC_API
  351. int
  352. random_r (
  353. struct random_data *RandomData,
  354. int32_t *Result
  355. )
  356. /*++
  357. Routine Description:
  358. This routine returns a random number in the range of 0 to 0x7FFFFFFF,
  359. inclusive.
  360. Arguments:
  361. RandomData - Supplies a pointer to the random state to use.
  362. Result - Supplies a pointer where the result will be returned on success.
  363. Return Value:
  364. 0 on success.
  365. -1 on failure.
  366. --*/
  367. {
  368. int32_t *End;
  369. int32_t *Front;
  370. int32_t *Rear;
  371. int32_t *State;
  372. int32_t Value;
  373. if ((RandomData == NULL) || (Result == NULL)) {
  374. errno = EINVAL;
  375. return -1;
  376. }
  377. State = RandomData->state;
  378. if (RandomData->rand_type == RandomType0) {
  379. Value = ((RandomData->state[0] * 1103515245) + 12345) & 0x7FFFFFFF;
  380. RandomData->state[0] = Value;
  381. *Result = Value;
  382. } else {
  383. Front = RandomData->fptr;
  384. Rear = RandomData->rptr;
  385. End = RandomData->end_ptr;
  386. *Front += *Rear;
  387. Value = *Front;
  388. //
  389. // Throw out the least significant bit.
  390. //
  391. *Result = (Value >> 1) & 0x7FFFFFFF;
  392. Front += 1;
  393. if (Front >= End) {
  394. Front = State;
  395. Rear += 1;
  396. } else {
  397. Rear += 1;
  398. if (Rear >= End) {
  399. Rear = State;
  400. }
  401. }
  402. RandomData->fptr = Front;
  403. RandomData->rptr = Rear;
  404. }
  405. return 0;
  406. }
  407. //
  408. // --------------------------------------------------------- Internal Functions
  409. //