source: sasmodels/sasmodels/models/lib/sas_erf.c @ 830cf6b

ticket-1257-vesicle-productticket_1156ticket_822_more_unit_tests
Last change on this file since 830cf6b was eb2946f, checked in by Paul Kienzle <pkienzle@…>, 7 years ago

improve precision of sasmodels special functions

  • Property mode set to 100644
File size: 6.8 KB
Line 
1
2/*
3 * Cephes Math Library Release 2.2:  June, 1992
4 * Copyright 1984, 1987, 1988, 1992 by Stephen L. Moshier
5 * Direct inquiries to 30 Frost Street, Cambridge, MA 02140
6 */
7/*
8 *
9 *      Error function
10 *
11 *
12 *
13 * SYNOPSIS:
14 *
15 * double x, y, erf();
16 *
17 * y = erf( x );
18 *
19 *
20 *
21 * DESCRIPTION:
22 *
23 * The integral is
24 *
25 *                           x
26 *                            -
27 *                 2         | |          2
28 *   erf(x)  =  --------     |    exp( - t  ) dt.
29 *              sqrt(pi)   | |
30 *                          -
31 *                           0
32 *
33 * For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise
34 * erf(x) = 1 - erfc(x).
35 *
36 *
37 *
38 * ACCURACY:
39 *
40 *                      Relative error:
41 * arithmetic   domain     # trials      peak         rms
42 *    IEEE      0,1         30000       3.7e-16     1.0e-16
43 *
44 */
45/*
46 *
47 *      Complementary error function
48 *
49 *
50 *
51 * SYNOPSIS:
52 *
53 * double x, y, erfc();
54 *
55 * y = erfc( x );
56 *
57 *
58 *
59 * DESCRIPTION:
60 *
61 *
62 *  1 - erf(x) =
63 *
64 *                           inf.
65 *                             -
66 *                  2         | |          2
67 *   erfc(x)  =  --------     |    exp( - t  ) dt
68 *               sqrt(pi)   | |
69 *                           -
70 *                            x
71 *
72 *
73 * For small x, erfc(x) = 1 - erf(x); otherwise rational
74 * approximations are computed.
75 *
76 *
77 *
78 * ACCURACY:
79 *
80 *                      Relative error:
81 * arithmetic   domain     # trials      peak         rms
82 *    IEEE      0,26.6417   30000       5.7e-14     1.5e-14
83 */
84
85#ifdef NEED_ERF
86
87#if FLOAT_SIZE>4  // DOUBLE_PRECISION
88
89double cephes_erf(double x);
90double cephes_erfc(double a);
91
92constant double PD[] = {
93    2.46196981473530512524E-10,
94    5.64189564831068821977E-1,
95    7.46321056442269912687E0,
96    4.86371970985681366614E1,
97    1.96520832956077098242E2,
98    5.26445194995477358631E2,
99    9.34528527171957607540E2,
100    1.02755188689515710272E3,
101    5.57535335369399327526E2
102};
103
104constant double QD[] = {
105    /* 1.00000000000000000000E0, */
106    1.32281951154744992508E1,
107    8.67072140885989742329E1,
108    3.54937778887819891062E2,
109    9.75708501743205489753E2,
110    1.82390916687909736289E3,
111    2.24633760818710981792E3,
112    1.65666309194161350182E3,
113    5.57535340817727675546E2
114};
115
116constant double RD[] = {
117    5.64189583547755073984E-1,
118    1.27536670759978104416E0,
119    5.01905042251180477414E0,
120    6.16021097993053585195E0,
121    7.40974269950448939160E0,
122    2.97886665372100240670E0
123};
124
125constant double SD[] = {
126    /* 1.00000000000000000000E0, */
127    2.26052863220117276590E0,
128    9.39603524938001434673E0,
129    1.20489539808096656605E1,
130    1.70814450747565897222E1,
131    9.60896809063285878198E0,
132    3.36907645100081516050E0
133};
134
135constant double TD[] = {
136    9.60497373987051638749E0,
137    9.00260197203842689217E1,
138    2.23200534594684319226E3,
139    7.00332514112805075473E3,
140    5.55923013010394962768E4
141};
142
143constant double UD[] = {
144    /* 1.00000000000000000000E0, */
145    3.35617141647503099647E1,
146    5.21357949780152679795E2,
147    4.59432382970980127987E3,
148    2.26290000613890934246E4,
149    4.92673942608635921086E4
150};
151
152double cephes_erfc(double a)
153{
154    double MAXLOG = 88.72283905206835;
155    double p, q, x, y, z;
156
157
158    x = fabs(a);
159
160    if (x < 1.0) {
161        // The line below causes problems on the GPU, so inline
162        // the erf function instead and z < 1.0.
163        //return (1.0 - cephes_erf(a));
164        // 2017-05-18 PAK - use erf(a) rather than erf(|a|)
165        z = a * a;
166        y = a * polevl(z, TD, 4) / p1evl(z, UD, 5);
167
168        return 1.0 - y;
169    }
170
171    z = -a * a;
172
173    if (z < -MAXLOG) {
174        if (a < 0)
175            return (2.0);
176        else
177            return (0.0);
178    }
179
180    z = exp(z);
181
182
183    if (x < 8.0) {
184        p = polevl(x, PD, 8);
185        q = p1evl(x, QD, 8);
186    }
187    else {
188        p = polevl(x, RD, 5);
189        q = p1evl(x, SD, 6);
190    }
191    y = (z * p) / q;
192
193    if (a < 0)
194        y = 2.0 - y;
195
196    if (y == 0.0) {
197        if (a < 0)
198            return (2.0);
199        else
200            return (0.0);
201    }
202    return y;
203}
204
205
206double cephes_erf(double x)
207{
208    double y, z;
209
210    if (fabs(x) > 1.0)
211        return (1.0 - cephes_erfc(x));
212
213    z = x * x;
214    y = x * polevl(z, TD, 4) / p1evl(z, UD, 5);
215
216    return y;
217}
218
219#else // SINGLE PRECISION
220
221float cephes_erff(float x);
222float cephes_erfcf(float a);
223
224/* erfc(x) = exp(-x^2) P(1/x), 1 < x < 2 */
225constant float PF[] = {
226    2.326819970068386E-002,
227    -1.387039388740657E-001,
228    3.687424674597105E-001,
229    -5.824733027278666E-001,
230    6.210004621745983E-001,
231    -4.944515323274145E-001,
232    3.404879937665872E-001,
233    -2.741127028184656E-001,
234    5.638259427386472E-001
235};
236
237/* erfc(x) = exp(-x^2) 1/x P(1/x^2), 2 < x < 14 */
238constant float RF[] = {
239    -1.047766399936249E+001,
240    1.297719955372516E+001,
241    -7.495518717768503E+000,
242    2.921019019210786E+000,
243    -1.015265279202700E+000,
244    4.218463358204948E-001,
245    -2.820767439740514E-001,
246    5.641895067754075E-001
247};
248
249/* erf(x) = x P(x^2), 0 < x < 1 */
250 constant float TF[] = {
251    7.853861353153693E-005,
252    -8.010193625184903E-004,
253    5.188327685732524E-003,
254    -2.685381193529856E-002,
255    1.128358514861418E-001,
256    -3.761262582423300E-001,
257    1.128379165726710E+000
258};
259
260
261float cephes_erfcf(float a)
262{
263    float MAXLOG = 88.72283905206835;
264    float p, q, x, y, z;
265
266
267    /*if (a < 0.0)
268        x = -a;
269    else
270        x = a;*/
271    // TODO: tinycc does not support fabsf
272    x = fabs(a);
273
274
275    if (x < 1.0) {
276        //The line below is a troublemaker for GPU, so sas_erf function
277        //is explicit here for the case < 1.0
278        //return (1.0 - sas_erf(a));
279        // 2017-05-18 PAK - use erf(a) rather than erf(|a|)
280        z = a * a;
281        y = a * polevl( z, TF, 6 );
282
283        return 1.0 - y;
284    }
285
286    z = -a * a;
287
288    if (z < -MAXLOG) {
289        if (a < 0)
290            return (2.0);
291        else
292            return (0.0);
293    }
294    z = expf(z);
295
296
297    q=1.0/x;
298    y=q*q;
299    if( x < 2.0 ) {
300        p = polevl( y, PF, 8 );
301    } else {
302        p = polevl( y, RF, 7 );
303    }
304    y = z * q * p;
305
306    if (a < 0)
307        y = 2.0 - y;
308
309    if (y == 0.0) {
310        if (a < 0)
311            return (2.0);
312        else
313            return (0.0);
314    }
315    return y;
316}
317
318
319float cephes_erff(float x)
320{
321    float y, z;
322
323    // TODO: tinycc does not support fabsf
324    if (fabs(x) > 1.0)
325        return (1.0 - cephes_erfcf(x));
326
327    z = x * x;
328    y = x * polevl( z, TF, 6 );
329
330    return y;
331}
332
333#endif // SINGLE_PRECISION
334
335#if FLOAT_SIZE>4
336//static double sas_erf(double x) { return erf(x); }
337//static double sas_erfc(double x) { return erfc(x); }
338#define sas_erf cephes_erf
339#define sas_erfc cephes_erfc
340#else
341#define sas_erf cephes_erff
342#define sas_erfc cephes_erfcf
343#endif
344
345#else // !NEED_ERF
346
347#if FLOAT_SIZE>4
348//static double sas_erf(double x) { return erf(x); }
349//static double sas_erfc(double x) { return erfc(x); }
350#define sas_erf erf
351#define sas_erfc erfc
352#else
353#define sas_erf erff
354#define sas_erfc erfcf
355#endif
356#endif // !NEED_ERF
Note: See TracBrowser for help on using the repository browser.