1 /**
2 Computate Dawson, Voigt, and several error functions,
3 based on erfcx, im_w_of_x, w_of_z as implemented in separate files.
4 
5 Copyright:
6     © 2012 Massachusetts Institute of Technology,    
7     © 2013 Forschungszentrum Jülich GmbH,
8     © 2014 Ilya Yaroshenko
9  
10 Authors:
11     Steven G. Johnson, core author;
12     Joachim Wuttke, C package maintainer;
13     $(LINK2 http://plus.google.com/+IlyaYaroshenko, Ilya Yaroshenko), D package maintainer
14 
15 License: 
16     Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
17  */
18 module libcerf.err_fcts;
19 
20 import std.complex;
21 import std.math : isNaN, copysign, SQRT2, M_1_PI;
22 import core.stdc.math : sin, cos, erf, fabs, exp, erfc;
23 
24 import libcerf.w_of_z;
25 import libcerf.im_w_of_x;
26 import libcerf.erfcx_;
27 
28 version(unittest)
29 {
30     import libcerf.testutils;
31 }
32 
33 private enum double spi2 = 0.8862269254527580136490837416705725913990; // sqrt(pi)/2
34 private enum double s2pi = 2.5066282746310005024157652848110; // sqrt(2*pi)
35 
36 /**
37 Compute erfcx(z) = exp(z^2) erfc(z),
38 the complex underflow-compensated complementary error function,
39 trivially related to Faddeeva's w_of_z.
40 */
41 Complex!double cerfcx(Complex!double z) @safe @nogc nothrow
42 {
43     return w_of_z(Complex!double(-z.im, z.re));
44 }
45 
46 unittest
47 {
48     static immutable Z = [ Complex!double(1.234,0.5678) ];
49     static immutable W = [ 
50         Complex!double(0.3382187479799972294747793561190487832579,
51           -0.1116077470811648467464927471872945833154)
52     ];
53     commonTest!cerfcx(Z, W);
54 }
55 
56 /**
57 Compute erfi(z) = -i erf(iz), the rotated complex error function.
58 */
59 Complex!double cerfi(Complex!double z) @safe @nogc nothrow
60 {
61     Complex!double e = cerf(Complex!double(-z.im, z.re));
62     return Complex!double(e.im, -e.re);
63 }
64 
65 unittest
66 {
67     static immutable Z = [ Complex!double(1.234,0.5678) ];
68     static immutable W = [ 
69         Complex!double(1.081032284405373149432716643834106923212,
70           1.926775520840916645838949402886591180834)
71     ];
72     commonTest!cerfi(Z, W);
73 }
74 
75 /**
76 Compute erfi(x) = -i erf(ix), the imaginary error function.
77 */
78 double erfi(double x) @safe @nogc nothrow
79 {
80     immutable x2 = x*x;
81     return x2 > 720 ? copysign(double.infinity, x) : exp(x2) * im_w_of_x(x);
82 }
83 
84 unittest {
85     double[2][] tests = [
86         [0.0, 0],
87         [1.0, 1.65042575879754287602533772956136244389],
88         [-1.0, -1.65042575879754287602533772956136244389],
89         [5.0, 8.29827388067680351614622319074691995187273573754139844564e+9],
90         [-5.0, -8.29827388067680351614622319074691995187273573754139844564e+9],
91     ];
92     foreach(test; tests)
93     {
94         auto x = test[0];
95         auto t = erfi(x);
96         auto y = test[1];
97         assert(relativeErrorCheck(t, y));
98     }
99 }
100 
101 /**
102 Compute dawson(x) = sqrt(pi)/2 * exp(-x^2) * erfi(x),
103 Dawson's integral for a real argument.
104 */
105 double dawson(double x) @safe @nogc nothrow
106 {
107     return spi2 * im_w_of_x(x);
108 }
109 
110 /**
111 Compute Voigt's convolution of a Gaussian
112 G(x,sigma) = 1/sqrt(2*pi)/|sigma| * exp(-x^2/2/sigma^2)
113 and a Lorentzian
114 L(x,gamma) = |gamma| / pi / ( x^2 + gamma^2 ),
115 namely
116 voigt(x,sigma,gamma) =
117       \int_{-infty}^{infty} dx' G(x',sigma) L(x-x',gamma)
118 using the relation
119 voigt(x,sigma,gamma) = Re{ w(z) } / sqrt(2*pi) / |sigma|
120 with
121 z = (x+i*|gamma|) / sqrt(2) / |sigma|.
122 
123 Reference: Abramowitz&Stegun (1964), formula (7.4.13).
124 */
125 //Joachim Wuttke, January 2013.
126 double voigt( double x, double sigma, double gamma ) @safe @nogc nothrow
127 {
128 
129     immutable gam = fabs(gamma);
130     immutable sig = fabs(sigma);
131 
132     if (!gam) {
133         if (!sig) {
134             // It's kind of a delta function
135             return x ? 0 : double.infinity;
136         } else {
137             // It's a pure Gaussian
138             return exp( -x*x/2/(sig*sig) ) / s2pi / sig;
139         }
140     } else {
141         if (!sig) {
142             // It's a pure Lorentzian
143             return gam * M_1_PI / (x*x + gam*gam);
144         } else {
145             // Regular case, both parameters are nonzero
146             Complex!double z = Complex!double(x,gam) / double(SQRT2) / sig;
147             return  w_of_z(z).re / s2pi / sig;
148         }
149     }
150 }
151 
152 /**
153 Compute erf(z), the complex error function,
154 using w_of_z except for certain regions.
155 */
156 //Steven G. Johnson, October 2012.
157 Complex!double cerf(Complex!double z) @safe @nogc nothrow
158 {
159     immutable x = z.re, y = z.im;
160 
161     if (!y)
162         return Complex!double(erf(x), y); // preserve sign of 0
163     if (!x) // handle separately for speed & handling of y = Inf or NaN
164         return Complex!double(x, // preserve sign of 0
165                  /* handle y -> Inf limit manually, since
166                     exp(y^2) -> Inf but Im[w(y)] -> 0, so
167                     IEEE will give us a NaN when it should be Inf */
168                  y*y > 720 ? copysign(double.infinity, y)
169                  : exp(y*y) * im_w_of_x(y));
170   
171     immutable mRe_z2 = (y - x) * (x + y); // Re(-z^2), being careful of overflow
172     immutable mIm_z2 = -2*x*y; // Im(-z^2)
173     if (mRe_z2 < -750) // underflow
174         return Complex!double(copysign(1.0, x), 0.0);
175 
176     /* Handle positive and negative x via different formulas,
177        using the mirror symmetries of w, to avoid overflow/underflow
178        problems from multiplying exponentially large and small quantities. */
179     if (x >= 0) {
180         if (x < 8e-2) {
181             if (fabs(y) < 1e-2)
182                 goto taylor;
183             else if (fabs(mIm_z2) < 5e-3 && x < 5e-3)
184                 goto taylor_erfi;
185         }
186         /* don't use complex exp function, since that will produce spurious NaN
187            values when multiplying w in an overflow situation. */
188         return 1.0 - exp(mRe_z2) *
189             (Complex!double(cos(mIm_z2), sin(mIm_z2))
190              * w_of_z(Complex!double(-y,x)));
191     }
192     else { // x < 0
193         if (x > -8e-2) { // duplicate from above to avoid fabs(x) call
194             if (fabs(y) < 1e-2)
195                 goto taylor;
196             else if (fabs(mIm_z2) < 5e-3 && x > -5e-3)
197                 goto taylor_erfi;
198         }
199         else if (isNaN(x))
200             return Complex!double(double.nan, y == 0 ? 0 : double.nan);
201         /* don't use complex exp function, since that will produce spurious NaN
202            values when multiplying w in an overflow situation. */
203         return exp(mRe_z2) *
204             (Complex!double(cos(mIm_z2), sin(mIm_z2))
205              * w_of_z(Complex!double(y,-x))) - 1.0;
206     }
207 
208     // Use Taylor series for small |z|, to avoid cancellation inaccuracy
209     //   erf(z) = 2/sqrt(pi) * z * (1 - z^2/3 + z^4/10 - z^6/42 + z^8/216 + ...)
210 taylor:
211     Complex!double mz2 = Complex!double(mRe_z2, mIm_z2); // -z^2
212     return z * (1.1283791670955125739
213                 + mz2 * (0.37612638903183752464
214                          + mz2 * (0.11283791670955125739
215                                   + mz2 * (0.026866170645131251760
216                                            + mz2 * 0.0052239776254421878422))));
217 
218     /* for small |x| and small |xy|, 
219        use Taylor series to avoid cancellation inaccuracy:
220        erf(x+iy) = erf(iy)
221        + 2*exp(y^2)/sqrt(pi) *
222        [ x * (1 - x^2 * (1+2y^2)/3 + x^4 * (3+12y^2+4y^4)/30 + ... 
223        - i * x^2 * y * (1 - x^2 * (3+2y^2)/6 + ...) ]
224        where:
225        erf(iy) = exp(y^2) * Im[w(y)]
226     */
227 taylor_erfi:
228     double x2 = x*x, y2 = y*y;
229     double expy2 = exp(y2);
230     return Complex!double
231         (expy2 * x * (1.1283791670955125739
232                       - x2 * (0.37612638903183752464
233                               + 0.75225277806367504925*y2)
234                       + x2*x2 * (0.11283791670955125739
235                                  + y2 * (0.45135166683820502956
236                                          + 0.15045055561273500986*y2))),
237          expy2 * (im_w_of_x(y)
238                   - x2*y * (1.1283791670955125739 
239                             - x2 * (0.56418958354775628695 
240                                     + 0.37612638903183752464*y2))));
241 }
242 
243 unittest
244 {
245     static immutable Z = [
246         Complex!double(1,2),
247         Complex!double(-1,2),
248         Complex!double(1,-2),
249         Complex!double(-1,-2),
250         Complex!double(9,-28),
251         Complex!double(21,-33),
252         Complex!double(1e3,1e3),
253         Complex!double(-3001,-1000),
254         Complex!double(1e160,-1e159),
255         Complex!double(5.1e-3, 1e-8),
256         Complex!double(-4.9e-3, 4.95e-3),
257         Complex!double(4.9e-3, 0.5),
258         Complex!double(4.9e-4, -0.5e1),
259         Complex!double(-4.9e-5, -0.5e2),
260         Complex!double(5.1e-3, 0.5),
261         Complex!double(5.1e-4, -0.5e1),
262         Complex!double(-5.1e-5, -0.5e2),
263         Complex!double(1e-6,2e-6),
264         Complex!double(0,2e-6),
265         Complex!double(0,2),
266         Complex!double(0,20),
267         Complex!double(0,200),
268         Complex!double(double.infinity,0),
269         Complex!double(-double.infinity,0),
270         Complex!double(0,double.infinity),
271         Complex!double(0,-double.infinity),
272         Complex!double(double.infinity,double.infinity),
273         Complex!double(double.infinity,-double.infinity),
274         Complex!double(double.nan,double.nan),
275         Complex!double(double.nan,0),
276         Complex!double(0,double.nan),
277         Complex!double(double.nan,double.infinity),
278         Complex!double(double.infinity,double.nan),
279         Complex!double(1e-3,double.nan),
280         Complex!double(7e-2,7e-2),
281         Complex!double(7e-2,-7e-4),
282         Complex!double(-9e-2,7e-4),
283         Complex!double(-9e-2,9e-2),
284         Complex!double(-7e-4,9e-2),
285         Complex!double(7e-2,0.9e-2),
286         Complex!double(7e-2,1.1e-2)
287     ];
288     static immutable W = [ 
289         Complex!double(-0.5366435657785650339917955593141927494421,
290           -5.049143703447034669543036958614140565553),
291         Complex!double(0.5366435657785650339917955593141927494421,
292           -5.049143703447034669543036958614140565553),
293         Complex!double(-0.5366435657785650339917955593141927494421,
294           5.049143703447034669543036958614140565553),
295         Complex!double(0.5366435657785650339917955593141927494421,
296           5.049143703447034669543036958614140565553),
297         Complex!double(0.3359473673830576996788000505817956637777e304,
298           -0.1999896139679880888755589794455069208455e304),
299         Complex!double(0.3584459971462946066523939204836760283645e278,
300           0.3818954885257184373734213077678011282505e280),
301         Complex!double(0.9996020422657148639102150147542224526887,
302           0.00002801044116908227889681753993542916894856),
303         Complex!double(-1, 0),
304         Complex!double(1, 0),
305         Complex!double(0.005754683859034800134412990541076554934877,
306           0.1128349818335058741511924929801267822634e-7),
307         Complex!double(-0.005529149142341821193633460286828381876955,
308           0.005585388387864706679609092447916333443570),
309         Complex!double(0.007099365669981359632319829148438283865814,
310           0.6149347012854211635026981277569074001219),
311         Complex!double(0.3981176338702323417718189922039863062440e8,
312           -0.8298176341665249121085423917575122140650e10),
313         Complex!double(-double.infinity,
314           -double.infinity),
315         Complex!double(0.007389128308257135427153919483147229573895,
316           0.6149332524601658796226417164791221815139),
317         Complex!double(0.4143671923267934479245651547534414976991e8,
318           -0.8298168216818314211557046346850921446950e10),
319         Complex!double(-double.infinity,
320           -double.infinity),
321         Complex!double(0.1128379167099649964175513742247082845155e-5,
322           0.2256758334191777400570377193451519478895e-5),
323         Complex!double(0,
324           0.2256758334194034158904576117253481476197e-5),
325         Complex!double(0,
326           18.56480241457555259870429191324101719886),
327         Complex!double(0,
328           0.1474797539628786202447733153131835124599e173),
329         Complex!double(0,
330           double.infinity),
331         Complex!double(1,0),
332         Complex!double(-1,0),
333         Complex!double(0,double.infinity),
334         Complex!double(0,-double.infinity),
335         Complex!double(double.nan,double.nan),
336         Complex!double(double.nan,double.nan),
337         Complex!double(double.nan,double.nan),
338         Complex!double(double.nan,0),
339         Complex!double(0,double.nan),
340         Complex!double(double.nan,double.nan),
341         Complex!double(double.nan,double.nan),
342         Complex!double(double.nan,double.nan),
343         Complex!double(0.07924380404615782687930591956705225541145,
344           0.07872776218046681145537914954027729115247),
345         Complex!double(0.07885775828512276968931773651224684454495,
346           -0.0007860046704118224342390725280161272277506),
347         Complex!double(-0.1012806432747198859687963080684978759881,
348           0.0007834934747022035607566216654982820299469),
349         Complex!double(-0.1020998418798097910247132140051062512527,
350           0.1010030778892310851309082083238896270340),
351         Complex!double(-0.0007962891763147907785684591823889484764272,
352           0.1018289385936278171741809237435404896152),
353         Complex!double(0.07886408666470478681566329888615410479530,
354           0.01010604288780868961492224347707949372245),
355         Complex!double(0.07886723099940260286824654364807981336591,
356           0.01235199327873258197931147306290916629654)
357     ];
358     commonTest!cerf(Z, W);
359 }
360 
361 
362 /**
363 Compute erfc(z) = 1 - erf(z), the complex complementary error function,
364 using w_of_z except for certain regions.
365 */
366 //Steven G. Johnson, October 2012.
367 Complex!double cerfc(Complex!double z) @safe @nogc nothrow
368 {
369 
370     immutable x = z.re, y = z.im;
371 
372     if (!x)
373         return Complex!double(1,
374                  /* handle y -> Inf limit manually, since
375                     exp(y^2) -> Inf but Im[w(y)] -> 0, so
376                     IEEE will give us a double.nan when it should be Inf */
377                  y*y > 720 ? -copysign(double.infinity, y)
378                  : -exp(y*y) * im_w_of_x(y));
379     if (!y) {
380         if (x*x > 750) // underflow
381             return Complex!double(x >= 0 ? 0.0 : 2.0,
382                      -y); // preserve sign of 0
383         return Complex!double(x >= 0 ? exp(-x*x) * erfcx(x) 
384                  : 2. - exp(-x*x) * erfcx(-x),
385                  -y); // preserve sign of zero
386     }
387 
388     immutable mRe_z2 = (y - x) * (x + y); // Re(-z^2), being careful of overflow
389     immutable mIm_z2 = -2*x*y; // Im(-z^2)
390     if (mRe_z2 < -750) // underflow
391         return Complex!double(x >= 0 ? 0.0 : 2.0, 0);
392 
393     if (x >= 0)
394         return cexp(Complex!double(mRe_z2, mIm_z2))
395             * w_of_z(Complex!double(-y,x));
396     else
397         return 2.0 - cexp(Complex!double(mRe_z2, mIm_z2))
398             * w_of_z(Complex!double(y,-x));
399 }
400 
401 unittest
402 {
403     static immutable Z = [
404         Complex!double(1,2),
405         Complex!double(-1,2),
406         Complex!double(1,-2),
407         Complex!double(-1,-2),
408         Complex!double(9,-28),
409         Complex!double(21,-33),
410         Complex!double(1e3,1e3),
411         Complex!double(-3001,-1000),
412         Complex!double(1e160,-1e159),
413         Complex!double(5.1e-3, 1e-8),
414         Complex!double(0,2e-6),
415         Complex!double(0,2),
416         Complex!double(0,20),
417         Complex!double(0,200),
418         Complex!double(2e-6,0),
419         Complex!double(2,0),
420         Complex!double(20,0),
421         Complex!double(200,0),
422         Complex!double(double.infinity,0),
423         Complex!double(-double.infinity,0),
424         Complex!double(0,double.infinity),
425         Complex!double(0,-double.infinity),
426         Complex!double(double.infinity,double.infinity),
427         Complex!double(double.infinity,-double.infinity),
428         Complex!double(double.nan,double.nan),
429         Complex!double(double.nan,0),
430         Complex!double(0,double.nan),
431         Complex!double(double.nan,double.infinity),
432         Complex!double(double.infinity,double.nan),
433         Complex!double(88,0)
434     ];
435     static immutable W = [
436         Complex!double(1.536643565778565033991795559314192749442,
437           5.049143703447034669543036958614140565553),
438         Complex!double(0.4633564342214349660082044406858072505579,
439           5.049143703447034669543036958614140565553),
440         Complex!double(1.536643565778565033991795559314192749442,
441           -5.049143703447034669543036958614140565553),
442         Complex!double(0.4633564342214349660082044406858072505579,
443           -5.049143703447034669543036958614140565553),
444         Complex!double(-0.3359473673830576996788000505817956637777e304,
445           0.1999896139679880888755589794455069208455e304),
446         Complex!double(-0.3584459971462946066523939204836760283645e278,
447           -0.3818954885257184373734213077678011282505e280),
448         Complex!double(0.0003979577342851360897849852457775473112748,
449           -0.00002801044116908227889681753993542916894856),
450         Complex!double(2, 0),
451         Complex!double(0, 0),
452         Complex!double(0.9942453161409651998655870094589234450651,
453           -0.1128349818335058741511924929801267822634e-7),
454         Complex!double(1,
455           -0.2256758334194034158904576117253481476197e-5),
456         Complex!double(1,
457           -18.56480241457555259870429191324101719886),
458         Complex!double(1,
459           -0.1474797539628786202447733153131835124599e173),
460         Complex!double(1, -double.infinity),
461         Complex!double(0.9999977432416658119838633199332831406314,
462           0),
463         Complex!double(0.004677734981047265837930743632747071389108,
464           0),
465         Complex!double(0.5395865611607900928934999167905345604088e-175,
466           0),
467         Complex!double(0, 0),
468         Complex!double(0, 0),
469         Complex!double(2, 0),
470         Complex!double(1, -double.infinity),
471         Complex!double(1, double.infinity),
472         Complex!double(double.nan, double.nan),
473         Complex!double(double.nan, double.nan),
474         Complex!double(double.nan, double.nan),
475         Complex!double(double.nan, 0),
476         Complex!double(1, double.nan),
477         Complex!double(double.nan, double.nan),
478         Complex!double(double.nan, double.nan),
479         Complex!double(0,0)
480     ];
481     commonTest!cerfc(Z, W);
482 }
483 
484 /**
485 Compute Dawson(z) = sqrt(pi)/2  *  exp(-z^2) * erfi(z),
486 Dawson's integral for a complex argument,
487 using w_of_z except for certain regions.
488 */
489 //Steven G. Johnson, October 2012.
490 Complex!double cdawson(Complex!double z) @safe @nogc nothrow
491 {
492 
493     immutable x = z.re, y = z.im;
494 
495     // handle axes separately for speed & proper handling of x or y = Inf or double.nan
496     if (!y)
497         return Complex!double(spi2 * im_w_of_x(x), -y); // preserve sign of 0
498     if (!x) {
499         immutable y2 = y*y;
500         if (y2 < 2.5e-5) { // Taylor expansion
501             return Complex!double(x, // preserve sign of 0
502                      y * (1.
503                           + y2 * (0.6666666666666666666666666666666666666667
504                                   + y2 * 0.26666666666666666666666666666666666667)));
505         }
506         return Complex!double(x, // preserve sign of 0
507                  spi2 * (y >= 0 
508                          ? exp(y2) - erfcx(y)
509                          : erfcx(-y) - exp(y2)));
510     }
511 
512     immutable mRe_z2 = (y - x) * (x + y); // Re(-z^2), being careful of overflow
513     immutable mIm_z2 = -2*x*y; // Im(-z^2)
514     Complex!double mz2 = Complex!double(mRe_z2, mIm_z2); // -z^2
515 
516     /* Handle positive and negative x via different formulas,
517        using the mirror symmetries of w, to avoid overflow/underflow
518        problems from multiplying exponentially large and small quantities. */
519     if (y >= 0) {
520         if (fabs(y) < 5e-3) {
521             if (fabs(x) < 5e-3)
522                 goto taylor;
523             else if (fabs(mIm_z2) < 5e-3)
524                 goto taylor_realaxis;
525         }
526         Complex!double res = cexp(mz2) - w_of_z(z);
527         return spi2 * Complex!double(-res.im, res.re);
528     }
529     else { // y < 0
530         if (y > -5e-3) { // duplicate from above to avoid fabs(x) call
531             if (fabs(x) < 5e-3)
532                 goto taylor;
533             else if (fabs(mIm_z2) < 5e-3)
534                 goto taylor_realaxis;
535         }
536         else if (isNaN(y))
537             return Complex!double(!x ? 0 : double.nan, double.nan);
538         Complex!double res = w_of_z(-z) - cexp(mz2);
539         return spi2 * Complex!double(-res.im, res.re);
540     }
541 
542     // Use Taylor series for small |z|, to avoid cancellation inaccuracy
543     //     dawson(z) = z - 2/3 z^3 + 4/15 z^5 + ...
544 taylor:
545     return z * (1.
546                 + mz2 * (0.6666666666666666666666666666666666666667
547                          + mz2 * 0.2666666666666666666666666666666666666667));
548 
549     /* for small |y| and small |xy|, 
550        use Taylor series to avoid cancellation inaccuracy:
551        dawson(x + iy)
552        = D + y^2 (D + x - 2Dx^2)
553        + y^4 (D/2 + 5x/6 - 2Dx^2 - x^3/3 + 2Dx^4/3)
554        + iy [ (1-2Dx) + 2/3 y^2 (1 - 3Dx - x^2 + 2Dx^3)
555        + y^4/15 (4 - 15Dx - 9x^2 + 20Dx^3 + 2x^4 - 4Dx^5) ] + ...
556        where D = dawson(x) 
557 
558        However, for large |x|, 2Dx -> 1 which gives cancellation problems in
559        this series (many of the leading terms cancel).  So, for large |x|,
560        we need to substitute a continued-fraction expansion for D.
561 
562        dawson(x) = 0.5 / (x-0.5/(x-1/(x-1.5/(x-2/(x-2.5/(x...))))))
563 
564        The 6 terms shown here seems to be the minimum needed to be
565        accurate as soon as the simpler Taylor expansion above starts
566        breaking down.  Using this 6-term expansion, factoring out the
567        denominator, and simplifying with Maple, we obtain:
568 
569        Re dawson(x + iy) * (-15 + 90x^2 - 60x^4 + 8x^6) / x
570        = 33 - 28x^2 + 4x^4 + y^2 (18 - 4x^2) + 4 y^4
571        Im dawson(x + iy) * (-15 + 90x^2 - 60x^4 + 8x^6) / y
572        = -15 + 24x^2 - 4x^4 + 2/3 y^2 (6x^2 - 15) - 4 y^4
573 
574        Finally, for |x| > 5e7, we can use a simpler 1-term continued-fraction
575        expansion for the real part, and a 2-term expansion for the imaginary
576        part.  (This avoids overflow problems for huge |x|.)  This yields:
577      
578        Re dawson(x + iy) = [1 + y^2 (1 + y^2/2 - (xy)^2/3)] / (2x)
579        Im dawson(x + iy) = y [ -1 - 2/3 y^2 + y^4/15 (2x^2 - 4) ] / (2x^2 - 1)
580 
581     */
582 taylor_realaxis:
583     immutable x2 = x*x;
584     if (x2 > 1600) // |x| > 40
585     { 
586         immutable y2 = y*y;
587         if (x2 > 25e14) {// |x| > 5e7
588             immutable xy2 = (x*y)*(x*y);
589             return Complex!double((0.5 + y2 * (0.5 + 0.25*y2
590                                   - 0.16666666666666666667*xy2)) / x,
591                      y * (-1 + y2 * (-0.66666666666666666667
592                                      + 0.13333333333333333333*xy2
593                                      - 0.26666666666666666667*y2))
594                      / (2*x2 - 1));
595         }
596         return (1. / (-15 + x2*(90 + x2*(-60 + 8*x2)))) *
597             Complex!double(x * (33 + x2 * (-28 + 4*x2)
598                    + y2 * (18 - 4*x2 + 4*y2)),
599               y * (-15 + x2 * (24 - 4*x2)
600                    + y2 * (4*x2 - 10 - 4*y2)));
601     }
602     else 
603     {
604         immutable D = spi2 * im_w_of_x(x);
605         immutable y2 = y*y;
606         return Complex!double
607             (D + y2 * (D + x - 2*D*x2)
608              + y2*y2 * (D * (0.5 - x2 * (2 - 0.66666666666666666667*x2))
609                         + x * (0.83333333333333333333
610                                - 0.33333333333333333333 * x2)),
611              y * (1 - 2*D*x
612                   + y2 * 0.66666666666666666667 * (1 - x2 - D*x * (3 - 2*x2))
613                   + y2*y2 * (0.26666666666666666667 -
614                              x2 * (0.6 - 0.13333333333333333333 * x2)
615                              - D*x * (1 - x2 * (1.3333333333333333333
616                                                 - 0.26666666666666666667 * x2)))));
617     }
618 }
619 
620 unittest
621 {
622     static immutable Z = [
623         Complex!double(2,1),
624         Complex!double(-2,1),
625         Complex!double(2,-1),
626         Complex!double(-2,-1),
627         Complex!double(-28,9),
628         Complex!double(33,-21),
629         Complex!double(1e3,1e3),
630         Complex!double(-1000,-3001),
631         Complex!double(1e-8, 5.1e-3),
632         Complex!double(4.95e-3, -4.9e-3),
633         Complex!double(5.1e-3, 5.1e-3),
634         Complex!double(0.5, 4.9e-3),
635         Complex!double(-0.5e1, 4.9e-4),
636         Complex!double(-0.5e2, -4.9e-5),
637         Complex!double(0.5e3, 4.9e-6),
638         Complex!double(0.5, 5.1e-3),
639         Complex!double(-0.5e1, 5.1e-4),
640         Complex!double(-0.5e2, -5.1e-5),
641         Complex!double(1e-6,2e-6),
642         Complex!double(2e-6,0),
643         Complex!double(2,0),
644         Complex!double(20,0),
645         Complex!double(200,0),
646         Complex!double(0,4.9e-3),
647         Complex!double(0,-5.1e-3),
648         Complex!double(0,2e-6),
649         Complex!double(0,-2),
650         Complex!double(0,20),
651         Complex!double(0,-200),
652         Complex!double(double.infinity,0),
653         Complex!double(-double.infinity,0),
654         Complex!double(0,double.infinity),
655         Complex!double(0,-double.infinity),
656         Complex!double(double.infinity,double.infinity),
657         Complex!double(double.infinity,-double.infinity),
658         Complex!double(double.nan,double.nan),
659         Complex!double(double.nan,0),
660         Complex!double(0,double.nan),
661         Complex!double(double.nan,double.infinity),
662         Complex!double(double.infinity,double.nan),
663         Complex!double(39, 6.4e-5),
664         Complex!double(41, 6.09e-5),
665         Complex!double(4.9e7, 5e-11),
666         Complex!double(5.1e7, 4.8e-11),
667         Complex!double(1e9, 2.4e-12),
668         Complex!double(1e11, 2.4e-14),
669         Complex!double(1e13, 2.4e-16),
670         Complex!double(1e300, 2.4e-303)
671     ];
672     static immutable W = [
673         Complex!double(0.1635394094345355614904345232875688576839,
674           -0.1531245755371229803585918112683241066853),
675         Complex!double(-0.1635394094345355614904345232875688576839,
676           -0.1531245755371229803585918112683241066853),
677         Complex!double(0.1635394094345355614904345232875688576839,
678           0.1531245755371229803585918112683241066853),
679         Complex!double(-0.1635394094345355614904345232875688576839,
680           0.1531245755371229803585918112683241066853),
681         Complex!double(-0.01619082256681596362895875232699626384420,
682           -0.005210224203359059109181555401330902819419),
683         Complex!double(0.01078377080978103125464543240346760257008,
684           0.006866888783433775382193630944275682670599),
685         Complex!double(-0.5808616819196736225612296471081337245459,
686           0.6688593905505562263387760667171706325749),
687         Complex!double(double.infinity,
688           -double.infinity),
689         Complex!double(0.1000052020902036118082966385855563526705e-7,
690           0.005100088434920073153418834680320146441685),
691         Complex!double(0.004950156837581592745389973960217444687524,
692           -0.004899838305155226382584756154100963570500),
693         Complex!double(0.005100176864319675957314822982399286703798,
694           0.005099823128319785355949825238269336481254),
695         Complex!double(0.4244534840871830045021143490355372016428,
696           0.002820278933186814021399602648373095266538),
697         Complex!double(-0.1021340733271046543881236523269967674156,
698           -0.00001045696456072005761498961861088944159916),
699         Complex!double(-0.01000200120119206748855061636187197886859,
700           0.9805885888237419500266621041508714123763e-8),
701         Complex!double(0.001000002000012000023960527532953151819595,
702           -0.9800058800588007290937355024646722133204e-11),
703         Complex!double(0.4244549085628511778373438768121222815752,
704           0.002935393851311701428647152230552122898291),
705         Complex!double(-0.1021340732357117208743299813648493928105,
706           -0.00001088377943049851799938998805451564893540),
707         Complex!double(-0.01000200120119126652710792390331206563616,
708           0.1020612612857282306892368985525393707486e-7),
709         Complex!double(0.1000000000007333333333344266666666664457e-5,
710           0.2000000000001333333333323199999999978819e-5),
711         Complex!double(0.1999999999994666666666675199999999990248e-5,
712           0),
713         Complex!double(0.3013403889237919660346644392864226952119,
714           0),
715         Complex!double(0.02503136792640367194699495234782353186858,
716           0),
717         Complex!double(0.002500031251171948248596912483183760683918,
718           0),
719         Complex!double(0,0.004900078433419939164774792850907128053308),
720         Complex!double(0,-0.005100088434920074173454208832365950009419),
721         Complex!double(0,0.2000000000005333333333341866666666676419e-5),
722         Complex!double(0,-48.16001211429122974789822893525016528191),
723         Complex!double(0,0.4627407029504443513654142715903005954668e174),
724         Complex!double(0,-double.infinity),
725         Complex!double(0,0),
726         Complex!double(-0,0),
727         Complex!double(0, double.infinity),
728         Complex!double(0, -double.infinity),
729         Complex!double(double.nan, double.nan),
730         Complex!double(double.nan, double.nan),
731         Complex!double(double.nan, double.nan),
732         Complex!double(double.nan, 0),
733         Complex!double(0, double.nan),
734         Complex!double(double.nan, double.nan),
735         Complex!double(double.nan, double.nan),
736         Complex!double(0.01282473148489433743567240624939698290584,
737           -0.2105957276516618621447832572909153498104e-7),
738         Complex!double(0.01219875253423634378984109995893708152885,
739           -0.1813040560401824664088425926165834355953e-7),
740         Complex!double(0.1020408163265306334945473399689037886997e-7,
741           -0.1041232819658476285651490827866174985330e-25),
742         Complex!double(0.9803921568627452865036825956835185367356e-8,
743           -0.9227220299884665067601095648451913375754e-26),
744         Complex!double(0.5000000000000000002500000000000000003750e-9,
745           -0.1200000000000000001800000188712838420241e-29),
746         Complex!double(5.00000000000000000000025000000000000000000003e-12,
747           -1.20000000000000000000018000000000000000000004e-36),
748         Complex!double(5.00000000000000000000000002500000000000000000e-14,
749           -1.20000000000000000000000001800000000000000000e-42),
750         Complex!double(5e-301, 0)
751     ];
752     commonTest!cdawson(Z, W);
753 }
754 
755 unittest
756 {
757     specialTest!(cerf, erf, 1e-20);
758     specialTest!(cerfi, erfi, 0);
759     specialTest!(cerfcx, erfcx, 0);
760     specialTest!(cerfc, erfc, 1e-20);
761     specialTest!(cdawson, dawson, 1e-20);
762 }