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