1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2017 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$ */
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(void);
54
php_combined_lcg(void)55 PHPAPI double php_combined_lcg(void) /* {{{ */
56 {
57 php_int32 q;
58 php_int32 z;
59
60 if (!LCG(seeded)) {
61 lcg_seed();
62 }
63
64 MODMULT(53668, 40014, 12211, 2147483563L, LCG(s1));
65 MODMULT(52774, 40692, 3791, 2147483399L, LCG(s2));
66
67 z = LCG(s1) - LCG(s2);
68 if (z < 1) {
69 z += 2147483562;
70 }
71
72 return z * 4.656613e-10;
73 }
74 /* }}} */
75
lcg_seed(void)76 static void lcg_seed(void) /* {{{ */
77 {
78 struct timeval tv;
79
80 if (gettimeofday(&tv, NULL) == 0) {
81 LCG(s1) = tv.tv_sec ^ (tv.tv_usec<<11);
82 } else {
83 LCG(s1) = 1;
84 }
85 #ifdef ZTS
86 LCG(s2) = (zend_long) tsrm_thread_id();
87 #else
88 LCG(s2) = (zend_long) getpid();
89 #endif
90
91 /* Add entropy to s2 by calling gettimeofday() again */
92 if (gettimeofday(&tv, NULL) == 0) {
93 LCG(s2) ^= (tv.tv_usec<<11);
94 }
95
96 LCG(seeded) = 1;
97 }
98 /* }}} */
99
lcg_init_globals(php_lcg_globals * lcg_globals_p)100 static void lcg_init_globals(php_lcg_globals *lcg_globals_p) /* {{{ */
101 {
102 LCG(seeded) = 0;
103 }
104 /* }}} */
105
PHP_MINIT_FUNCTION(lcg)106 PHP_MINIT_FUNCTION(lcg) /* {{{ */
107 {
108 #ifdef ZTS
109 ts_allocate_id(&lcg_globals_id, sizeof(php_lcg_globals), (ts_allocate_ctor) lcg_init_globals, NULL);
110 #else
111 lcg_init_globals(&lcg_globals);
112 #endif
113 return SUCCESS;
114 }
115 /* }}} */
116
117 /* {{{ proto float lcg_value()
118 Returns a value from the combined linear congruential generator */
PHP_FUNCTION(lcg_value)119 PHP_FUNCTION(lcg_value)
120 {
121 RETURN_DOUBLE(php_combined_lcg());
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 */
133