The OpenD Programming Language

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