Back to index

php5  5.3.10
lcg.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Sascha Schumann <sascha@schumann.cx>                         |
00016    +----------------------------------------------------------------------+
00017 */
00018 
00019 /* $Id: lcg.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #include "php.h"
00022 #include "php_lcg.h"
00023 
00024 #if HAVE_UNISTD_H
00025 #include <unistd.h>
00026 #endif
00027 
00028 #ifdef PHP_WIN32
00029 #include "win32/time.h"
00030 #else
00031 #include <sys/time.h>
00032 #endif
00033 
00034 #ifdef ZTS
00035 int lcg_globals_id;
00036 #else
00037 static php_lcg_globals lcg_globals;
00038 #endif
00039 
00040 #ifdef PHP_WIN32
00041 #include <process.h>
00042 #endif
00043 
00044 /*
00045  * combinedLCG() returns a pseudo random number in the range of (0, 1).
00046  * The function combines two CGs with periods of
00047  * 2^31 - 85 and 2^31 - 249. The period of this function
00048  * is equal to the product of both primes.
00049  */
00050 
00051 #define MODMULT(a, b, c, m, s) q = s/a;s=b*(s-a*q)-c*q;if(s<0)s+=m
00052 
00053 static void lcg_seed(TSRMLS_D);
00054 
00055 PHPAPI double php_combined_lcg(TSRMLS_D) /* {{{ */
00056 {
00057        php_int32 q;
00058        php_int32 z;
00059 
00060        if (!LCG(seeded)) {
00061               lcg_seed(TSRMLS_C);
00062        }
00063 
00064        MODMULT(53668, 40014, 12211, 2147483563L, LCG(s1));
00065        MODMULT(52774, 40692, 3791, 2147483399L, LCG(s2));
00066 
00067        z = LCG(s1) - LCG(s2);
00068        if (z < 1) {
00069               z += 2147483562;
00070        }
00071 
00072        return z * 4.656613e-10;
00073 }
00074 /* }}} */
00075 
00076 static void lcg_seed(TSRMLS_D) /* {{{ */
00077 {
00078        struct timeval tv;
00079 
00080        if (gettimeofday(&tv, NULL) == 0) {
00081               LCG(s1) = tv.tv_sec ^ (tv.tv_usec<<11);
00082        } else {
00083               LCG(s1) = 1;
00084        }
00085 #ifdef ZTS
00086        LCG(s2) = (long) tsrm_thread_id();
00087 #else
00088        LCG(s2) = (long) getpid();
00089 #endif
00090 
00091        /* Add entropy to s2 by calling gettimeofday() again */
00092        if (gettimeofday(&tv, NULL) == 0) {
00093               LCG(s2) ^= (tv.tv_usec<<11);
00094        }
00095 
00096        LCG(seeded) = 1;
00097 }
00098 /* }}} */
00099 
00100 static void lcg_init_globals(php_lcg_globals *lcg_globals_p TSRMLS_DC) /* {{{ */
00101 {
00102        LCG(seeded) = 0;
00103 }
00104 /* }}} */
00105 
00106 PHP_MINIT_FUNCTION(lcg) /* {{{ */
00107 {
00108 #ifdef ZTS
00109        ts_allocate_id(&lcg_globals_id, sizeof(php_lcg_globals), (ts_allocate_ctor) lcg_init_globals, NULL);
00110 #else
00111        lcg_init_globals(&lcg_globals);
00112 #endif
00113        return SUCCESS;
00114 }
00115 /* }}} */
00116 
00117 /* {{{ proto float lcg_value()
00118    Returns a value from the combined linear congruential generator */
00119 PHP_FUNCTION(lcg_value)
00120 {
00121        RETURN_DOUBLE(php_combined_lcg(TSRMLS_C));
00122 }
00123 /* }}} */
00124 
00125 /*
00126  * Local variables:
00127  * tab-width: 4
00128  * c-basic-offset: 4
00129  * End:
00130  * vim600: sw=4 ts=4 fdm=marker
00131  * vim<600: sw=4 ts=4
00132  */