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 272374 2008-12-31 11:17: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 :
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 732 : {
58 : php_int32 q;
59 : php_int32 z;
60 :
61 732 : if (!LCG(seeded)) {
62 223 : lcg_seed(TSRMLS_C);
63 : }
64 :
65 732 : MODMULT(53668, 40014, 12211, 2147483563L, LCG(s1));
66 732 : MODMULT(52774, 40692, 3791, 2147483399L, LCG(s2));
67 :
68 732 : z = LCG(s1) - LCG(s2);
69 732 : if (z < 1) {
70 305 : z += 2147483562;
71 : }
72 :
73 732 : return z * 4.656613e-10;
74 : }
75 :
76 : static void lcg_seed(TSRMLS_D)
77 223 : {
78 : struct timeval tv;
79 :
80 223 : if (gettimeofday(&tv, NULL) == 0) {
81 223 : 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 223 : LCG(s2) = (long) getpid();
89 : #endif
90 :
91 223 : LCG(seeded) = 1;
92 223 : }
93 :
94 : static void lcg_init_globals(php_lcg_globals *lcg_globals_p TSRMLS_DC)
95 13565 : {
96 13565 : LCG(seeded) = 0;
97 13565 : }
98 :
99 : PHP_MINIT_FUNCTION(lcg)
100 13565 : {
101 : #ifdef ZTS
102 : ts_allocate_id(&lcg_globals_id, sizeof(php_lcg_globals), (ts_allocate_ctor) lcg_init_globals, NULL);
103 : #else
104 13565 : lcg_init_globals(&lcg_globals);
105 : #endif
106 13565 : return SUCCESS;
107 : }
108 :
109 : /* {{{ proto float lcg_value()
110 : Returns a value from the combined linear congruential generator */
111 : PHP_FUNCTION(lcg_value)
112 102 : {
113 102 : RETURN_DOUBLE(php_combined_lcg(TSRMLS_C));
114 : }
115 : /* }}} */
116 :
117 : /*
118 : * Local variables:
119 : * tab-width: 4
120 : * c-basic-offset: 4
121 : * End:
122 : * vim600: sw=4 ts=4 fdm=marker
123 : * vim<600: sw=4 ts=4
124 : */
|