erfc_scaled.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /* Implementation of the ERFC_SCALED intrinsic.
  2. Copyright (C) 2008-2022 Free Software Foundation, Inc.
  3. This file is part of the GNU Fortran runtime library (libgfortran).
  4. Libgfortran is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public
  6. License as published by the Free Software Foundation; either
  7. version 3 of the License, or (at your option) any later version.
  8. Libgfortran is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. Under Section 7 of GPL version 3, you are granted additional
  13. permissions described in the GCC Runtime Library Exception, version
  14. 3.1, as published by the Free Software Foundation.
  15. You should have received a copy of the GNU General Public License and
  16. a copy of the GCC Runtime Library Exception along with this program;
  17. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  18. <http://www.gnu.org/licenses/>. */
  19. #include "libgfortran.h"
  20. /* This implementation of ERFC_SCALED is based on the netlib algorithm
  21. available at http://www.netlib.org/specfun/erf */
  22. #ifdef HAVE_GFC_REAL_4
  23. #undef KIND
  24. #define KIND 4
  25. #include "erfc_scaled_inc.c"
  26. #endif
  27. #ifdef HAVE_GFC_REAL_8
  28. #undef KIND
  29. #define KIND 8
  30. #include "erfc_scaled_inc.c"
  31. #endif
  32. #ifdef HAVE_GFC_REAL_10
  33. #undef KIND
  34. #define KIND 10
  35. #include "erfc_scaled_inc.c"
  36. #endif
  37. #ifdef HAVE_GFC_REAL_16
  38. /* For quadruple-precision, netlib's implementation is
  39. not accurate enough. We provide another one. */
  40. #ifdef GFC_REAL_16_IS_FLOAT128
  41. # define _THRESH -106.566990228185312813205074546585730Q
  42. # define _M_2_SQRTPI M_2_SQRTPIq
  43. # define _INF __builtin_infq()
  44. # define _ERFC(x) erfcq(x)
  45. # define _EXP(x) expq(x)
  46. #else
  47. # define _THRESH -106.566990228185312813205074546585730L
  48. # ifndef M_2_SQRTPIl
  49. # define M_2_SQRTPIl 1.128379167095512573896158903121545172L
  50. # endif
  51. # define _M_2_SQRTPI M_2_SQRTPIl
  52. # define _INF __builtin_infl()
  53. # ifdef HAVE_ERFCL
  54. # define _ERFC(x) erfcl(x)
  55. # endif
  56. # ifdef HAVE_EXPL
  57. # define _EXP(x) expl(x)
  58. # endif
  59. #endif
  60. #define ERFC_SCALED(k) \
  61. GFC_REAL_ ## k \
  62. erfc_scaled_r ## k (GFC_REAL_ ## k x) \
  63. { \
  64. if (x < _THRESH) \
  65. { \
  66. return _INF; \
  67. } \
  68. if (x < 12) \
  69. { \
  70. /* Compute directly as ERFC_SCALED(x) = ERFC(x) * EXP(X**2). \
  71. This is not perfect, but much better than netlib. */ \
  72. return _ERFC(x) * _EXP(x * x); \
  73. } \
  74. else \
  75. { \
  76. /* Calculate ERFC_SCALED(x) using a power series in 1/x: \
  77. ERFC_SCALED(x) = 1 / (x * sqrt(pi)) \
  78. * (1 + Sum_n (-1)**n * (1 * 3 * 5 * ... * (2n-1)) \
  79. / (2 * x**2)**n) \
  80. */ \
  81. GFC_REAL_ ## k sum = 0, oldsum; \
  82. GFC_REAL_ ## k inv2x2 = 1 / (2 * x * x); \
  83. GFC_REAL_ ## k fac = 1; \
  84. int n = 1; \
  85. \
  86. while (n < 200) \
  87. { \
  88. fac *= - (2*n - 1) * inv2x2; \
  89. oldsum = sum; \
  90. sum += fac; \
  91. \
  92. if (sum == oldsum) \
  93. break; \
  94. \
  95. n++; \
  96. } \
  97. \
  98. return (1 + sum) / x * (_M_2_SQRTPI / 2); \
  99. } \
  100. }
  101. #if defined(_ERFC) && defined(_EXP)
  102. extern GFC_REAL_16 erfc_scaled_r16 (GFC_REAL_16);
  103. export_proto(erfc_scaled_r16);
  104. ERFC_SCALED(16)
  105. #endif
  106. #undef _THRESH
  107. #undef _M_2_SQRTPI
  108. #undef _INF
  109. #undef _ERFC
  110. #undef _EXP
  111. #endif
  112. #ifdef HAVE_GFC_REAL_17
  113. /* For quadruple-precision, netlib's implementation is
  114. not accurate enough. We provide another one. */
  115. # define _THRESH -106.566990228185312813205074546585730Q
  116. # define _M_2_SQRTPI M_2_SQRTPIq
  117. # define _INF __builtin_inff128()
  118. # ifdef POWER_IEEE128
  119. # define _ERFC(x) __erfcieee128(x)
  120. # define _EXP(x) __expieee128(x)
  121. # else
  122. # define _ERFC(x) erfcq(x)
  123. # define _EXP(x) expq(x)
  124. # endif
  125. extern GFC_REAL_17 erfc_scaled_r17 (GFC_REAL_17);
  126. export_proto(erfc_scaled_r17);
  127. ERFC_SCALED(17)
  128. #undef _THRESH
  129. #undef _M_2_SQRTPI
  130. #undef _INF
  131. #undef _ERFC
  132. #undef _EXP
  133. #undef ERFC_SCALED
  134. #endif