1 // Written in the D programming language.
2 
3 /**
4 This is a submodule of $(MREF std, math).
5 
6 It contains several trigonometric functions.
7 
8 Copyright: Copyright The D Language Foundation 2000 - 2011.
9            D implementations of tan, atan, and atan2 functions are based on the
10            CEPHES math library, which is Copyright (C) 2001 Stephen L. Moshier
11            $(LT)steve@moshier.net$(GT) and are incorporated herein by permission
12            of the author. The author reserves the right to distribute this
13            material elsewhere under different copying permissions.
14            These modifications are distributed here under the following terms:
15 License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
16 Authors:   $(HTTP digitalmars.com, Walter Bright), Don Clugston,
17            Conversion of CEPHES math library to D by Iain Buclaw and David Nadlinger
18 Source: $(PHOBOSSRC std/math/trigonometry.d)
19 
20 Macros:
21     TABLE_SV = <table border="1" cellpadding="4" cellspacing="0">
22                <caption>Special Values</caption>
23                $0</table>
24     SVH = $(TR $(TH $1) $(TH $2))
25     SV  = $(TR $(TD $1) $(TD $2))
26     TH3 = $(TR $(TH $1) $(TH $2) $(TH $3))
27     TD3 = $(TR $(TD $1) $(TD $2) $(TD $3))
28     TABLE_DOMRG = <table border="1" cellpadding="4" cellspacing="0">
29                   $(SVH Domain X, Range Y)
30                   $(SV $1, $2)
31                   </table>
32     DOMAIN=$1
33     RANGE=$1
34     POWER = $1<sup>$2</sup>
35     NAN = $(RED NAN)
36     PLUSMN = &plusmn;
37     INFIN = &infin;
38     PLUSMNINF = &plusmn;&infin;
39  */
40 
41 module std.math.trigonometry;
42 
43 static import core.math;
44 
45 version (D_InlineAsm_X86)    version = InlineAsm_X86_Any;
46 version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any;
47 
48 version (InlineAsm_X86_Any) version = InlineAsm_X87;
49 version (InlineAsm_X87)
50 {
51     static assert(real.mant_dig == 64);
52     version (CRuntime_Microsoft) version = InlineAsm_X87_MSVC;
53 }
54 
55 /***********************************
56  * Returns cosine of x. x is in radians.
57  *
58  *      $(TABLE_SV
59  *      $(TR $(TH x)                 $(TH cos(x)) $(TH invalid?))
60  *      $(TR $(TD $(NAN))            $(TD $(NAN)) $(TD yes)     )
61  *      $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(NAN)) $(TD yes)     )
62  *      )
63  * Bugs:
64  *      Results are undefined if |x| >= $(POWER 2,64).
65  */
66 pragma(inline, true)
67 real cos(real x) @safe pure nothrow @nogc { return core.math.cos(x); }
68 ///ditto
69 pragma(inline, true)
70 double cos(double x) @safe pure nothrow @nogc { return core.math.cos(x); }
71 ///ditto
72 pragma(inline, true)
73 float cos(float x) @safe pure nothrow @nogc { return core.math.cos(x); }
74 
75 ///
76 @safe unittest
77 {
78     import std.math.operations : isClose;
79 
80     assert(cos(0.0) == 1.0);
81     assert(cos(1.0).isClose(0.5403023059));
82     assert(cos(3.0).isClose(-0.9899924966));
83 }
84 
85 @safe unittest
86 {
87     real function(real) pcos = &cos;
88     assert(pcos != null);
89 }
90 
91 @safe pure nothrow @nogc unittest
92 {
93     import std.math.algebraic : fabs;
94 
95     float f = cos(-2.0f);
96     assert(fabs(f - -0.416147f) < .00001);
97 
98     double d = cos(-2.0);
99     assert(fabs(d - -0.416147f) < .00001);
100 
101     real r = cos(-2.0L);
102     assert(fabs(r - -0.416147f) < .00001);
103 }
104 
105 /***********************************
106  * Returns $(HTTP en.wikipedia.org/wiki/Sine, sine) of x. x is in $(HTTP en.wikipedia.org/wiki/Radian, radians).
107  *
108  *      $(TABLE_SV
109  *      $(TH3 x           ,  sin(x)      ,  invalid?)
110  *      $(TD3 $(NAN)      ,  $(NAN)      ,  yes     )
111  *      $(TD3 $(PLUSMN)0.0,  $(PLUSMN)0.0,  no      )
112  *      $(TD3 $(PLUSMNINF),  $(NAN)      ,  yes     )
113  *      )
114  *
115  * Params:
116  *      x = angle in radians (not degrees)
117  * Returns:
118  *      sine of x
119  * See_Also:
120  *      $(MYREF cos), $(MYREF tan), $(MYREF asin)
121  * Bugs:
122  *      Results are undefined if |x| >= $(POWER 2,64).
123  */
124 pragma(inline, true)
125 real sin(real x) @safe pure nothrow @nogc { return core.math.sin(x); }
126 ///ditto
127 pragma(inline, true)
128 double sin(double x) @safe pure nothrow @nogc { return core.math.sin(x); }
129 ///ditto
130 pragma(inline, true)
131 float sin(float x) @safe pure nothrow @nogc { return core.math.sin(x); }
132 
133 ///
134 @safe unittest
135 {
136     import std.math.constants : PI;
137     import std.stdio : writefln;
138 
139     void someFunc()
140     {
141       real x = 30.0;
142       auto result = sin(x * (PI / 180)); // convert degrees to radians
143       writefln("The sine of %s degrees is %s", x, result);
144     }
145 }
146 
147 @safe unittest
148 {
149     real function(real) psin = &sin;
150     assert(psin != null);
151 }
152 
153 @safe pure nothrow @nogc unittest
154 {
155     import std.math.algebraic : fabs;
156 
157     float f = sin(-2.0f);
158     assert(fabs(f - -0.909297f) < .00001);
159 
160     double d = sin(-2.0);
161     assert(fabs(d - -0.909297f) < .00001);
162 
163     real r = sin(-2.0L);
164     assert(fabs(r - -0.909297f) < .00001);
165 }
166 
167 /****************************************************************************
168  * Returns tangent of x. x is in radians.
169  *
170  *      $(TABLE_SV
171  *      $(TR $(TH x)             $(TH tan(x))       $(TH invalid?))
172  *      $(TR $(TD $(NAN))        $(TD $(NAN))       $(TD yes))
173  *      $(TR $(TD $(PLUSMN)0.0)  $(TD $(PLUSMN)0.0) $(TD no))
174  *      $(TR $(TD $(PLUSMNINF))  $(TD $(NAN))       $(TD yes))
175  *      )
176  */
177 pragma(inline, true)
178 real tan(real x) @safe pure nothrow @nogc
179 {
180     version (InlineAsm_X87)
181     {
182         if (!__ctfe)
183             return tanAsm(x);
184     }
185     return tanImpl(x);
186 }
187 
188 /// ditto
189 pragma(inline, true)
190 double tan(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) tan(cast(real) x) : tanImpl(x); }
191 
192 /// ditto
193 pragma(inline, true)
194 float tan(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) tan(cast(real) x) : tanImpl(x); }
195 
196 ///
197 @safe unittest
198 {
199     import std.math.operations : isClose;
200     import std.math.traits : isIdentical;
201     import std.math.constants : PI;
202     import std.math.algebraic : sqrt;
203 
204     assert(isIdentical(tan(0.0), 0.0));
205     assert(tan(PI).isClose(0, 0.0, 1e-10));
206     assert(tan(PI / 3).isClose(sqrt(3.0)));
207 }
208 
209 version (InlineAsm_X87)
210 private real tanAsm(real x) @trusted pure nothrow @nogc
211 {
212     // Separating `return real.nan` from the asm block on LDC produces unintended
213     // behaviour as additional instructions are generated, invalidating the asm
214     // logic inside the previous block. To circumvent this, we can push rnan
215     // manually by creating an immutable variable in the stack.
216     immutable rnan = real.nan;
217 
218     version (X86)
219     {
220     asm pure nothrow @nogc
221     {
222         fld     x[EBP]                  ; // load theta
223         fxam                            ; // test for oddball values
224         fstsw   AX                      ;
225         sahf                            ;
226         jc      trigerr                 ; // x is NAN, infinity, or empty
227                                           // 387's can handle subnormals
228 SC18:   fptan                           ;
229         fstsw   AX                      ;
230         sahf                            ;
231         jnp     Clear1                  ; // C2 = 1 (x is out of range)
232 
233         // Do argument reduction to bring x into range
234         fldpi                           ;
235         fxch                            ;
236 SC17:   fprem1                          ;
237         fstsw   AX                      ;
238         sahf                            ;
239         jp      SC17                    ;
240         fstp    ST(1)                   ; // remove pi from stack
241         jmp     SC18                    ;
242 
243 trigerr:
244         jnp     Lret                    ; // if theta is NAN, return theta
245         fstp    ST(0)                   ; // dump theta
246         fld     rnan                    ; // return rnan
247         jmp     Lret                    ;
248 Clear1:
249         fstp    ST(0)                   ; // dump X, which is always 1
250 Lret:
251         ;
252     }
253     }
254     else version (X86_64)
255     {
256         version (Win64)
257         {
258             asm pure nothrow @nogc
259             {
260                 fld     real ptr [RCX]  ; // load theta
261             }
262         }
263         else
264         {
265             asm pure nothrow @nogc
266             {
267                 fld     x[RBP]          ; // load theta
268             }
269         }
270     asm pure nothrow @nogc
271     {
272         fxam                            ; // test for oddball values
273         fstsw   AX                      ;
274         test    AH,1                    ;
275         jnz     trigerr                 ; // x is NAN, infinity, or empty
276                                           // 387's can handle subnormals
277 SC18:   fptan                           ;
278         fstsw   AX                      ;
279         test    AH,4                    ;
280         jz      Clear1                  ; // C2 = 1 (x is out of range)
281 
282         // Do argument reduction to bring x into range
283         fldpi                           ;
284         fxch                            ;
285 SC17:   fprem1                          ;
286         fstsw   AX                      ;
287         test    AH,4                    ;
288         jnz     SC17                    ;
289         fstp    ST(1)                   ; // remove pi from stack
290         jmp     SC18                    ;
291 
292 trigerr:
293         test    AH,4                    ;
294         jz      Lret                    ; // if theta is NAN, return theta
295         fstp    ST(0)                   ; // dump theta
296         fld     rnan                    ; // return rnan
297         jmp     Lret                    ;
298 Clear1:
299         fstp    ST(0)                   ; // dump X, which is always 1
300 Lret:
301         ;
302     }
303     }
304     else
305         static assert(0);
306 }
307 
308 private T tanImpl(T)(T x) @safe pure nothrow @nogc
309 {
310     import std.math.traits : floatTraits, RealFormat;
311     import std.math.constants : PI, PI_4;
312     import std.math.rounding : floor;
313     import std.math.algebraic : poly;
314     import std.math.traits : isInfinity, isNaN, signbit;
315 
316     // Coefficients for tan(x) and PI/4 split into three parts.
317     enum realFormat = floatTraits!T.realFormat;
318     static if (realFormat == RealFormat.ieeeQuadruple)
319     {
320         static immutable T[6] P = [
321             2.883414728874239697964612246732416606301E10L,
322             -2.307030822693734879744223131873392503321E9L,
323             5.160188250214037865511600561074819366815E7L,
324             -4.249691853501233575668486667664718192660E5L,
325             1.272297782199996882828849455156962260810E3L,
326             -9.889929415807650724957118893791829849557E-1L
327         ];
328         static immutable T[7] Q = [
329             8.650244186622719093893836740197250197602E10L,
330             -4.152206921457208101480801635640958361612E10L,
331             2.758476078803232151774723646710890525496E9L,
332             -5.733709132766856723608447733926138506824E7L,
333             4.529422062441341616231663543669583527923E5L,
334             -1.317243702830553658702531997959756728291E3L,
335             1.0
336         ];
337 
338         enum T P1 =
339             7.853981633974483067550664827649598009884357452392578125E-1L;
340         enum T P2 =
341             2.8605943630549158983813312792950660807511260829685741796657E-18L;
342         enum T P3 =
343             2.1679525325309452561992610065108379921905808E-35L;
344     }
345     else static if (realFormat == RealFormat.ieeeExtended ||
346                     realFormat == RealFormat.ieeeDouble)
347     {
348         static immutable T[3] P = [
349            -1.7956525197648487798769E7L,
350             1.1535166483858741613983E6L,
351            -1.3093693918138377764608E4L,
352         ];
353         static immutable T[5] Q = [
354            -5.3869575592945462988123E7L,
355             2.5008380182335791583922E7L,
356            -1.3208923444021096744731E6L,
357             1.3681296347069295467845E4L,
358             1.0000000000000000000000E0L,
359         ];
360 
361         enum T P1 = 7.853981554508209228515625E-1L;
362         enum T P2 = 7.946627356147928367136046290398E-9L;
363         enum T P3 = 3.061616997868382943065164830688E-17L;
364     }
365     else static if (realFormat == RealFormat.ieeeSingle)
366     {
367         static immutable T[6] P = [
368             3.33331568548E-1,
369             1.33387994085E-1,
370             5.34112807005E-2,
371             2.44301354525E-2,
372             3.11992232697E-3,
373             9.38540185543E-3,
374         ];
375 
376         enum T P1 = 0.78515625;
377         enum T P2 = 2.4187564849853515625E-4;
378         enum T P3 = 3.77489497744594108E-8;
379     }
380     else
381         static assert(0, "no coefficients for tan()");
382 
383     // Special cases.
384     if (x == cast(T) 0.0 || isNaN(x))
385         return x;
386     if (isInfinity(x))
387         return T.nan;
388 
389     // Make argument positive but save the sign.
390     bool sign = false;
391     if (signbit(x))
392     {
393         sign = true;
394         x = -x;
395     }
396 
397     // Compute x mod PI/4.
398     static if (realFormat == RealFormat.ieeeSingle)
399     {
400         enum T FOPI = 4 / PI;
401         int j = cast(int) (FOPI * x);
402         T y = j;
403         T z;
404     }
405     else
406     {
407         T y = floor(x / cast(T) PI_4);
408         // Strip high bits of integer part.
409         enum T highBitsFactor = (realFormat == RealFormat.ieeeDouble ? 0x1p3 : 0x1p4);
410         enum T highBitsInv = 1.0 / highBitsFactor;
411         T z = y * highBitsInv;
412         // Compute y - 2^numHighBits * (y / 2^numHighBits).
413         z = y - highBitsFactor * floor(z);
414 
415         // Integer and fraction part modulo one octant.
416         int j = cast(int)(z);
417     }
418 
419     // Map zeros and singularities to origin.
420     if (j & 1)
421     {
422         j += 1;
423         y += cast(T) 1.0;
424     }
425 
426     z = ((x - y * P1) - y * P2) - y * P3;
427     const T zz = z * z;
428 
429     enum T zzThreshold = (realFormat == RealFormat.ieeeSingle ? 1.0e-4L :
430                           realFormat == RealFormat.ieeeDouble ? 1.0e-14L : 1.0e-20L);
431     if (zz > zzThreshold)
432     {
433         static if (realFormat == RealFormat.ieeeSingle)
434             y = z + z * (zz * poly(zz, P));
435         else
436             y = z + z * (zz * poly(zz, P) / poly(zz, Q));
437     }
438     else
439         y = z;
440 
441     if (j & 2)
442         y = (cast(T) -1.0) / y;
443 
444     return (sign) ? -y : y;
445 }
446 
447 @safe @nogc nothrow unittest
448 {
449     static void testTan(T)()
450     {
451         import std.math.operations : CommonDefaultFor, isClose, NaN;
452         import std.math.traits : isIdentical, isNaN;
453         import std.math.constants : PI, PI_4;
454 
455         // ±0
456         const T zero = 0.0;
457         assert(isIdentical(tan(zero), zero));
458         assert(isIdentical(tan(-zero), -zero));
459         // ±∞
460         const T inf = T.infinity;
461         assert(isNaN(tan(inf)));
462         assert(isNaN(tan(-inf)));
463         // NaN
464         const T specialNaN = NaN(0x0123L);
465         assert(isIdentical(tan(specialNaN), specialNaN));
466 
467         static immutable T[2][] vals =
468         [
469             // angle, tan
470             [   .5,  .546302489843790513255L],
471             [   1,   1.55740772465490223050L],
472             [   1.5, 14.1014199471717193876L],
473             [   2,  -2.18503986326151899164L],
474             [   2.5,-.747022297238660279355L],
475             [   3,  -.142546543074277805295L],
476             [   3.5, .374585640158594666330L],
477             [   4,   1.15782128234957758313L],
478             [   4.5, 4.63733205455118446831L],
479             [   5,  -3.38051500624658563698L],
480             [   5.5,-.995584052213885017701L],
481             [   6,  -.291006191384749157053L],
482             [   6.5, .220277200345896811825L],
483             [   10,  .648360827459086671259L],
484 
485             // special angles
486             [   PI_4,   1],
487             //[   PI_2,   T.infinity], // PI_2 is not _exactly_ pi/2.
488             [   3*PI_4, -1],
489             [   PI,     0],
490             [   5*PI_4, 1],
491             //[   3*PI_2, -T.infinity],
492             [   7*PI_4, -1],
493             [   2*PI,   0],
494          ];
495 
496         foreach (ref val; vals)
497         {
498             T x = val[0];
499             T r = val[1];
500             T t = tan(x);
501 
502             //printf("tan(%Lg) = %Lg, should be %Lg\n", cast(real) x, cast(real) t, cast(real) r);
503             assert(isClose(r, t, CommonDefaultFor!(T,T), CommonDefaultFor!(T,T)));
504 
505             x = -x;
506             r = -r;
507             t = tan(x);
508             //printf("tan(%Lg) = %Lg, should be %Lg\n", cast(real) x, cast(real) t, cast(real) r);
509             assert(isClose(r, t, CommonDefaultFor!(T,T), CommonDefaultFor!(T,T)));
510         }
511     }
512 
513     import std.meta : AliasSeq;
514     foreach (T; AliasSeq!(real, double, float))
515         testTan!T();
516 
517     import std.math.operations : isClose;
518     import std.math.constants : PI;
519     import std.math.algebraic : sqrt;
520     assert(isClose(tan(PI / 3), sqrt(3.0L), real.sizeof > double.sizeof ? 1e-15 : 1e-14));
521 }
522 
523 @safe pure nothrow @nogc unittest
524 {
525     import std.math.algebraic : fabs;
526     import std.math.traits : isNaN;
527 
528     float f = tan(-2.0f);
529     assert(fabs(f - 2.18504f) < .00001);
530 
531     double d = tan(-2.0);
532     assert(fabs(d - 2.18504f) < .00001);
533 
534     real r = tan(-2.0L);
535     assert(fabs(r - 2.18504f) < .00001);
536 
537     // Verify correct behavior for large inputs
538     assert(!isNaN(tan(0x1p63)));
539     assert(!isNaN(tan(-0x1p63)));
540     static if (real.mant_dig >= 64)
541     {
542         assert(!isNaN(tan(0x1p300L)));
543         assert(!isNaN(tan(-0x1p300L)));
544     }
545 }
546 
547 /***************
548  * Calculates the arc cosine of x,
549  * returning a value ranging from 0 to $(PI).
550  *
551  *      $(TABLE_SV
552  *      $(TR $(TH x)         $(TH acos(x)) $(TH invalid?))
553  *      $(TR $(TD $(GT)1.0)  $(TD $(NAN))  $(TD yes))
554  *      $(TR $(TD $(LT)-1.0) $(TD $(NAN))  $(TD yes))
555  *      $(TR $(TD $(NAN))    $(TD $(NAN))  $(TD yes))
556  *  )
557  */
558 real acos(real x) @safe pure nothrow @nogc
559 {
560     import core.math : sqrt;
561 
562     return atan2(sqrt(1-x*x), x);
563 }
564 
565 /// ditto
566 double acos(double x) @safe pure nothrow @nogc { return acos(cast(real) x); }
567 
568 /// ditto
569 float acos(float x) @safe pure nothrow @nogc  { return acos(cast(real) x); }
570 
571 ///
572 @safe unittest
573 {
574     import std.math.operations : isClose;
575     import std.math.traits : isNaN;
576     import std.math.constants : PI;
577 
578     assert(acos(0.0).isClose(1.570796327));
579     assert(acos(0.5).isClose(PI / 3));
580     assert(acos(PI).isNaN);
581 }
582 
583 @safe @nogc nothrow unittest
584 {
585     import std.math.operations : isClose;
586     import std.math.constants : PI;
587 
588     assert(isClose(acos(0.5), PI / 3, real.sizeof > double.sizeof ? 1e-15 : 1e-14));
589 }
590 
591 /***************
592  * Calculates the arc sine of x,
593  * returning a value ranging from -$(PI)/2 to $(PI)/2.
594  *
595  *      $(TABLE_SV
596  *      $(TR $(TH x)            $(TH asin(x))      $(TH invalid?))
597  *      $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no))
598  *      $(TR $(TD $(GT)1.0)     $(TD $(NAN))       $(TD yes))
599  *      $(TR $(TD $(LT)-1.0)    $(TD $(NAN))       $(TD yes))
600  *  )
601  */
602 real asin(real x) @safe pure nothrow @nogc
603 {
604     import core.math : sqrt;
605 
606     return atan2(x, sqrt(1-x*x));
607 }
608 
609 /// ditto
610 double asin(double x) @safe pure nothrow @nogc { return asin(cast(real) x); }
611 
612 /// ditto
613 float asin(float x) @safe pure nothrow @nogc  { return asin(cast(real) x); }
614 
615 ///
616 @safe unittest
617 {
618     import std.math.operations : isClose;
619     import std.math.traits : isIdentical, isNaN;
620     import std.math.constants : PI;
621 
622     assert(isIdentical(asin(0.0), 0.0));
623     assert(asin(0.5).isClose(PI / 6));
624     assert(asin(PI).isNaN);
625 }
626 
627 @safe @nogc nothrow unittest
628 {
629     import std.math.operations : isClose;
630     import std.math.constants : PI;
631 
632     assert(isClose(asin(0.5), PI / 6, real.sizeof > double.sizeof ? 1e-15 : 1e-14));
633 }
634 
635 /***************
636  * Calculates the arc tangent of x,
637  * returning a value ranging from -$(PI)/2 to $(PI)/2.
638  *
639  *      $(TABLE_SV
640  *      $(TR $(TH x)                 $(TH atan(x))      $(TH invalid?))
641  *      $(TR $(TD $(PLUSMN)0.0)      $(TD $(PLUSMN)0.0) $(TD no))
642  *      $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(NAN))       $(TD yes))
643  *  )
644  */
645 pragma(inline, true)
646 real atan(real x) @safe pure nothrow @nogc
647 {
648     version (InlineAsm_X87)
649     {
650         if (!__ctfe)
651             return atan2Asm(x, 1.0L);
652     }
653     return atanImpl(x);
654 }
655 
656 /// ditto
657 pragma(inline, true)
658 double atan(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) atan(cast(real) x) : atanImpl(x); }
659 
660 /// ditto
661 pragma(inline, true)
662 float atan(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) atan(cast(real) x) : atanImpl(x); }
663 
664 ///
665 @safe unittest
666 {
667     import std.math.operations : isClose;
668     import std.math.traits : isIdentical;
669     import std.math.constants : PI;
670     import std.math.algebraic : sqrt;
671 
672     assert(isIdentical(atan(0.0), 0.0));
673     assert(atan(sqrt(3.0)).isClose(PI / 3));
674 }
675 
676 private T atanImpl(T)(T x) @safe pure nothrow @nogc
677 {
678     import std.math.traits : floatTraits, RealFormat, copysign, isInfinity, signbit;
679     import std.math.constants : PI_2, PI_4;
680     import std.math.algebraic : poly;
681 
682     // Coefficients for atan(x)
683     enum realFormat = floatTraits!T.realFormat;
684     static if (realFormat == RealFormat.ieeeQuadruple)
685     {
686         static immutable T[9] P = [
687             -6.880597774405940432145577545328795037141E2L,
688             -2.514829758941713674909996882101723647996E3L,
689             -3.696264445691821235400930243493001671932E3L,
690             -2.792272753241044941703278827346430350236E3L,
691             -1.148164399808514330375280133523543970854E3L,
692             -2.497759878476618348858065206895055957104E2L,
693             -2.548067867495502632615671450650071218995E1L,
694             -8.768423468036849091777415076702113400070E-1L,
695             -6.635810778635296712545011270011752799963E-4L
696         ];
697         static immutable T[9] Q = [
698             2.064179332321782129643673263598686441900E3L,
699             8.782996876218210302516194604424986107121E3L,
700             1.547394317752562611786521896296215170819E4L,
701             1.458510242529987155225086911411015961174E4L,
702             7.928572347062145288093560392463784743935E3L,
703             2.494680540950601626662048893678584497900E3L,
704             4.308348370818927353321556740027020068897E2L,
705             3.566239794444800849656497338030115886153E1L,
706             1.0
707         ];
708     }
709     else static if (realFormat == RealFormat.ieeeExtended)
710     {
711         static immutable T[5] P = [
712            -5.0894116899623603312185E1L,
713            -9.9988763777265819915721E1L,
714            -6.3976888655834347413154E1L,
715            -1.4683508633175792446076E1L,
716            -8.6863818178092187535440E-1L,
717         ];
718         static immutable T[6] Q = [
719             1.5268235069887081006606E2L,
720             3.9157570175111990631099E2L,
721             3.6144079386152023162701E2L,
722             1.4399096122250781605352E2L,
723             2.2981886733594175366172E1L,
724             1.0000000000000000000000E0L,
725         ];
726     }
727     else static if (realFormat == RealFormat.ieeeDouble)
728     {
729         static immutable T[5] P = [
730            -6.485021904942025371773E1L,
731            -1.228866684490136173410E2L,
732            -7.500855792314704667340E1L,
733            -1.615753718733365076637E1L,
734            -8.750608600031904122785E-1L,
735         ];
736         static immutable T[6] Q = [
737             1.945506571482613964425E2L,
738             4.853903996359136964868E2L,
739             4.328810604912902668951E2L,
740             1.650270098316988542046E2L,
741             2.485846490142306297962E1L,
742             1.000000000000000000000E0L,
743         ];
744 
745         enum T MOREBITS = 6.123233995736765886130E-17L;
746     }
747     else static if (realFormat == RealFormat.ieeeSingle)
748     {
749         static immutable T[4] P = [
750            -3.33329491539E-1,
751             1.99777106478E-1,
752            -1.38776856032E-1,
753             8.05374449538E-2,
754         ];
755     }
756     else
757         static assert(0, "no coefficients for atan()");
758 
759     // tan(PI/8)
760     enum T TAN_PI_8 = 0.414213562373095048801688724209698078569672L;
761     // tan(3 * PI/8)
762     enum T TAN3_PI_8 = 2.414213562373095048801688724209698078569672L;
763 
764     // Special cases.
765     if (x == cast(T) 0.0)
766         return x;
767     if (isInfinity(x))
768         return copysign(cast(T) PI_2, x);
769 
770     // Make argument positive but save the sign.
771     bool sign = false;
772     if (signbit(x))
773     {
774         sign = true;
775         x = -x;
776     }
777 
778     static if (realFormat == RealFormat.ieeeDouble) // special case for double precision
779     {
780         short flag = 0;
781         T y;
782         if (x > TAN3_PI_8)
783         {
784             y = PI_2;
785             flag = 1;
786             x = -(1.0 / x);
787         }
788         else if (x <= 0.66)
789         {
790             y = 0.0;
791         }
792         else
793         {
794             y = PI_4;
795             flag = 2;
796             x = (x - 1.0)/(x + 1.0);
797         }
798 
799         T z = x * x;
800         z = z * poly(z, P) / poly(z, Q);
801         z = x * z + x;
802         if (flag == 2)
803             z += 0.5 * MOREBITS;
804         else if (flag == 1)
805             z += MOREBITS;
806         y = y + z;
807     }
808     else
809     {
810         // Range reduction.
811         T y;
812         if (x > TAN3_PI_8)
813         {
814             y = PI_2;
815             x = -((cast(T) 1.0) / x);
816         }
817         else if (x > TAN_PI_8)
818         {
819             y = PI_4;
820             x = (x - cast(T) 1.0)/(x + cast(T) 1.0);
821         }
822         else
823             y = 0.0;
824 
825         // Rational form in x^^2.
826         const T z = x * x;
827         static if (realFormat == RealFormat.ieeeSingle)
828             y += poly(z, P) * z * x + x;
829         else
830             y = y + (poly(z, P) / poly(z, Q)) * z * x + x;
831     }
832 
833     return (sign) ? -y : y;
834 }
835 
836 @safe @nogc nothrow unittest
837 {
838     static void testAtan(T)()
839     {
840         import std.math.operations : CommonDefaultFor, isClose, NaN;
841         import std.math.traits : isIdentical;
842         import std.math.constants : PI_2, PI_4;
843 
844         // ±0
845         const T zero = 0.0;
846         assert(isIdentical(atan(zero), zero));
847         assert(isIdentical(atan(-zero), -zero));
848         // ±∞
849         const T inf = T.infinity;
850         assert(isClose(atan(inf), cast(T) PI_2));
851         assert(isClose(atan(-inf), cast(T) -PI_2));
852         // NaN
853         const T specialNaN = NaN(0x0123L);
854         assert(isIdentical(atan(specialNaN), specialNaN));
855 
856         static immutable T[2][] vals =
857         [
858             // x, atan(x)
859             [ 0.25, 0.244978663126864154172L ],
860             [ 0.5,  0.463647609000806116214L ],
861             [ 1,    PI_4                     ],
862             [ 1.5,  0.982793723247329067985L ],
863             [ 10,   1.471127674303734591852L ],
864         ];
865 
866         foreach (ref val; vals)
867         {
868             T x = val[0];
869             T r = val[1];
870             T a = atan(x);
871 
872             //printf("atan(%Lg) = %Lg, should be %Lg\n", cast(real) x, cast(real) a, cast(real) r);
873             assert(isClose(r, a, CommonDefaultFor!(T,T), CommonDefaultFor!(T,T)));
874 
875             x = -x;
876             r = -r;
877             a = atan(x);
878             //printf("atan(%Lg) = %Lg, should be %Lg\n", cast(real) x, cast(real) a, cast(real) r);
879             assert(isClose(r, a, CommonDefaultFor!(T,T), CommonDefaultFor!(T,T)));
880         }
881     }
882 
883     import std.meta : AliasSeq;
884     foreach (T; AliasSeq!(real, double, float))
885         testAtan!T();
886 
887     import std.math.operations : isClose;
888     import std.math.algebraic : sqrt;
889     import std.math.constants : PI;
890     assert(isClose(atan(sqrt(3.0L)), PI / 3, real.sizeof > double.sizeof ? 1e-15 : 1e-14));
891 }
892 
893 /***************
894  * Calculates the arc tangent of y / x,
895  * returning a value ranging from -$(PI) to $(PI).
896  *
897  *      $(TABLE_SV
898  *      $(TR $(TH y)                 $(TH x)            $(TH atan(y, x)))
899  *      $(TR $(TD $(NAN))            $(TD anything)     $(TD $(NAN)) )
900  *      $(TR $(TD anything)          $(TD $(NAN))       $(TD $(NAN)) )
901  *      $(TR $(TD $(PLUSMN)0.0)      $(TD $(GT)0.0)     $(TD $(PLUSMN)0.0) )
902  *      $(TR $(TD $(PLUSMN)0.0)      $(TD +0.0)         $(TD $(PLUSMN)0.0) )
903  *      $(TR $(TD $(PLUSMN)0.0)      $(TD $(LT)0.0)     $(TD $(PLUSMN)$(PI)))
904  *      $(TR $(TD $(PLUSMN)0.0)      $(TD -0.0)         $(TD $(PLUSMN)$(PI)))
905  *      $(TR $(TD $(GT)0.0)          $(TD $(PLUSMN)0.0) $(TD $(PI)/2) )
906  *      $(TR $(TD $(LT)0.0)          $(TD $(PLUSMN)0.0) $(TD -$(PI)/2) )
907  *      $(TR $(TD $(GT)0.0)          $(TD $(INFIN))     $(TD $(PLUSMN)0.0) )
908  *      $(TR $(TD $(PLUSMN)$(INFIN)) $(TD anything)     $(TD $(PLUSMN)$(PI)/2))
909  *      $(TR $(TD $(GT)0.0)          $(TD -$(INFIN))    $(TD $(PLUSMN)$(PI)) )
910  *      $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(INFIN))     $(TD $(PLUSMN)$(PI)/4))
911  *      $(TR $(TD $(PLUSMN)$(INFIN)) $(TD -$(INFIN))    $(TD $(PLUSMN)3$(PI)/4))
912  *      )
913  */
914 pragma(inline, true)
915 real atan2(real y, real x) @trusted pure nothrow @nogc // TODO: @safe
916 {
917     version (InlineAsm_X87)
918     {
919         if (!__ctfe)
920             return atan2Asm(y, x);
921     }
922     return atan2Impl(y, x);
923 }
924 
925 /// ditto
926 pragma(inline, true)
927 double atan2(double y, double x) @safe pure nothrow @nogc
928 {
929     return __ctfe ? cast(double) atan2(cast(real) y, cast(real) x) : atan2Impl(y, x);
930 }
931 
932 /// ditto
933 pragma(inline, true)
934 float atan2(float y, float x) @safe pure nothrow @nogc
935 {
936     return __ctfe ? cast(float) atan2(cast(real) y, cast(real) x) : atan2Impl(y, x);
937 }
938 
939 ///
940 @safe unittest
941 {
942     import std.math.operations : isClose;
943     import std.math.constants : PI;
944     import std.math.algebraic : sqrt;
945 
946     assert(atan2(1.0, sqrt(3.0)).isClose(PI / 6));
947 }
948 
949 version (InlineAsm_X87)
950 private real atan2Asm(real y, real x) @trusted pure nothrow @nogc
951 {
952     version (Win64)
953     {
954         asm pure nothrow @nogc {
955             naked;
956             fld real ptr [RDX]; // y
957             fld real ptr [RCX]; // x
958             fpatan;
959             ret;
960         }
961     }
962     else
963     {
964         asm pure nothrow @nogc {
965             fld y;
966             fld x;
967             fpatan;
968         }
969     }
970 }
971 
972 private T atan2Impl(T)(T y, T x) @safe pure nothrow @nogc
973 {
974     import std.math.traits : copysign, isInfinity, isNaN, signbit;
975     import std.math.constants : PI, PI_2, PI_4;
976 
977     // Special cases.
978     if (isNaN(x) || isNaN(y))
979         return T.nan;
980     if (y == cast(T) 0.0)
981     {
982         if (x >= 0 && !signbit(x))
983             return copysign(0, y);
984         else
985             return copysign(cast(T) PI, y);
986     }
987     if (x == cast(T) 0.0)
988         return copysign(cast(T) PI_2, y);
989     if (isInfinity(x))
990     {
991         if (signbit(x))
992         {
993             if (isInfinity(y))
994                 return copysign(3 * cast(T) PI_4, y);
995             else
996                 return copysign(cast(T) PI, y);
997         }
998         else
999         {
1000             if (isInfinity(y))
1001                 return copysign(cast(T) PI_4, y);
1002             else
1003                 return copysign(cast(T) 0.0, y);
1004         }
1005     }
1006     if (isInfinity(y))
1007         return copysign(cast(T) PI_2, y);
1008 
1009     // Call atan and determine the quadrant.
1010     T z = atan(y / x);
1011 
1012     if (signbit(x))
1013     {
1014         if (signbit(y))
1015             z = z - cast(T) PI;
1016         else
1017             z = z + cast(T) PI;
1018     }
1019 
1020     if (z == cast(T) 0.0)
1021         return copysign(z, y);
1022 
1023     return z;
1024 }
1025 
1026 @safe @nogc nothrow unittest
1027 {
1028     static void testAtan2(T)()
1029     {
1030         import std.math.operations : isClose;
1031         import std.math.traits : isIdentical, isNaN;
1032         import std.math.constants : PI, PI_2, PI_4;
1033 
1034         // NaN
1035         const T nan = T.nan;
1036         assert(isNaN(atan2(nan, cast(T) 1)));
1037         assert(isNaN(atan2(cast(T) 1, nan)));
1038 
1039         const T inf = T.infinity;
1040         static immutable T[3][] vals =
1041         [
1042             // y, x, atan2(y, x)
1043 
1044             // ±0
1045             [  0.0,  1.0,  0.0 ],
1046             [ -0.0,  1.0, -0.0 ],
1047             [  0.0,  0.0,  0.0 ],
1048             [ -0.0,  0.0, -0.0 ],
1049             [  0.0, -1.0,  PI ],
1050             [ -0.0, -1.0, -PI ],
1051             [  0.0, -0.0,  PI ],
1052             [ -0.0, -0.0, -PI ],
1053             [  1.0,  0.0,  PI_2 ],
1054             [  1.0, -0.0,  PI_2 ],
1055             [ -1.0,  0.0, -PI_2 ],
1056             [ -1.0, -0.0, -PI_2 ],
1057 
1058             // ±∞
1059             [  1.0,  inf,  0.0 ],
1060             [ -1.0,  inf, -0.0 ],
1061             [  1.0, -inf,  PI ],
1062             [ -1.0, -inf, -PI ],
1063             [  inf,  1.0,  PI_2 ],
1064             [  inf, -1.0,  PI_2 ],
1065             [ -inf,  1.0, -PI_2 ],
1066             [ -inf, -1.0, -PI_2 ],
1067             [  inf,  inf,  PI_4 ],
1068             [ -inf,  inf, -PI_4 ],
1069             [  inf, -inf,  3 * PI_4 ],
1070             [ -inf, -inf, -3 * PI_4 ],
1071 
1072             [  1.0,  1.0,  PI_4 ],
1073             [ -2.0,  2.0, -PI_4 ],
1074             [  3.0, -3.0,  3 * PI_4 ],
1075             [ -4.0, -4.0, -3 * PI_4 ],
1076 
1077             [  0.75,  0.25,   1.2490457723982544258299L ],
1078             [ -0.5,   0.375, -0.9272952180016122324285L ],
1079             [  0.5,  -0.125,  1.8157749899217607734034L ],
1080             [ -0.75, -0.5,   -2.1587989303424641704769L ],
1081         ];
1082 
1083         foreach (ref val; vals)
1084         {
1085             const T y = val[0];
1086             const T x = val[1];
1087             const T r = val[2];
1088             const T a = atan2(y, x);
1089 
1090             //printf("atan2(%Lg, %Lg) = %Lg, should be %Lg\n", cast(real) y, cast(real) x, cast(real) a, cast(real) r);
1091             if (r == 0)
1092                 assert(isIdentical(r, a)); // check sign
1093             else
1094                 assert(isClose(r, a));
1095         }
1096     }
1097 
1098     import std.meta : AliasSeq;
1099     foreach (T; AliasSeq!(real, double, float))
1100         testAtan2!T();
1101 
1102     import std.math.operations : isClose;
1103     import std.math.algebraic : sqrt;
1104     import std.math.constants : PI;
1105     assert(isClose(atan2(1.0L, sqrt(3.0L)), PI / 6, real.sizeof > double.sizeof ? 1e-15 : 1e-14));
1106 }
1107 
1108 /***********************************
1109  * Calculates the hyperbolic cosine of x.
1110  *
1111  *      $(TABLE_SV
1112  *      $(TR $(TH x)                 $(TH cosh(x))      $(TH invalid?))
1113  *      $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(PLUSMN)0.0) $(TD no) )
1114  *      )
1115  */
1116 real cosh(real x) @safe pure nothrow @nogc
1117 {
1118     import std.math.exponential : exp;
1119 
1120     //  cosh = (exp(x)+exp(-x))/2.
1121     // The naive implementation works correctly.
1122     const real y = exp(x);
1123     return (y + 1.0/y) * 0.5;
1124 }
1125 
1126 /// ditto
1127 double cosh(double x) @safe pure nothrow @nogc { return cosh(cast(real) x); }
1128 
1129 /// ditto
1130 float cosh(float x) @safe pure nothrow @nogc  { return cosh(cast(real) x); }
1131 
1132 ///
1133 @safe unittest
1134 {
1135     import std.math.constants : E;
1136     import std.math.operations : isClose;
1137 
1138     assert(cosh(0.0) == 1.0);
1139     assert(cosh(1.0).isClose((E + 1.0 / E) / 2));
1140 }
1141 
1142 @safe @nogc nothrow unittest
1143 {
1144     import std.math.constants : E;
1145     import std.math.operations : isClose;
1146 
1147     assert(isClose(cosh(1.0), (E + 1.0 / E) / 2, real.sizeof > double.sizeof ? 1e-15 : 1e-14));
1148 }
1149 
1150 /***********************************
1151  * Calculates the hyperbolic sine of x.
1152  *
1153  *      $(TABLE_SV
1154  *      $(TR $(TH x)                 $(TH sinh(x))           $(TH invalid?))
1155  *      $(TR $(TD $(PLUSMN)0.0)      $(TD $(PLUSMN)0.0)      $(TD no))
1156  *      $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(PLUSMN)$(INFIN)) $(TD no))
1157  *      )
1158  */
1159 real sinh(real x) @safe pure nothrow @nogc { return _sinh(x); }
1160 
1161 /// ditto
1162 double sinh(double x) @safe pure nothrow @nogc { return _sinh(x); }
1163 
1164 /// ditto
1165 float sinh(float x) @safe pure nothrow @nogc { return _sinh(x); }
1166 
1167 ///
1168 @safe unittest
1169 {
1170     import std.math.constants : E;
1171     import std.math.operations : isClose;
1172     import std.math.traits : isIdentical;
1173 
1174     enum sinh1 = (E - 1.0 / E) / 2;
1175     import std.meta : AliasSeq;
1176     static foreach (F; AliasSeq!(float, double, real))
1177     {
1178         assert(isIdentical(sinh(F(0.0)), F(0.0)));
1179         assert(sinh(F(1.0)).isClose(F(sinh1)));
1180     }
1181 }
1182 
1183 private F _sinh(F)(F x)
1184 {
1185     import std.math.traits : copysign;
1186     import std.math.exponential : exp, expm1;
1187     import core.math : fabs;
1188     import std.math.constants : LN2;
1189 
1190     //  sinh(x) =  (exp(x)-exp(-x))/2;
1191     // Very large arguments could cause an overflow, but
1192     // the maximum value of x for which exp(x) + exp(-x)) != exp(x)
1193     // is x = 0.5 * (real.mant_dig) * LN2. // = 22.1807 for real80.
1194     if (fabs(x) > F.mant_dig * F(LN2))
1195     {
1196         return copysign(F(0.5) * exp(fabs(x)), x);
1197     }
1198 
1199     const y = expm1(x);
1200     return F(0.5) * y / (y+1) * (y+2);
1201 }
1202 
1203 @safe @nogc nothrow unittest
1204 {
1205     import std.math.constants : E;
1206     import std.math.operations : isClose;
1207 
1208     assert(isClose(sinh(1.0L), real((E - 1.0 / E) / 2), real.sizeof > double.sizeof ? 1e-15 : 1e-14));
1209 }
1210 /***********************************
1211  * Calculates the hyperbolic tangent of x.
1212  *
1213  *      $(TABLE_SV
1214  *      $(TR $(TH x)                 $(TH tanh(x))      $(TH invalid?))
1215  *      $(TR $(TD $(PLUSMN)0.0)      $(TD $(PLUSMN)0.0) $(TD no) )
1216  *      $(TR $(TD $(PLUSMN)$(INFIN)) $(TD $(PLUSMN)1.0) $(TD no))
1217  *      )
1218  */
1219 real tanh(real x) @safe pure nothrow @nogc { return _tanh(x); }
1220 
1221 /// ditto
1222 double tanh(double x) @safe pure nothrow @nogc { return _tanh(x); }
1223 
1224 /// ditto
1225 float tanh(float x) @safe pure nothrow @nogc { return _tanh(x); }
1226 
1227 ///
1228 @safe unittest
1229 {
1230     import std.math.operations : isClose;
1231     import std.math.traits : isIdentical;
1232 
1233     assert(isIdentical(tanh(0.0), 0.0));
1234     assert(tanh(1.0).isClose(sinh(1.0) / cosh(1.0)));
1235 }
1236 
1237 private F _tanh(F)(F x)
1238 {
1239     import std.math.traits : copysign;
1240     import std.math.exponential : expm1;
1241     import core.math : fabs;
1242     import std.math.constants : LN2;
1243 
1244     //  tanh(x) = (exp(x) - exp(-x))/(exp(x)+exp(-x))
1245     if (fabs(x) > F.mant_dig * F(LN2))
1246     {
1247         return copysign(1, x);
1248     }
1249 
1250     const y = expm1(2*x);
1251     return y / (y + 2);
1252 }
1253 
1254 @safe @nogc nothrow unittest
1255 {
1256     import std.math.operations : isClose;
1257 
1258     assert(isClose(tanh(1.0L), sinh(1.0L) / cosh(1.0L), real.sizeof > double.sizeof ? 1e-15 : 1e-14));
1259 }
1260 
1261 /***********************************
1262  * Calculates the inverse hyperbolic cosine of x.
1263  *
1264  *  Mathematically, acosh(x) = log(x + sqrt( x*x - 1))
1265  *
1266  * $(TABLE_DOMRG
1267  *    $(DOMAIN 1..$(INFIN)),
1268  *    $(RANGE  0..$(INFIN))
1269  * )
1270  *
1271  *  $(TABLE_SV
1272  *    $(SVH  x,     acosh(x) )
1273  *    $(SV  $(NAN), $(NAN) )
1274  *    $(SV  $(LT)1,     $(NAN) )
1275  *    $(SV  1,      0       )
1276  *    $(SV  +$(INFIN),+$(INFIN))
1277  *  )
1278  */
1279 real acosh(real x) @safe pure nothrow @nogc { return _acosh(x); }
1280 
1281 /// ditto
1282 double acosh(double x) @safe pure nothrow @nogc { return _acosh(x); }
1283 
1284 /// ditto
1285 float acosh(float x) @safe pure nothrow @nogc { return _acosh(x); }
1286 
1287 ///
1288 @safe @nogc nothrow unittest
1289 {
1290     import std.math.traits : isIdentical, isNaN;
1291 
1292     assert(isNaN(acosh(0.9)));
1293     assert(isNaN(acosh(real.nan)));
1294     assert(isIdentical(acosh(1.0), 0.0));
1295     assert(acosh(real.infinity) == real.infinity);
1296     assert(isNaN(acosh(0.5)));
1297 }
1298 
1299 private F _acosh(F)(F x) @safe pure nothrow @nogc
1300 {
1301     import std.math.constants : LN2;
1302     import std.math.exponential : log;
1303     import core.math : sqrt;
1304 
1305     if (x > 1/F.epsilon)
1306         return F(LN2) + log(x);
1307     else
1308         return log(x + sqrt(x*x - 1));
1309 }
1310 
1311 @safe @nogc nothrow unittest
1312 {
1313     import std.math.operations : isClose;
1314 
1315     assert(isClose(acosh(cosh(3.0L)), 3.0L, real.sizeof > double.sizeof ? 1e-15 : 1e-14));
1316 }
1317 
1318 /***********************************
1319  * Calculates the inverse hyperbolic sine of x.
1320  *
1321  *  Mathematically,
1322  *  ---------------
1323  *  asinh(x) =  log( x + sqrt( x*x + 1 )) // if x >= +0
1324  *  asinh(x) = -log(-x + sqrt( x*x + 1 )) // if x <= -0
1325  *  -------------
1326  *
1327  *    $(TABLE_SV
1328  *    $(SVH x,                asinh(x)       )
1329  *    $(SV  $(NAN),           $(NAN)         )
1330  *    $(SV  $(PLUSMN)0,       $(PLUSMN)0      )
1331  *    $(SV  $(PLUSMN)$(INFIN),$(PLUSMN)$(INFIN))
1332  *    )
1333  */
1334 real asinh(real x) @safe pure nothrow @nogc { return _asinh(x); }
1335 
1336 /// ditto
1337 double asinh(double x) @safe pure nothrow @nogc { return _asinh(x); }
1338 
1339 /// ditto
1340 float asinh(float x) @safe pure nothrow @nogc { return _asinh(x); }
1341 
1342 ///
1343 @safe @nogc nothrow unittest
1344 {
1345     import std.math.traits : isIdentical, isNaN;
1346 
1347     assert(isIdentical(asinh(0.0), 0.0));
1348     assert(isIdentical(asinh(-0.0), -0.0));
1349     assert(asinh(real.infinity) == real.infinity);
1350     assert(asinh(-real.infinity) == -real.infinity);
1351     assert(isNaN(asinh(real.nan)));
1352 }
1353 
1354 private F _asinh(F)(F x)
1355 {
1356     import std.math.traits : copysign;
1357     import core.math : fabs, sqrt;
1358     import std.math.exponential : log, log1p;
1359     import std.math.constants : LN2;
1360 
1361     return (fabs(x) > 1 / F.epsilon)
1362         // beyond this point, x*x + 1 == x*x
1363         ? copysign(F(LN2) + log(fabs(x)), x)
1364         // sqrt(x*x + 1) ==  1 + x * x / ( 1 + sqrt(x*x + 1) )
1365         : copysign(log1p(fabs(x) + x*x / (1 + sqrt(x*x + 1)) ), x);
1366 }
1367 
1368 @safe unittest
1369 {
1370     import std.math.operations : isClose;
1371 
1372     assert(isClose(asinh(sinh(3.0L)), 3.0L, real.sizeof > double.sizeof ? 1e-15 : 1e-14));
1373 }
1374 
1375 /***********************************
1376  * Calculates the inverse hyperbolic tangent of x,
1377  * returning a value from ranging from -1 to 1.
1378  *
1379  * Mathematically, atanh(x) = log( (1+x)/(1-x) ) / 2
1380  *
1381  * $(TABLE_DOMRG
1382  *    $(DOMAIN -$(INFIN)..$(INFIN)),
1383  *    $(RANGE  -1 .. 1)
1384  * )
1385  * $(BR)
1386  * $(TABLE_SV
1387  *    $(SVH  x,     acosh(x) )
1388  *    $(SV  $(NAN), $(NAN) )
1389  *    $(SV  $(PLUSMN)0, $(PLUSMN)0)
1390  *    $(SV  -$(INFIN), -0)
1391  * )
1392  */
1393 real atanh(real x) @safe pure nothrow @nogc
1394 {
1395     import std.math.exponential : log1p;
1396 
1397     // log( (1+x)/(1-x) ) == log ( 1 + (2*x)/(1-x) )
1398     return  0.5 * log1p( 2 * x / (1 - x) );
1399 }
1400 
1401 /// ditto
1402 double atanh(double x) @safe pure nothrow @nogc { return atanh(cast(real) x); }
1403 
1404 /// ditto
1405 float atanh(float x) @safe pure nothrow @nogc { return atanh(cast(real) x); }
1406 
1407 ///
1408 @safe @nogc nothrow unittest
1409 {
1410     import std.math.traits : isIdentical, isNaN;
1411 
1412     assert(isIdentical(atanh(0.0), 0.0));
1413     assert(isIdentical(atanh(-0.0),-0.0));
1414     assert(isNaN(atanh(real.nan)));
1415     assert(isNaN(atanh(-real.infinity)));
1416     assert(atanh(0.0) == 0);
1417 }
1418 
1419 @safe unittest
1420 {
1421     import std.math.operations : isClose;
1422 
1423     assert(isClose(atanh(tanh(0.5L)), 0.5, real.sizeof > double.sizeof ? 1e-15 : 1e-14));
1424 }