erfc_scaled.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /* Implementation of the ERFC_SCALED intrinsic.
  2. Copyright (C) 2008-2015 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. #if defined(_ERFC) && defined(_EXP)
  61. extern GFC_REAL_16 erfc_scaled_r16 (GFC_REAL_16);
  62. export_proto(erfc_scaled_r16);
  63. GFC_REAL_16
  64. erfc_scaled_r16 (GFC_REAL_16 x)
  65. {
  66. if (x < _THRESH)
  67. {
  68. return _INF;
  69. }
  70. if (x < 12)
  71. {
  72. /* Compute directly as ERFC_SCALED(x) = ERFC(x) * EXP(X**2).
  73. This is not perfect, but much better than netlib. */
  74. return _ERFC(x) * _EXP(x * x);
  75. }
  76. else
  77. {
  78. /* Calculate ERFC_SCALED(x) using a power series in 1/x:
  79. ERFC_SCALED(x) = 1 / (x * sqrt(pi))
  80. * (1 + Sum_n (-1)**n * (1 * 3 * 5 * ... * (2n-1))
  81. / (2 * x**2)**n)
  82. */
  83. GFC_REAL_16 sum = 0, oldsum;
  84. GFC_REAL_16 inv2x2 = 1 / (2 * x * x);
  85. GFC_REAL_16 fac = 1;
  86. int n = 1;
  87. while (n < 200)
  88. {
  89. fac *= - (2*n - 1) * inv2x2;
  90. oldsum = sum;
  91. sum += fac;
  92. if (sum == oldsum)
  93. break;
  94. n++;
  95. }
  96. return (1 + sum) / x * (_M_2_SQRTPI / 2);
  97. }
  98. }
  99. #endif
  100. #endif