lcg.c 2.8 KB

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