1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2007 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,v 1.41.2.1.2.1 2007/01/01 09:36:08 sebastian Exp $ */
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 :
41 : #ifdef PHP_WIN32
42 : #include <process.h>
43 : #endif
44 :
45 : /*
46 : * combinedLCG() returns a pseudo random number in the range of (0, 1).
47 : * The function combines two CGs with periods of
48 : * 2^31 - 85 and 2^31 - 249. The period of this function
49 : * is equal to the product of both primes.
50 : */
51 :
52 : #define MODMULT(a, b, c, m, s) q = s/a;s=b*(s-a*q)-c*q;if(s<0)s+=m
53 :
54 : static void lcg_seed(TSRMLS_D);
55 :
56 : PHPAPI double php_combined_lcg(TSRMLS_D)
57 7 : {
58 : php_int32 q;
59 : php_int32 z;
60 :
61 7 : if (!LCG(seeded)) {
62 0 : lcg_seed(TSRMLS_C);
63 : }
64 :
65 7 : MODMULT(53668, 40014, 12211, 2147483563L, LCG(s1));
66 7 : MODMULT(52774, 40692, 3791, 2147483399L, LCG(s2));
67 :
68 7 : z = LCG(s1) - LCG(s2);
69 7 : if (z < 1) {
70 2 : z += 2147483562;
71 : }
72 :
73 7 : return z * 4.656613e-10;
74 : }
75 :
76 : static void lcg_seed(TSRMLS_D)
77 219 : {
78 : struct timeval tv;
79 :
80 219 : if (gettimeofday(&tv, NULL) == 0) {
81 219 : 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 219 : LCG(s2) = (long) getpid();
89 : #endif
90 :
91 219 : LCG(seeded) = 1;
92 219 : }
93 :
94 : static void lcg_init_globals(php_lcg_globals *lcg_globals_p TSRMLS_DC)
95 220 : {
96 220 : LCG(seeded) = 0;
97 220 : }
98 :
99 : PHP_MINIT_FUNCTION(lcg)
100 220 : {
101 : #ifdef ZTS
102 : ts_allocate_id(&lcg_globals_id, sizeof(php_lcg_globals), (ts_allocate_ctor) lcg_init_globals, NULL);
103 : #else
104 220 : lcg_init_globals(&lcg_globals);
105 : #endif
106 220 : return SUCCESS;
107 : }
108 :
109 : PHP_RINIT_FUNCTION(lcg)
110 219 : {
111 219 : if (!LCG(seeded)) {
112 219 : lcg_seed(TSRMLS_C);
113 : }
114 219 : return SUCCESS;
115 : }
116 :
117 : /* {{{ proto float lcg_value()
118 : Returns a value from the combined linear congruential generator */
119 : PHP_FUNCTION(lcg_value)
120 0 : {
121 0 : RETURN_DOUBLE(php_combined_lcg(TSRMLS_C));
122 : }
123 : /* }}} */
124 :
125 : /*
126 : * Local variables:
127 : * tab-width: 4
128 : * c-basic-offset: 4
129 : * End:
130 : * vim600: sw=4 ts=4 fdm=marker
131 : * vim<600: sw=4 ts=4
132 : */
|