lcg.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 7 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2018 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. #include "php.h"
  19. #include "php_lcg.h"
  20. #if HAVE_UNISTD_H
  21. #include <unistd.h>
  22. #endif
  23. #ifdef PHP_WIN32
  24. #include "win32/time.h"
  25. #else
  26. #include <sys/time.h>
  27. #endif
  28. #ifdef ZTS
  29. int lcg_globals_id;
  30. #else
  31. static php_lcg_globals lcg_globals;
  32. #endif
  33. #ifdef PHP_WIN32
  34. #include <process.h>
  35. #endif
  36. /*
  37. * combinedLCG() returns a pseudo random number in the range of (0, 1).
  38. * The function combines two CGs with periods of
  39. * 2^31 - 85 and 2^31 - 249. The period of this function
  40. * is equal to the product of both primes.
  41. */
  42. #define MODMULT(a, b, c, m, s) q = s/a;s=b*(s-a*q)-c*q;if(s<0)s+=m
  43. static void lcg_seed(void);
  44. PHPAPI double php_combined_lcg(void) /* {{{ */
  45. {
  46. int32_t q;
  47. int32_t z;
  48. if (!LCG(seeded)) {
  49. lcg_seed();
  50. }
  51. MODMULT(53668, 40014, 12211, 2147483563L, LCG(s1));
  52. MODMULT(52774, 40692, 3791, 2147483399L, LCG(s2));
  53. z = LCG(s1) - LCG(s2);
  54. if (z < 1) {
  55. z += 2147483562;
  56. }
  57. return z * 4.656613e-10;
  58. }
  59. /* }}} */
  60. static void lcg_seed(void) /* {{{ */
  61. {
  62. struct timeval tv;
  63. if (gettimeofday(&tv, NULL) == 0) {
  64. LCG(s1) = tv.tv_sec ^ (tv.tv_usec<<11);
  65. } else {
  66. LCG(s1) = 1;
  67. }
  68. #ifdef ZTS
  69. LCG(s2) = (zend_long) tsrm_thread_id();
  70. #else
  71. LCG(s2) = (zend_long) getpid();
  72. #endif
  73. /* Add entropy to s2 by calling gettimeofday() again */
  74. if (gettimeofday(&tv, NULL) == 0) {
  75. LCG(s2) ^= (tv.tv_usec<<11);
  76. }
  77. LCG(seeded) = 1;
  78. }
  79. /* }}} */
  80. static void lcg_init_globals(php_lcg_globals *lcg_globals_p) /* {{{ */
  81. {
  82. LCG(seeded) = 0;
  83. }
  84. /* }}} */
  85. PHP_MINIT_FUNCTION(lcg) /* {{{ */
  86. {
  87. #ifdef ZTS
  88. ts_allocate_id(&lcg_globals_id, sizeof(php_lcg_globals), (ts_allocate_ctor) lcg_init_globals, NULL);
  89. #else
  90. lcg_init_globals(&lcg_globals);
  91. #endif
  92. return SUCCESS;
  93. }
  94. /* }}} */
  95. /* {{{ proto float lcg_value()
  96. Returns a value from the combined linear congruential generator */
  97. PHP_FUNCTION(lcg_value)
  98. {
  99. if (zend_parse_parameters_none() == FAILURE) {
  100. return;
  101. }
  102. RETURN_DOUBLE(php_combined_lcg());
  103. }
  104. /* }}} */
  105. /*
  106. * Local variables:
  107. * tab-width: 4
  108. * c-basic-offset: 4
  109. * End:
  110. * vim600: sw=4 ts=4 fdm=marker
  111. * vim<600: sw=4 ts=4
  112. */