1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Author: Sascha Schumann <sascha@schumann.cx> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: lcg.c 272370 2008-12-31 11:15:49Z sebastian $ */
20 :
21 : #include "php.h"
22 : #include "php_lcg.h"
23 :
24 : #if HAVE_UNISTD_H
25 : #include <unistd.h>
26 : #endif
27 :
28 : #ifdef PHP_WIN32
29 : #include "win32/time.h"
30 : #else
31 : #include <sys/time.h>
32 : #endif
33 :
34 : #ifdef ZTS
35 : int lcg_globals_id;
36 : #else
37 : static php_lcg_globals lcg_globals;
38 : #endif
39 :
40 : #ifdef PHP_WIN32
41 : #include <process.h>
42 : #endif
43 :
44 : /*
45 : * combinedLCG() returns a pseudo random number in the range of (0, 1).
46 : * The function combines two CGs with periods of
47 : * 2^31 - 85 and 2^31 - 249. The period of this function
48 : * is equal to the product of both primes.
49 : */
50 :
51 : #define MODMULT(a, b, c, m, s) q = s/a;s=b*(s-a*q)-c*q;if(s<0)s+=m
52 :
53 : static void lcg_seed(TSRMLS_D);
54 :
55 : PHPAPI double php_combined_lcg(TSRMLS_D) /* {{{ */
56 780 : {
57 : php_int32 q;
58 : php_int32 z;
59 :
60 780 : if (!LCG(seeded)) {
61 261 : lcg_seed(TSRMLS_C);
62 : }
63 :
64 780 : MODMULT(53668, 40014, 12211, 2147483563L, LCG(s1));
65 780 : MODMULT(52774, 40692, 3791, 2147483399L, LCG(s2));
66 :
67 780 : z = LCG(s1) - LCG(s2);
68 780 : if (z < 1) {
69 336 : z += 2147483562;
70 : }
71 :
72 780 : return z * 4.656613e-10;
73 : }
74 : /* }}} */
75 :
76 : static void lcg_seed(TSRMLS_D) /* {{{ */
77 261 : {
78 : struct timeval tv;
79 :
80 261 : if (gettimeofday(&tv, NULL) == 0) {
81 261 : LCG(s1) = tv.tv_sec ^ (~tv.tv_usec);
82 : } else {
83 0 : LCG(s1) = 1;
84 : }
85 : #ifdef ZTS
86 : LCG(s2) = (long) tsrm_thread_id();
87 : #else
88 261 : LCG(s2) = (long) getpid();
89 : #endif
90 :
91 261 : LCG(seeded) = 1;
92 261 : }
93 : /* }}} */
94 :
95 : static void lcg_init_globals(php_lcg_globals *lcg_globals_p TSRMLS_DC) /* {{{ */
96 17633 : {
97 17633 : LCG(seeded) = 0;
98 17633 : }
99 : /* }}} */
100 :
101 : PHP_MINIT_FUNCTION(lcg) /* {{{ */
102 17633 : {
103 : #ifdef ZTS
104 : ts_allocate_id(&lcg_globals_id, sizeof(php_lcg_globals), (ts_allocate_ctor) lcg_init_globals, NULL);
105 : #else
106 17633 : lcg_init_globals(&lcg_globals);
107 : #endif
108 17633 : return SUCCESS;
109 : }
110 : /* }}} */
111 :
112 : /* {{{ proto float lcg_value()
113 : Returns a value from the combined linear congruential generator */
114 : PHP_FUNCTION(lcg_value)
115 102 : {
116 102 : RETURN_DOUBLE(php_combined_lcg(TSRMLS_C));
117 : }
118 : /* }}} */
119 :
120 : /*
121 : * Local variables:
122 : * tab-width: 4
123 : * c-basic-offset: 4
124 : * End:
125 : * vim600: sw=4 ts=4 fdm=marker
126 : * vim<600: sw=4 ts=4
127 : */
|