xref: /PHP-7.0/ext/standard/lcg.c (revision 478f119a)
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