algo-680-erf.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /* algo-680-erf.f -- translated by f2c (version 20100827).
  2. This file no longer depends on f2c.
  3. */
  4. /* This routine isn't originally from SLATEC, but it makes sense to package it in. */
  5. #include "slatec-internal.hpp"
  6. /* ALGORITHM 680, COLLECTED ALGORITHMS FROM ACM. */
  7. /* THIS WORK PUBLISHED IN TRANSACTIONS ON MATHEMATICAL SOFTWARE, */
  8. /* VOL. 16, NO. 1, PP. 47. */
  9. int wofz_(double *xi, double *yi, double *u,
  10. double *v, logical *flag__)
  11. {
  12. /* System generated locals */
  13. double d__1, d__2;
  14. /* Local variables */
  15. logical a, b;
  16. double c__, h__;
  17. integer i__, j, n;
  18. double x, y, h2 = 0., u1, v1, u2, v2, w1;
  19. integer nu;
  20. double rx, ry, sx, sy, tx, ty;
  21. integer np1, kapn;
  22. double xabs, yabs, daux, qrho, xaux, xsum, ysum, xabsq, xquad, yquad;
  23. /* GIVEN A COMPLEX NUMBER Z = (XI,YI), THIS SUBROUTINE COMPUTES */
  24. /* THE VALUE OF THE FADDEEVA-FUNCTION W(Z) = EXP(-Z**2)*ERFC(-I*Z), */
  25. /* WHERE ERFC IS THE COMPLEX COMPLEMENTARY ERROR-FUNCTION AND I */
  26. /* MEANS SQRT(-1). */
  27. /* THE ACCURACY OF THE ALGORITHM FOR Z IN THE 1ST AND 2ND QUADRANT */
  28. /* IS 14 SIGNIFICANT DIGITS; IN THE 3RD AND 4TH IT IS 13 SIGNIFICANT */
  29. /* DIGITS OUTSIDE A CIRCULAR REGION WITH RADIUS 0.126 AROUND A ZERO */
  30. /* OF THE FUNCTION. */
  31. /* ALL REAL VARIABLES IN THE PROGRAM ARE DOUBLE PRECISION. */
  32. /* THE CODE CONTAINS A FEW COMPILER-DEPENDENT PARAMETERS : */
  33. /* RMAXREAL = THE MAXIMUM VALUE OF RMAXREAL EQUALS THE ROOT OF */
  34. /* RMAX = THE LARGEST NUMBER WHICH CAN STILL BE */
  35. /* IMPLEMENTED ON THE COMPUTER IN DOUBLE PRECISION */
  36. /* FLOATING-POINT ARITHMETIC */
  37. /* RMAXEXP = LN(RMAX) - LN(2) */
  38. /* RMAXGONI = THE LARGEST POSSIBLE ARGUMENT OF A DOUBLE PRECISION */
  39. /* GONIOMETRIC FUNCTION (DCOS, DSIN, ...) */
  40. /* THE REASON WHY THESE PARAMETERS ARE NEEDED AS THEY ARE DEFINED WILL */
  41. /* BE EXPLAINED IN THE CODE BY MEANS OF COMMENTS */
  42. /* PARAMETER LIST */
  43. /* XI = REAL PART OF Z */
  44. /* YI = IMAGINARY PART OF Z */
  45. /* U = REAL PART OF W(Z) */
  46. /* V = IMAGINARY PART OF W(Z) */
  47. /* FLAG = AN ERROR FLAG INDICATING WHETHER OVERFLOW WILL */
  48. /* OCCUR OR NOT; TYPE LOGICAL; */
  49. /* THE VALUES OF THIS VARIABLE HAVE THE FOLLOWING */
  50. /* MEANING : */
  51. /* FLAG=.FALSE. : NO ERROR CONDITION */
  52. /* FLAG=.TRUE. : OVERFLOW WILL OCCUR, THE ROUTINE */
  53. /* BECOMES INACTIVE */
  54. /* XI, YI ARE THE INPUT-PARAMETERS */
  55. /* U, V, FLAG ARE THE OUTPUT-PARAMETERS */
  56. /* FURTHERMORE THE PARAMETER FACTOR EQUALS 2/SQRT(PI) */
  57. /* THE ROUTINE IS NOT UNDERFLOW-PROTECTED BUT ANY VARIABLE CAN BE */
  58. /* PUT TO 0 UPON UNDERFLOW; */
  59. /* REFERENCE - GPM POPPE, CMJ WIJERS; MORE EFFICIENT COMPUTATION OF */
  60. /* THE COMPLEX ERROR-FUNCTION, ACM TRANS. MATH. SOFTWARE. */
  61. /* DOUBLE PRECISION D1MACH, FACTOR, RMAX, RMAXREAL, RMAXEXP */
  62. /* PARAMETER (FACTOR = 1.12837916709551257389615890312154517D0, */
  63. /* * RMAXREAL = 1.340780792994259D+154, */
  64. /* * RMAXEXP = 709.0895657128241D0, */
  65. /* * RMAXGONI = 0.6746518850690209D10) */
  66. /* RMAX = D1MACH(2) */
  67. /* RMAXREAL = DSQRT(RMAX) */
  68. /* RMAXEXP = DLOG(RMAX)-DLOG(2D0) */
  69. *flag__ = FALSE_;
  70. xabs = abs(*xi);
  71. yabs = abs(*yi);
  72. x = xabs / (float)6.3;
  73. y = yabs / (float)4.4;
  74. /* THE FOLLOWING IF-STATEMENT PROTECTS */
  75. /* QRHO = (X**2 + Y**2) AGAINST OVERFLOW */
  76. if (xabs > 5e153 || yabs > 5e153) {
  77. goto L100;
  78. }
  79. /* Computing 2nd power */
  80. d__1 = x;
  81. /* Computing 2nd power */
  82. d__2 = y;
  83. qrho = d__1 * d__1 + d__2 * d__2;
  84. /* Computing 2nd power */
  85. d__1 = xabs;
  86. xabsq = d__1 * d__1;
  87. /* Computing 2nd power */
  88. d__1 = yabs;
  89. xquad = xabsq - d__1 * d__1;
  90. yquad = xabs * 2 * yabs;
  91. a = qrho < .085264;
  92. if (a) {
  93. /* IF (QRHO.LT.0.085264D0) THEN THE FADDEEVA-FUNCTION IS EVALUATED */
  94. /* USING A POWER-SERIES (ABRAMOWITZ/STEGUN, EQUATION (7.1.5), P.297) */
  95. /* N IS THE MINIMUM NUMBER OF TERMS NEEDED TO OBTAIN THE REQUIRED */
  96. /* ACCURACY */
  97. qrho = (1 - y * (float).85) * sqrt(qrho);
  98. d__1 = qrho * 72 + 6;
  99. n = f2c::i_dnnt(&d__1);
  100. j = (n << 1) + 1;
  101. xsum = (float)1. / j;
  102. ysum = 0.;
  103. for (i__ = n; i__ >= 1; --i__) {
  104. j += -2;
  105. xaux = (xsum * xquad - ysum * yquad) / i__;
  106. ysum = (xsum * yquad + ysum * xquad) / i__;
  107. xsum = xaux + (float)1. / j;
  108. /* L10: */
  109. }
  110. u1 = (xsum * yabs + ysum * xabs) *
  111. -1.12837916709551257389615890312154517 + (float)1.;
  112. v1 = (xsum * xabs - ysum * yabs) *
  113. 1.12837916709551257389615890312154517;
  114. daux = exp(-xquad);
  115. u2 = daux * cos(yquad);
  116. v2 = -daux * sin(yquad);
  117. *u = u1 * u2 - v1 * v2;
  118. *v = u1 * v2 + v1 * u2;
  119. } else {
  120. /* IF (QRHO.GT.1.O) THEN W(Z) IS EVALUATED USING THE LAPLACE */
  121. /* CONTINUED FRACTION */
  122. /* NU IS THE MINIMUM NUMBER OF TERMS NEEDED TO OBTAIN THE REQUIRED */
  123. /* ACCURACY */
  124. /* IF ((QRHO.GT.0.085264D0).AND.(QRHO.LT.1.0)) THEN W(Z) IS EVALUATED */
  125. /* BY A TRUNCATED TAYLOR EXPANSION, WHERE THE LAPLACE CONTINUED FRACTION */
  126. /* IS USED TO CALCULATE THE DERIVATIVES OF W(Z) */
  127. /* KAPN IS THE MINIMUM NUMBER OF TERMS IN THE TAYLOR EXPANSION NEEDED */
  128. /* TO OBTAIN THE REQUIRED ACCURACY */
  129. /* NU IS THE MINIMUM NUMBER OF TERMS OF THE CONTINUED FRACTION NEEDED */
  130. /* TO CALCULATE THE DERIVATIVES WITH THE REQUIRED ACCURACY */
  131. if (qrho > (float)1.) {
  132. h__ = 0.;
  133. kapn = 0;
  134. qrho = sqrt(qrho);
  135. nu = (integer) (1442 / (qrho * 26 + 77) + 3);
  136. } else {
  137. qrho = (1 - y) * sqrt(1 - qrho);
  138. h__ = qrho * (float)1.88;
  139. h2 = h__ * 2;
  140. d__1 = qrho * 34 + 7;
  141. kapn = f2c::i_dnnt(&d__1);
  142. d__1 = qrho * 26 + 16;
  143. nu = f2c::i_dnnt(&d__1);
  144. }
  145. b = h__ > (float)0.;
  146. double qlambda = b ? f2c::pow_di(&h2, &kapn) : 0.; /* to avoid -Wmaybe-uninitialized */
  147. rx = (float)0.;
  148. ry = (float)0.;
  149. sx = (float)0.;
  150. sy = (float)0.;
  151. for (n = nu; n >= 0; --n) {
  152. np1 = n + 1;
  153. tx = yabs + h__ + np1 * rx;
  154. ty = xabs - np1 * ry;
  155. /* Computing 2nd power */
  156. d__1 = tx;
  157. /* Computing 2nd power */
  158. d__2 = ty;
  159. c__ = (float).5 / (d__1 * d__1 + d__2 * d__2);
  160. rx = c__ * tx;
  161. ry = c__ * ty;
  162. if (b && n <= kapn) {
  163. tx = qlambda + sx;
  164. sx = rx * tx - ry * sy;
  165. sy = ry * tx + rx * sy;
  166. qlambda /= h2;
  167. }
  168. /* L11: */
  169. }
  170. if (h__ == (float)0.) {
  171. *u = rx * 1.12837916709551257389615890312154517;
  172. *v = ry * 1.12837916709551257389615890312154517;
  173. } else {
  174. *u = sx * 1.12837916709551257389615890312154517;
  175. *v = sy * 1.12837916709551257389615890312154517;
  176. }
  177. if (yabs == (float)0.) {
  178. /* Computing 2nd power */
  179. d__1 = xabs;
  180. *u = exp(-(d__1 * d__1));
  181. }
  182. }
  183. /* EVALUATION OF W(Z) IN THE OTHER QUADRANTS */
  184. if (*yi < (float)0.) {
  185. if (a) {
  186. u2 *= 2;
  187. v2 *= 2;
  188. } else {
  189. xquad = -xquad;
  190. /* THE FOLLOWING IF-STATEMENT PROTECTS 2*EXP(-Z**2) */
  191. /* AGAINST OVERFLOW */
  192. if (yquad > 3537118876014220. || xquad > 708.503061461606) {
  193. goto L100;
  194. }
  195. w1 = exp(xquad) * 2;
  196. u2 = w1 * cos(yquad);
  197. v2 = -w1 * sin(yquad);
  198. }
  199. *u = u2 - *u;
  200. *v = v2 - *v;
  201. if (*xi > (float)0.) {
  202. *v = -(*v);
  203. }
  204. } else {
  205. if (*xi < (float)0.) {
  206. *v = -(*v);
  207. }
  208. }
  209. return 0;
  210. L100:
  211. *flag__ = TRUE_;
  212. return 0;
  213. } /* wofz_ */