ran1.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * Copyright (c) 2008, Christian Mendl
  3. * All rights reserved.
  4. *
  5. */
  6. // Pseudo random number generator 'ran1' used in the stimulation program.
  7. #include <mex.h>
  8. #include <memory.h>
  9. const long NTAB = 32;
  10. // seed also contains 'static' variables used in 'ran1'
  11. struct Seed
  12. {
  13. long idum;
  14. long iy;
  15. long iv[NTAB];
  16. Seed()
  17. : idum(-1), iy(0) {
  18. }
  19. };
  20. // function declarations
  21. double ran1(Seed& seed); // random generator
  22. mxArray *Seed2Mat(const Seed& seed);
  23. void Mat2Seed(const mxArray *mat, Seed& seed);
  24. /* x = ran1(seed)
  25. * x = ran1(seed,n)
  26. * [x,seed] = ran1(seed)
  27. * [x,seed] = ran1(seed,n)
  28. * seed = ran1(seed,n,0)
  29. */
  30. void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
  31. {
  32. if (nrhs == 0 || nrhs > 3) mexErrMsgTxt("One, two or three input arguments required.");
  33. if (nlhs > 2) mexErrMsgTxt("Wrong number of output arguments.");
  34. if (nlhs > 1 && nrhs == 3) mexErrMsgTxt("One output argument expected given three input arguments.");
  35. Seed seed;
  36. if (mxIsDouble(prhs[0]))
  37. seed.idum = (long)mxGetScalar(prhs[0]);
  38. else if (mxIsInt32(prhs[0]))
  39. memcpy(&seed.idum, mxGetData(prhs[0]), sizeof(long));
  40. else if (mxIsStruct(prhs[0]))
  41. Mat2Seed(prhs[0], seed);
  42. else
  43. mexErrMsgTxt("Invalid class of input argument 'seed'.");
  44. // number of generated random numbers
  45. int n;
  46. if (nrhs < 2) n = 1;
  47. else {
  48. n = (int)mxGetScalar(prhs[1]);
  49. if (n < 1) mexErrMsgTxt("'n' must be a positive integer.");
  50. }
  51. if (nrhs <= 2)
  52. {
  53. // generate random numbers
  54. double *x = new double[n];
  55. for (int i = 0; i < n; i++)
  56. x[i] = ran1(seed);
  57. // copy output: random numbers
  58. plhs[0] = mxCreateDoubleMatrix(n, 1, mxREAL);
  59. memcpy(mxGetPr(plhs[0]), x, n*sizeof(double));
  60. delete [] x;
  61. // seed
  62. if (nlhs == 2) {
  63. plhs[1] = Seed2Mat(seed);
  64. }
  65. }
  66. else
  67. {
  68. // omit random numbers, just advance the seed value
  69. for (int i = 0; i < n; i++)
  70. ran1(seed);
  71. // copy output: seed
  72. plhs[0] = Seed2Mat(seed);
  73. }
  74. }
  75. // convert Matlab 'mxArray' to the 'seed' structure and vice versa
  76. inline void Mat2Seed(const mxArray *mat, Seed& seed)
  77. {
  78. // copy 'idum'
  79. mxArray *idum = mxGetField(mat, 0, "idum");
  80. if (!idum) mexErrMsgTxt("Structure field 'idum' not found.");
  81. if (!mxIsInt32(idum)) mexErrMsgTxt("Structure field 'idum' should be of class 'int32'.");
  82. memcpy(&seed.idum, mxGetData(idum), sizeof(seed.idum));
  83. // copy 'iy'
  84. mxArray *iy = mxGetField(mat, 0, "iy");
  85. if (!iy) mexErrMsgTxt("Structure field 'iy' not found.");
  86. if (!mxIsInt32(iy)) mexErrMsgTxt("Structure field 'iy' should be of class 'int32'.");
  87. memcpy(&seed.iy, mxGetData(iy), sizeof(seed.iy));
  88. // copy 'iv'
  89. mxArray *iv = mxGetField(mat, 0, "iv");
  90. if (!iv) mexErrMsgTxt("Structure field 'iv' not found.");
  91. if (!mxIsInt32(iv)) mexErrMsgTxt("Structure field 'iv' should be of class 'int32'.");
  92. if (!(mxGetM(iv) == NTAB && mxGetN(iv) == 1) && !(mxGetM(iv) == 1 && mxGetN(iv) == NTAB))
  93. mexErrMsgTxt("Wrong dimension of structure field 'iv'.");
  94. memcpy(&seed.iv, mxGetData(iv), sizeof(seed.iv));
  95. }
  96. inline mxArray *Seed2Mat(const Seed& seed)
  97. {
  98. // create seed structure fields
  99. mxArray *idum = mxCreateNumericMatrix(1, 1, mxINT32_CLASS, mxREAL);
  100. memcpy(mxGetData(idum), &seed.idum, sizeof(seed.idum));
  101. mxArray *iy = mxCreateNumericMatrix(1, 1, mxINT32_CLASS, mxREAL);
  102. memcpy(mxGetData(iy), &seed.iy, sizeof(seed.iy));
  103. mxArray *iv = mxCreateNumericMatrix(1, NTAB, mxINT32_CLASS, mxREAL);
  104. memcpy(mxGetData(iv), &seed.iv, sizeof(seed.iv));
  105. // create return value structure
  106. const char *fieldnames[] = { "idum", "iy", "iv" };
  107. mxArray *ret = mxCreateStructMatrix(1, 1, 3, fieldnames);
  108. mxSetFieldByNumber(ret, 0, 0, idum);
  109. mxSetFieldByNumber(ret, 0, 1, iy);
  110. mxSetFieldByNumber(ret, 0, 2, iv);
  111. return ret;
  112. }
  113. const long IA = 16807;
  114. const long IM = 2147483647;
  115. const double AM = 1.0/IM;
  116. const long IQ = 127773;
  117. const long IR = 2836;
  118. const long NDIV = 1+(IM-1)/NTAB;
  119. const double EPS = 1.2e-7;
  120. const double RNMX = 1.0-EPS;
  121. double ran1(Seed& seed)
  122. {
  123. int j;
  124. long k;
  125. // static long iy=0;
  126. // static long iv[NTAB];
  127. double temp;
  128. if (seed.idum <= 0 || !seed.iy) {
  129. if (-seed.idum < 1) seed.idum=1;
  130. else seed.idum = -seed.idum;
  131. for (j=NTAB+7;j>=0;j--) {
  132. k=seed.idum/IQ;
  133. seed.idum=IA*(seed.idum-k*IQ)-IR*k;
  134. if (seed.idum < 0) seed.idum += IM;
  135. if (j < NTAB) seed.iv[j] = seed.idum;
  136. }
  137. seed.iy=seed.iv[0];
  138. }
  139. k=(seed.idum)/IQ;
  140. seed.idum=IA*(seed.idum-k*IQ)-IR*k;
  141. if (seed.idum < 0) seed.idum += IM;
  142. j=seed.iy/NDIV;
  143. seed.iy=seed.iv[j];
  144. seed.iv[j] = seed.idum;
  145. if ((temp=AM*seed.iy) > RNMX) return RNMX;
  146. else return temp;
  147. }