1 // Written in the D programming language
2 
3 /**
4  * Floating-point decimal mathematical functions.
5  *
6  * An implementation of the
7  * General Decimal Arithmetic Specification.
8  *
9  * Authors: Paul D. Anderson
10  *
11  * Copyright: Copyright 2009-2016 by Paul D. Anderson.
12  *
13  * License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>
14  *
15  * Standards: Conforms to the
16  *	General Decimal Arithmetic Specification,
17  *	Version 1.70, (25 March 2009).
18  */
19 
20 module eris.decimal.math;
21 
22 import std.stdio; // for test only
23 
24 import eris.decimal;
25 
26 unittest {
27 	writeln("        math tests        ");
28 	writeln("==========================");
29 }
30 
31 version(unittest) {
32 	import std.stdio;
33 //	import eris.decimal.asserts;
34 	import eris.decimal.test;
35 }
36 
37 /*
38 	TODO: For each function --
39 		1. Ensure algorithm is properly implemented.
40 		2. Ensure context flags are being set properly.
41 		3. Ensure function passes GDA tests.
42 		4. Determine additional tests needed and implement them.
43 		5. Ensure all special cases are enumerated.
44 		6. Automate all tests, if possible.
45 		7. Determine what effect the context has on the function and
46 			if it should be explained.
47 		8. Ensure all documentation is complete:
48 			a. Header - description, inputs, return value(s)
49 			b. Code - variables, control statements, branches, return points.
50 		9. Move most tests to the test module.
51 */
52 
53 /*
54 mixin template checkNaN() {
55 	if (x.isNaN) {
56 		contextFlags.set(INVALID_OPERATION);
57 		return T.nan;
58 	}
59 }*/
60 
61 //--------------------------------
62 // ROUNDING
63 //--------------------------------
64 
65 unittest
66 {
67 	writeln("-------- rounding --------");
68 }
69 /**
70  *  Rounds the argument to the nearest integer. If the argument is exactly
71  *  half-way between two integers the even integer is returned.
72  */
73 public D rint(D)(D num)
74     if (isDecimal!D)
75 {
76   return roundToInt(num, HALF_EVEN);
77 }
78 
79 unittest
80 {  // rint
81   static struct S { D9 num; D9 expect; }
82   S[] s =
83   [
84     {  "2.1",   "2" },
85     {  "100",   "100" },
86     {  "100.0", "100" },
87     {  "101.5", "102" },
88     {  "-101.5", "-102" },
89     {  "10E+5", "1.0E+6" },
90     { "7.89E+77", "7.89E+77" },
91     { "-Inf", "-Infinity" },
92     {  "2.1",  2 },
93     {  "2.5",  2 },
94     {  "3.5",  4 },
95     {  "2.9",  3 },
96     { "-2.1", -2 },
97     { "-2.9", -3 },
98     { "-2.5", -2 },
99   ];
100   auto f = FunctionTest!(S,D9)("rint");
101   foreach (t; s) f.test(t, rint(t.num));
102   writefln(f.report);
103 }
104 
105 /**
106  *  Returns the nearest integer less than or equal to the argument.
107  *  Rounds toward negative infinity.
108  */
109 public T floor(T)(T x) {
110 	return roundToInt(x, FLOOR);
111 }
112 
113 unittest
114 {	// floor
115 	static struct S { TD x; TD expect; }
116 	S[] s =
117 	[
118 		{  "2.1",  2 },
119 		{  "2.5",  2 },
120 		{  "3.5",  3 },
121 		{  "2.9",  2 },
122 		{ "-2.1", -3 },
123 		{ "-2.9", -3 },
124 		{ "-2.5", -3 },
125 	];
126 	auto f = FunctionTest!(S,TD)("floor");
127 	foreach (t; s) f.test(t, floor(t.x));
128   writefln(f.report);
129 }
130 
131 /**
132  *  Returns the nearest integer greater than or equal to the argument.
133  *  Rounds toward positive infinity.
134  */
135 public T ceil(T)(T x) {
136 	return roundToInt(x, CEILING);
137 }
138 
139 unittest
140 {	// ceil
141 	static struct S { TD x; TD expect; }
142 	S[] s =
143 	[
144 		{  "2.1",  3 },
145 		{  "2.5",  3 },
146 		{  "3.5",  4 },
147 		{  "2.9",  3 },
148 		{ "-2.1", -2 },
149 		{ "-2.9", -2 },
150 		{ "-2.5", -2 },
151 	];
152 	auto f = FunctionTest!(S,TD)("ceil");
153 	foreach (t; s) f.test(t, ceil(t.x));
154   writefln(f.report);
155 }
156 
157 /**
158  *  Returns the truncated argument.
159  *  Rounds toward zero.
160  */
161 public T trunc(T)(T x) {
162 	return roundToInt(x, ROUND_DOWN);
163 }
164 
165 unittest
166 {	// trunc
167 	static struct S { TD x; TD expect; }
168 	S[] s =
169 	[
170 		{  "2.1",  2 },
171 		{  "2.5",  2 },
172 		{  "3.5",  3 },
173 		{  "2.9",  2 },
174 		{ "-2.1", -2 },
175 		{ "-2.9", -2 },
176 		{ "-2.5", -2 },
177 	];
178 	auto f = FunctionTest!(S,TD)("trunc");
179 	foreach (t; s) f.test(t, trunc(t.x));
180   writefln(f.report);
181 }
182 
183 /**
184  *  Returns the nearest integer value. If the value is greater (less) than
185  *  the maximum (minimum) int value the maximum (minimum) value is returned.
186  *  The value is rounded based on the specified rounding mode. The default
187  *  mode is half-even.
188  */
189 public int toInt(T)(T x, Round mode = HALF_EVEN)
190 {
191 	if (x.isNaN)
192 	{
193 		throw new InvalidOperationException("NaN cannot be converted to int");
194 	}
195 	if (x.isInfinite)
196 	{
197 		return x.isNegative ? int.min : int.max;
198 	}
199 	return toBigInt(x, mode).toInt;
200 }
201 
202 /**
203  *  Returns the nearest long value. If the value is greater (less) than
204  *  the maximum (minimum) long value the maximum (minimum) value is returned.
205  *  The value is rounded based on the specified rounding mode. The default
206  *  mode is half-even.
207  */
208 public long toLong(T)(T x,
209 		Round mode = HALF_EVEN) if (isDecimal!T)
210 {
211 	if (x.isNaN)
212 	{
213 		throw new InvalidOperationException("NaN cannot be converted to long");
214 	}
215 	if (x.isInfinite)
216 	{
217 		return x.isNegative ? long.min : long.max;
218 	}
219 	return toBigInt(x, mode).toLong;
220 }
221 
222 // FIXTHIS: toBigInt doesn't work?
223 /**
224  *  Returns the nearest extended integer value.
225  *  The value is rounded based on the specified rounding mode. The default
226  *  mode is half-even.
227  */
228 public BigInt toBigInt(T)(T x, Round mode = HALF_EVEN)
229 {
230 	if (x.isNaN)
231 	{
232 		throw new InvalidOperationException("NaN cannot be converted to BigInt");
233 	}
234 	if (x.isInfinite)
235 	{
236 		return x.isNegative ? -T.max.coff : T.max.coff;
237 	}
238 	if (x.expo != 0)
239 	{
240 		return roundToInt(x, mode).coff;
241 	}
242 	return x.coff;
243 }
244 
245 //--------------------------------
246 //	string mixins
247 //--------------------------------
248 
249 /*template Constant(string name)
250 {
251 const char[] Constant =
252 	"/// Returns the value of the constant at the specified precision.
253 	public T " ~ name ~ "(T)(int precision = T.precision) if (isDecimal!T)
254 	{
255 		Context context = Context(precision, T.maxExpo, T.mode);
256 		static T value;
257 		static int lastPrecision = 0;
258 		if (precision == lastPrecision) return value;
259 		if (precision > lastPrecision) {
260 			value = eris.decimal.math." ~ name ~ "!T(context);
261 			lastPrecision = precision;
262 		}
263 		return round(value, precision);
264 	}";
265 }*/
266 
267 /*template UnaryFunction(string name)
268 {
269 const char[] UnaryFunction =
270 
271 	"/// Returns the value of the function at the specified precision.
272 	public T " ~ name ~ "(T, U:int)(T x, U precision = T.precision) if (isDecimal!T)
273 	{
274 		if (x.isNaN) {
275 			contextFlags.set(INVALID_OPERATION);
276 			return T.nan;
277 		}
278 		Context context = Context(precision, T.maxExpo, HALF_EVEN);
279 		return " ~ name ~ "!T(x, context);
280 	}
281 
282 	/// Returns the value of the function at the specified precision.
283 	public T " ~ name ~ "(T,S:string)(S str, int precision = T.precision) if (isDecimal!T) {
284 		T x = T(str);
285 		return " ~ name ~ "!T(x, precision);
286 	}
287 
288 	/// Returns the value of the function at the specified precision.
289 	public T " ~ name ~ "(T,L:long)(L n, int precision = T.precision) if (isDecimal!T) {
290 		T x = T(n);
291 		return " ~ name ~ "!T(x, precision);
292 	}
293 
294 	/// Returns the value of the function at the specified precision.
295 	public T " ~ name ~ "(T,R:real)(R a, int precision = T.precision)  if (isDecimal!T){
296 		T x = T(a);
297 		return " ~ name ~ "!T(x, precision);
298 	}";
299 }
300 */
301 
302 template UnaryFunction(string name)
303 {
304   const char[] UnaryFunction =
305 
306   "/// Returns the value of the function at the specified precision.
307   public T " ~ name ~ "(T)(T x, int precision = T.precision) if (isDecimal!T)
308   {
309     if (x.isNaN)
310     {
311       contextFlags.set(INVALID_OPERATION);
312       return T.nan;
313     }
314     Context context = Context(precision, T.maxExpo, HALF_EVEN);
315     return " ~ name ~ "!T(x, context);
316   }
317 
318   /// Returns the value of the function at the specified precision.
319   public T " ~ name ~ "(T,U)(U num, int precision)
320     if (isDecimal!T && isConvertible!U)
321   {
322     T x = T(num);
323     return " ~ name ~ "!T(x, precision);
324   }";
325 }
326 
327 template BinaryFunction(string name)
328 {
329 const char[] BinaryFunction =
330 
331   "/// Returns the value of the function at the specified precision.
332   public T " ~ name ~ "(T)(T x, T y, int precision = T.precision)
333   if (isDecimal!T)
334   {
335     if (x.isNaN || y.isNaN)
336     {
337       contextFlags.set(INVALID_OPERATION);
338       return T.nan;
339     }
340     Context context = Context(precision, T.maxExpo, HALF_EVEN);
341     return " ~ name ~ "!T(x, y, context);
342   }";
343 }
344 
345 //--------------------------------
346 //	CONSTANTS
347 //--------------------------------
348 
349 unittest
350 {
351 	writeln("------- constants --------");
352 }
353 
354 public immutable D M_PI(D) = D(roundStr(
355   "3.1415926535897932384626433832795028841971693993751" ~
356     "0582097494459230781640628620899862803482534211707",
357   D.precision));
358 
359 public immutable D M_E(D) = D(roundStr(
360   "2.7182818284590452353602874713526624977572470936999" ~
361     "5957496696762772407663035354759457138217852516643",
362   D.precision));
363 
364 public immutable D M_LN2(D) = D(roundStr(
365   "0.69314718055994530941723212145817656807550013436025" ~
366     "52541206800094933936219696947156058633269964186887",
367   D.precision));
368 
369 public immutable D M_LN10(D) = D(roundStr(
370   "2.3025850929940456840179914546843642076011014886287" ~
371     "7297603332790096757260967735248023599720508959820",
372   D.precision));
373 
374 public immutable D M_LOG2E(D) = D(roundStr(
375   "1.4426950408889634073599246810018921374266459541529" ~
376     "8593413544940693110921918118507988552662289350634",
377   D.precision));
378 
379 public immutable D M_LOG2T(D) = D(roundStr(
380   "3.3219280948873623478703194294893901758648313930245" ~
381     "8061205475639581593477660862521585013974335937016",
382   D.precision));
383 
384 public immutable D M_LOG10E(D) = D(roundStr(
385   "4.3429448190325182765112891891660508229439700580366" ~
386     "6566114453783165864649208870774729224949338431748",
387   D.precision));
388 
389 public immutable D M_LOGT2(D) = D(roundStr(
390   "0.30102999566398119521373889472449302676818988146210" ~
391     "8541310427461127108189274424509486927252118186172",
392   D.precision));
393 
394 public immutable D M_SQRT2(D) = D(roundStr(
395   "1.4142135623730950488016887242096980785696718753769" ~
396     "4807317667973799073247846210703885038753432764157",
397   D.precision));
398 
399 unittest
400 {  // constants
401   static struct S { TD x; TD expect; }
402   S[] s =
403   [
404     { M_E!TD,     "2.718281828459045" },
405     { M_PI!TD,  "3.141592653589793" },
406     { M_LN2!TD,   "0.6931471805599453" },
407     { M_LN10!TD,  "2.302585092994046" },
408     { M_SQRT2!TD, "1.414213562373095" },
409 //      { TD.INV_PI,"0.318309886" },
410   ];
411   auto f = FunctionTest!(S,TD)("constants");
412   foreach (t; s) f.test(t, t.x);
413   writefln(f.report);
414 }
415 
416 mixin template MCInit(D, string str)
417 {
418   enum D typeValue = roundString(str, D.precision);
419   static D value = typeValue;
420   static int last = D.precision;
421   static D highValue = typeValue;
422   static int high = D.precision;
423 }
424 
425 //mixin template MCType(D)
426 //{
427 //  if
428 
429 /// If a constant has already been calculated, this function attempts
430 /// to use an existing value rather than recalculate.
431 /// If the constant has not yet been calculated to the desired precision,
432 /// returns false.
433 package D Constant(D, D typeValue)(/*D function(int) calc, */int precision)
434     if (isDecimal!D)
435 {
436   static D value = typeValue;
437   static int last = D.precision;
438   static D highValue = typeValue;
439   static int high = D.precision;
440 
441   if (precision == D.precision) return typeValue;
442 
443   // if the input precision <= last precision used
444   if (precision == last) return value;
445   if (precision < last)
446   {
447     last = precision;
448     value = round(value, precision);
449     return value;
450   }
451 
452   // if the input precision <= highest precision used
453   if (precision == high)
454   {
455     last = high;
456     value = highValue;
457     return value;
458   }
459   if (precision < high)
460   {
461     last = precision;
462     value = round(highValue, precision);
463     return value;
464   }
465   high = precision;
466   last = precision;
467   return D.nan;
468 }
469 
470 private Context calcContext(D)(int precision, int guardDigits = 2)
471 {
472   return Context(precision + guardDigits, D.maxExpo, HALF_EVEN);
473 }
474 
475 /// Returns pi (3.14159265...) at the specified precision.
476 /// If the precision is less than or equal to a prior precision,
477 /// the earlier calculated value is returned (rounded if needed).
478 /// If the specified precision is higher than any previously calculated
479 /// precision, then the constant is recalculated and the higher value
480 /// is retained for subsequent use.
481 /// Repeated calls to the function at the same precision perform no rounding
482 /// or calculation.
483 public static D pi(D)(int precision = D.precision) if (isDecimal!D)
484 {
485   D value = Constant!(D, M_PI!D)(precision);
486   if (value.isNaN) value = calcPi!D(precision);
487   return value;
488 }
489 
490 /// Returns pi (3.14159265...) for the specified context.
491 public D calcPi(D)(int precision) if (isDecimal!D)
492 {
493   // TODO: (behavior) if only 2 guard digits are used, function doesn't return
494   auto ctxt = calcContext!D(precision, 3);
495   // AGM algorithm
496   long k = 1;
497   D a0 = D.one;
498   D b0 = D.HALF * sqrt2!D(precision);
499   D s0 = D(5,-1);//.HALF;
500   D a1, b1, s1;
501   // loop until the arithmetic mean equals the geometric mean
502   while (!equals(a0, b0, ctxt))
503   {
504     // arithmetic mean: a1 = (a0+bo)/2))
505     a1 = mul(D.HALF, add(a0, b0, ctxt), ctxt);
506     // geometric mean: b1 = sqrt(a0*b0)
507     b1 = sqrt(mul(a0, b0, ctxt), ctxt);
508     k *= 2;
509     s1 = sub(s0, mul(sub(sqr(a1, ctxt), sqr(b1, ctxt), ctxt), k, ctxt), ctxt);
510     a0 = a1;
511     b0 = b1;
512     s0 = s1;
513   }
514   D pi = mul(div(sqr(a1, ctxt), s1, ctxt), 2, ctxt);
515   return round(pi, precision, D.mode);
516 }
517 
518 unittest
519 {  // pi
520   static struct S { int n; TD expect; }
521   S[] s =
522   [
523     {  9, "3.14159265" },
524     { 10, "3.141592654" },
525     { 12, "3.14159265359" },
526     { 20, "3.1415926535897932385" },
527     { 14, "3.1415926535898" },
528     { 16, "3.141592653589793" },
529     { 18, "3.14159265358979324" },
530     { 22, "3.141592653589793238463" },
531     { 23, "3.1415926535897932384626" },
532     { 24, "3.14159265358979323846264" },
533     { 25, "3.141592653589793238462643" },
534     { 26, "3.1415926535897932384626434" },
535   ];
536   auto f = FunctionTest!(S,TD)("pi");
537   foreach (t; s) f.test(t, pi!TD(t.n), t.n);
538   writefln(f.report);
539 }
540 
541 /*//mixin (Constant!("pi_2"));
542 package T pi_2(T)(Context inContext) if (isDecimal!T)
543 {
544 	auto context = guard(inContext);
545 	T halfPi = mul(pi!T(context), T.HALF, context);
546 	return round(halfPi, inContext);
547 }*/
548 
549 /*unittest
550 {	// pi_2
551 	static struct S { int n; TD expect; }
552 	S[] s =
553 	[
554 		{  9, "1.57079633" },
555 		{ 25, "1.570796326794896619231322" },
556 		{  5, "1.5708234" },	// note extra incorrect digits
557 	];
558 	auto f = FunctionTest!(S,TD)("pi/2");
559 	foreach (t; s) f.test(t, TD.pi_2(t.n), t.n);
560   writefln(f.report);
561 }*/
562 
563 //mixin (Constant!("M_1_PI"));
564 // TODO: shouldn't this be a calculation without a division?
565 /// Calculates the value of 1/pi in the specified context.
566 package D M_1_PI(D)(Context inContext) if (isDecimal!D)
567 {
568 	auto context = guard(inContext, 4);
569 	D alpha =  div(D.ONE, pi!D(context), context);
570 	return round(alpha, inContext);
571 }
572 
573 /*unittest
574 {	// M_1_PI
575 	static struct S { int n; TD expect; }
576 	S[] s =
577 	[
578 		{  9, "0.318309886" },
579 		{ 25, "0.3183098861837906715377675" },
580 		{  5, "0.3183144449" },	// note extra incorrect digits
581 	];
582 	auto f = FunctionTest!(S,TD)("1/pi");
583 	foreach (t; s) f.test(t, TD.M_1_PI(t.n), t.n);
584   writefln(f.report);
585 }*/
586 
587 //mixin (Constant!("M_2_PI"));
588 // TODO: (efficiency) Need to ensure that previous version of pi isn't reset.
589 // TODO: shouldn't this be a calculation without a division?
590 /// Calculates the value of 1/pi in the specified context.
591 package D M_2_PI(D)(Context inContext) if (isDecimal!D)
592 {
593 	auto context = guard(inContext, 4);
594 	D alpha =  div(D.TWO, pi!D(context.precision), context);
595 	return round(alpha, inContext);
596 }
597 
598 /*unittest
599 {	// M_2_PI
600 	static struct S { int n; TD expect; }
601 	S[] s =
602 	[
603 		{  9, "0.636619772" },
604 		{ 25, "0.6366197723675813430755351" },
605 		{  5, "0.63662" },
606 	];
607 	auto f = FunctionTest!(S,TD)("2/pi");
608 	foreach (t; s) f.test(t, TD.M_2_PI(t.n), t.n);
609   writefln(f.report);
610 }*/
611 
612 
613 public D e(D)(int precision = D.precision) if (isDecimal!D)
614 {
615   D value = Constant!(D, M_E!D)(precision);
616   if (value.isNaN) value = calcE!D(precision);
617   return value;
618 }
619 
620 /// Calculates the value of e to the specified precision.
621 /// Returns the calculated value.
622 package D calcE(D)(int precision = D.precision) if (isDecimal!D)
623 {
624   auto context = calcContext!D(precision);
625   auto epsilon = D.epsilon(context);
626   // initialize Taylor series.
627   D term = D.one;
628   D sum  = D.one;
629   // loop until the term is too small to affect the sum.
630   long n = 2;
631   while (term > epsilon) {
632     sum  = add(sum, term, context);
633     term = div!D(term, n, context);
634     n++;
635   }
636   return round(sum, precision, D.mode);
637 }
638 
639 unittest
640 {  // e
641   static struct S { int n; TD expect; }
642   S[] s =
643   [
644     {  9, "2.71828183" },
645     { 25, "2.7182818284590452353602874713526625" },
646     {  5, "2.7183" },
647   ];
648   auto f = FunctionTest!(S,TD)("e");
649   foreach (t; s) f.test(t, e!TD(t.n), t.n);
650   writefln(f.report);
651 }
652 
653 /// natural logarithm of 2 = 0.693147806...
654 public D ln2(D)(int precision = D.precision)
655 {
656   D value = Constant!(D, M_LN2!D)(precision);
657   if (value.isNaN) value = log(D.TEN, precision);
658   return value;
659 }
660 
661 /// natural logarithm of 10 = 2.30258509...
662 public D ln10(D)(int precision = D.precision)
663 {
664   D value = Constant!(D, M_LN10!D)(precision);
665   if (value.isNaN) value = log(D.TEN, precision);
666   return value;
667 }
668 
669 
670 /// base 2 logarithm of e = 1.44269504...
671 public D lbe(D)(int precision = D.precision)
672 {
673   mixin MCInit!(D,
674   "1.44269504088896340735992468100189213" ~
675   "742664595415298593413544940693110921918118507988552662289350634" );
676 
677   if (precision == D.precision) return typeValue;
678 
679   // attempt to use previously calculated values
680   if (Constant!D(precision, last, value, high, highValue)) return value;
681 
682   high = precision;
683   last = high;
684   value = log(D.TEN, precision);
685   return value;
686 }
687 
688 
689 /*/// base 2 logarithm of 10 = 3.32192809...
690 public enum decimal LB10 = roundString(
691   "3.3219280948873623478703194294893901" ~
692   "7586483139302458061205475639581593477660862521585013974335937016",
693   decimal.precision);
694 
695 /// base 10 logarithm of 2 = 0.301029996...
696 public enum decimal LG2 = roundString(
697   "0.3010299956639811952137388947244930" ~
698   "26768189881462108541310427461127108189274424509486927252118186172",
699   decimal.precision);
700 
701 /// base 10 logarithm of e  = 4.34294482...
702 public enum decimal LGE = roundString(
703   "4.3429448190325182765112891891660508" ~
704   "2294397005803666566114453783165864649208870774729224949338431748",
705   decimal.precision);
706 
707 /// golden ratio = 1.6180339887...
708 public enum decimal PHI = roundString(
709   "1.6180339887498948482045868343656381177" ~
710   "20309179805762862135448622705260462818902449707207204189391137",
711   decimal.precision);
712 */
713 /// Returns the square root of two (1.41421357...) at the specified precision.
714 public D sqrt2(D)(int precision = D.precision)
715 {
716   D value = Constant!(D, M_SQRT2!D)(precision);
717   if (value.isNaN) value = sqrt(D(2), precision);
718   return value;
719 }
720 
721 
722 /*//mixin (Constant!("ln10"));
723 package enum T ln10(T)(Context context) if (isDecimal!T)
724 {
725 	return log(T.TEN, context, false);
726 }*/
727 
728 //mixin (Constant!("ln2"));
729 package enum T ln2(T)(Context context) if (isDecimal!T)
730 {
731 	return log(T.TWO, context, false);
732 }
733 
734 //mixin (Constant!("log2_e"));
735 package enum T log2_e(T)(Context context) if (isDecimal!T)
736 {
737 	return div(T.one, log(T.TWO, context, false), context);
738 }
739 
740 //mixin (Constant!("log2_10"));
741 package enum T log2_10(T)(Context inContext) if (isDecimal!T)
742 {
743 	auto context = guard(inContext);
744 	T log2T = div(log(T.TEN, context, false), log(T.TWO, context, false), context);
745 	return round(log2T, inContext);
746 //	return round(TD("18690473486004564289165545643685440097"), inContext);
747 //	return round(TD("18690473486004564245643685440097"), inContext);
748 }
749 
750 //mixin (Constant!("log10_e"));
751 package enum T log10_e(T)(Context context) {
752 	return T.one/log(T.TEN, context, false);
753 }
754 
755 //mixin (Constant!("log10_2"));
756 package enum T log10_2(T)(Context context) {
757 	return log(T.TWO, context)/log(T.TWO, context, false);
758 }
759 
760 //mixin (Constant!("M_SQRT2"));
761 package enum T sqrt2(T)(Context context) if (isDecimal!T)
762 {
763 	return sqrt(T.TWO, context);
764 }
765 
766 //mixin (Constant!("M_SQRT1_2"));
767 package enum D M_SQRT1_2(D)(Context context) if (isDecimal!D)
768 {
769 	return sqrt(D.HALF, context);
770 }
771 
772 //mixin (Constant!("phi"));
773 package enum T phi(T)(Context context) if (isDecimal!T)
774 {
775 	return mul(add(T(1) , sqrt(T(5), context), context), T.half, context);
776 }
777 
778 //mixin (Constant!("invSqrtPi"));
779 package enum T invSqrtPi(T)(Context inContext) if (isDecimal!T)
780 {
781 	auto context = guard(inContext, 4);
782 	T alpha =  div(T.one, sqrt(pi!T(context), context), context);
783 	return round(alpha, inContext);
784 }
785 
786 /*unittest
787 {	// constants
788 	static struct S { TD x; int p; TD expect; }
789 	S[] s =
790 	[
791 		{ TD.ln10,    9,  "2.30258509" },
792 		{ TD.ln2,     9,  "0.693147181" },
793 		{ TD.log2_e,  9,  "1.44269504" },
794 		{ TD.log2_10, 9,  "3.32192809" },
795 		{ TD.M_SQRT2,   9,  "1.41421356" },
796 		{ TD.M_SQRT1_2, 9,  "0.707106781" },
797 		{ TD.phi,     9,  "1.61803399" },
798 		{ TD.ln10(16),    16, "2.302585092994046" },
799 		{ TD.ln2(16),     16, "0.6931471805599453" },
800 		{ TD.log2_e(16),  16, "1.442695040888963" },
801 		{ TD.log2_10(16), 16, "3.21928094887362" }, // FIXTHIS: returns 3.321457567817785
802 		{ TD.M_SQRT2(16),   16, "1.414213562373095" },
803 		{ TD.M_SQRT1_2(16), 16, "0.7071067811865475" },
804 		{ TD.phi(16),     16, "1.618033988749895" },
805 	];
806 	auto f = FunctionTest!(S,TD)("constants");
807 	foreach (t; s) f.test(t, t.x, t.p);
808   writefln(f.report);
809 }*/
810 
811 //--------------------------------
812 //	ALGEBRAIC FUNCTIONS
813 //--------------------------------
814 
815 /// Returns true if n is odd, false otherwise.
816 private bool isOdd(int n) {
817 	return n & 1;
818 }
819 
820 unittest {	// isOdd
821 	assertTrue(isOdd(3));
822 	assertTrue(!isOdd(8));
823 	assertTrue(isOdd(-1));
824 }
825 
826 // TODO: (behavior) add bitshift function?
827 
828 //mixin (UnaryFunction!("reciprocal"));
829 mixin (UnaryFunction!("invSqrt"));
830 mixin (UnaryFunction!("sqrt"));
831 
832 /// Returns the value of the function at the specified precision.
833 public T reciprocal(T, U:int)(T x, U precision) if (isDecimal!T)
834 {
835 	if (x.isNaN) {
836 		contextFlags.set(INVALID_OPERATION);
837 		return T.nan;
838 	}
839 	Context context = Context(precision, T.maxExpo, HALF_EVEN);
840 	return reciprocal!T(x, context);
841 }
842 
843 /*/// Returns the value of the function at the specified precision.
844 public T reciprocal(T, U)(in U u, int precision)
845 	if (isDecimal!T && isConvertible!U)
846 {
847 	T x = T(u);
848 	if (x.isNaN) {
849 		contextFlags.set(INVALID_OPERATION);
850 		return T.nan;
851 	}
852 	Context context = Context(precision, T.maxExpo, HALF_EVEN);
853 	return reciprocal!T(T(x), context);
854 }*/
855 
856 // TODO: what happens if x is very close to zero or one?
857 // Does it try to work with the numbers anyway??
858 public T reciprocal(T)(in T x, Context inContext = T.context) if (isDecimal!T)
859 {
860 	// special values
861 	if (x.isZero) {
862 		contextFlags.set(DIVISION_BY_ZERO);
863 		return T.infinity(x.sign);
864 	}
865 	if (x.copyAbs.isOne) return x.copy;
866 	if (x.isInfinite) return T.zero(x.sign);
867 
868 	// extend working precision
869 	auto context = guard(inContext);
870 
871 	// initial estimate
872 	T a = x.reduce;
873 	T r1 = T(2, -ilogb(a)-1);
874 
875 	// Newton's method
876 	while (true) {
877 		T r0 = r1;
878 		r1 = mul(r0, sub(T.TWO, mul(a, r0, context), context), context);
879 		if (equals(r0, r1 ,context)) break;
880 	}
881 	// round to the original precision
882 	return round(r1, context);
883 }
884 
885 unittest
886 {	// reciprocal
887 	static struct S { TD x; TD expect; }
888 	S[] s =
889 	[
890 //		{ "1234567890123456789", TD(1)/TD("1234567890123456789") },
891 //		{ "1234567890678900000", TD(1)/TD("1234567890123456789") },
892 		{ "125", "0.008" },
893 		{ "0.008", "125" },
894 	];
895 	auto f = FunctionTest!(S,TD)("reciprocal");
896 	foreach (t; s) f.test(t, reciprocal(t.x));
897   writefln(f.report);
898 }
899 
900 // TODO: see note at reciprocal
901 public T invSqrt(T)(T x, Context inContext) if (isDecimal!T)
902 {
903 	// special values
904 	if (x.isZero) {
905 		contextFlags.set(DIVISION_BY_ZERO);
906 		return T.infinity(x.sign);
907 	}
908 	if (x.isOne) return x;
909 	if (x.isInfinite) return T.zero(x.sign);
910 
911 	// increase the working precision
912 	auto context = guard(inContext);
913 
914 	// initial estimate
915 	T a;
916 	int k = ilogb(x);
917 	if (isOdd(k)) {
918 		a = T(2, -1);
919 	}
920 	else {
921 		a = T(5, -1);
922 		k++;
923 	}
924 	const t = T(3);
925 	// reduce the exponent
926 	x.expo = x.expo - k - 1;
927 	// Newton's method
928 	while (true) {
929 		T b = a;
930 		a = mul(b, mul(T.HALF, sub(t, mul(x, sqr(b, context), context), context), context), context);
931 		if (equals(b, a, context)) break;
932 	}
933 	// restore the exponent
934 	a.expo = a.expo - k/2 - 1;
935 	// round to the original precision
936 	return round(a, inContext);
937 }
938 
939 /*unittest
940 {	// invSqrt
941 	static struct S { TD x; int n; TD expect; }
942 	S[] s =
943 	[
944 		{ "2", 6, "0.707107" },
945 		{ "20", 9, "0.223606798" },
946 		{ "300", 9, "0.0577350269" },
947 		{ "98763", 9, "0.00318201969" },
948 		{ "98763098", 9, "0.000100624248" },
949 		{ "0.008", 9, "1.11803399" },
950 		{ "98763098", 9, "0.000100624248" },
951 		{ "9876387982347", 9, "3.18200552E-7" },
952 		{ "2", 14, "0.70710678118655" },
953 		{ "4000", 11, "0.015811388301" },
954 	];
955 	auto f = FunctionTest!(S,TD)("invSqt");
956 	foreach (t; s) f.test(t, invSqrt(t.x,t.n));
957   writefln(f.report);
958 }*/
959 
960 /// Returns the square root of the argument to the current precision.
961 /// Uses Newton's method.
962 public D sqrt(D)(D arg, Context context) if (isDecimal!D)
963 {
964 //  auto context = guard(inContext, 3);
965   // special values
966   if (arg.isNegative) {
967     contextFlags.set(INVALID_OPERATION);
968     return D.nan;
969   }
970   // TODO: what if arg is very close to one or zero??
971   if (arg.isOne) return D.one;
972   if (arg.isZero) return D.zero;
973   if (arg.isInfinite) return D.infinity;
974 
975   // reduce the exponent and estimate the result
976   D value;
977   int k = ilogb(arg);
978   if (isOdd(k)) {
979     value = D(6, -1);
980   }
981   else {
982     value = D(2, -1);
983     k++;
984   }
985   arg.expo = arg.expo - k - 1;
986 
987   // Newton's method
988   while (true) {
989     D prev = value;
990     value = mul(D.HALF, add(prev, div(arg, prev, context), context), context);
991     if (equals(value, prev, context)) break;
992   }
993   // restore the exponent
994   value.expo = value.expo + (k+1)/2;
995   // round the result
996   return round(value, context);
997 }
998 
999 unittest
1000 {  // sqrt
1001   static struct S { TD x; int p; TD expect; }
1002   S[] s =
1003   [
1004     { "2", 9, "1.41421356" },
1005     { "0.707106781187", 12, "0.840896415254" },
1006     { "200", 21, "14.142135623730950488000" },
1007     { "25", 8, "5.0" },
1008     { "2E-5", 10, "0.00447213595500" },
1009     { "1E-15", 9, "3.16227766E-8" },
1010     { "1E-16", 9, "1.00000000E-8" },
1011   ];
1012   auto f = FunctionTest!(S,TD)("sqrt");
1013   foreach (t; s) f.test(t, sqrt(t.x, t.p), t.p);
1014   writefln(f.report);
1015 }
1016 
1017 //--------------------------------
1018 // EXPONENTIAL AND LOGARITHMIC FUNCTIONS
1019 //--------------------------------
1020 
1021 /+mixin (UnaryFunction!("exp"));
1022 
1023 	"/// Returns the value of the function at the specified precision.
1024 	public T " ~ name ~ "(T)(T x, int precision = T.precision) if (isDecimal!T)
1025 	{
1026 		if (x.isNaN) {
1027 			contextFlags.set(INVALID_OPERATION);
1028 			return T.nan;
1029 		}
1030 		Context context = Context(precision, T.maxExpo, HALF_EVEN);
1031 		return " ~ name ~ "!T(x, context);
1032 	}
1033 +/
1034 
1035 //--------------------------------
1036 // exponentials and logarithms
1037 //--------------------------------
1038 
1039 /// Adds guard digits to the current precision and sets rounding to HALF_EVEN.
1040 /// This is useful for extended calculation to minimize errors.
1041 /// Returns a new context with the precision increased by the guard digits value.
1042 /// Note that this does not create a new Decimal type with this context.
1043 public Context guard(Context context, int guardDigits = 2)
1044 {
1045   return Context(context.precision + guardDigits, context.maxExpo, HALF_EVEN);
1046 }
1047 
1048 /// Changes the current precision and sets rounding to HALF_EVEN.
1049 /// This is useful for extended calculation to minimize errors.
1050 /// Returns a new context with the precision increased by the guard digits value.
1051 /// Note that this does not create a new Decimal type with this context.
1052 public Context changePrecision(Context context, int precision)
1053 {
1054   return Context(precision, context.maxExpo, HALF_EVEN);
1055 }
1056 
1057 /// Returns the exponent of the argument at the specified precision.
1058 public D exp(D)(in D arg, int precision)
1059     if (isDecimal!D || isConvertible(D))
1060   {
1061     D num = D(arg);
1062 
1063     // check for nan
1064     if (num.isNaN)
1065     {
1066       contextFlags.set(INVALID_OPERATION);
1067       return D.nan;
1068     }
1069     // create new context at given precision
1070     Context context = changePrecision(D.context, precision);
1071     // call the function
1072     return exp!D(num, context);
1073   }
1074 
1075 /// Returns the exponent of the argument at the current precision.
1076 /// Decimal version of std.math function.
1077 /// Required by General Decimal Arithmetic Specification
1078 public D exp(D)(D num, Context context = D.context, int guardDigits = 2)
1079     if (isDecimal!D)
1080 {
1081   if (num.isInfinite)
1082   {
1083     return num.isNegative ? D.zero : num;
1084   }
1085   bool negative = num.isNegative;
1086   if (negative) num = num.copyAbs;
1087   auto guarded = guard(context, guardDigits);
1088   D sqrx = sqr(num, guarded);
1089   long n = 1;
1090   D fact = 1;
1091   D t1   = D.one;
1092   D t2   = num;
1093   D term = add(t1, t2, guarded);
1094   D sum  = term;
1095   while (term > D.epsilon(guarded))
1096   {
1097     n   += 2;
1098     t1   = mul(t2, mul(num, n, guarded), guarded);
1099     t2   = mul(t2, sqrx, guarded);
1100     fact = mul(fact, n*(n-1), guarded);
1101     term = div(add(t1, t2, guarded), fact, guarded);
1102     sum  = add(sum, term, guarded);
1103   }
1104   if (negative) sum = div(D.one, sum, guarded);
1105   return round(sum, context);
1106 }
1107 
1108 unittest
1109 {  // exp
1110   static struct S { TD x; int p; TD expect; }
1111   S[] s =
1112   [
1113     {  1, 9, "2.71828183" },
1114     {  2, 9, "7.3890560989306502272" },
1115     { -2, 9, "0.13533528324" },
1116     {  1, 9, "2.71828183" },
1117     {  1, 11, "2.7182818285" },
1118     {  1, 15, "2.71828182845905" },
1119     {  2, 15, "7.3890560989306502272" },
1120     {  2, 11, "7.3890560989306502272" },
1121     { -2, 11, "0.13533528324" },
1122   ];
1123   auto f = FunctionTest!(S,TD)("exp");
1124   foreach (t; s) f.test(t, exp(t.x, t.p), t.p);
1125   writefln(f.report);
1126 }
1127 
1128 public enum D ln10(D)(Context context) if (isDecimal!D)
1129 {
1130   return log(D.TEN, context, false);
1131 }
1132 
1133 /// Returns the logarithm of the argument at the specified precision.
1134 public D log(D)(in D arg, int precision = D.precision)
1135     if (isDecimal!D || isConvertible(D))
1136 {
1137   D num = D(arg);
1138    // check for nan
1139   if (num.isNaN)
1140   {
1141     contextFlags.set(INVALID_OPERATION);
1142     return D.nan;
1143   }
1144   // create new context at input precision
1145   Context context = Context(precision, D.maxExpo, HALF_EVEN);
1146   // call the function
1147   return log!D(num, context);
1148 }
1149 
1150 public D log(D)(D num, Context context,
1151     bool reduceArg = true) if (isDecimal!D)
1152 {
1153   if (num.isZero)
1154   {
1155     contextFlags.set(DIVISION_BY_ZERO);
1156     return -D.infinity;
1157   }
1158   if (num.isNegative) return D.nan;
1159   if (num.isInfinite) return D.infinity;
1160 
1161   auto guarded = guard(context);
1162   int k;
1163   if (reduceArg)
1164   {
1165     k = ilogb(num) + 1;
1166     num.expo = num.expo - k;
1167   }
1168   D a = div(sub(num, 1, guarded), add(num, 1, guarded), guarded);
1169   D b = sqr(a, guarded);
1170   D c = a;
1171   long n = 3;
1172   while (true)
1173   {
1174     c = mul(c, b, guarded);
1175     D d = add(a, div(c, n, guarded), guarded);
1176     if (equals(a, d, guarded))
1177     {
1178       D ln = mul(a, 2, guarded);
1179       if (reduceArg)
1180       {
1181         ln = add(ln, mul(ln10!D(guarded), k, guarded), guarded);
1182       }
1183       return round(ln, context);
1184     }
1185     a = d;
1186     n += 2;
1187   }
1188 }
1189 
1190 unittest
1191 {	// log
1192 	static struct S { TD x; int p; TD expect; }
1193 	S[] s =
1194 	[
1195 		{  "2.71828183",  9, "1.0" },
1196 		{  "10.00",      12, "2.30258509299" },
1197 		{  "10.00",       9, "2.30258509" },
1198 		{ "123.45",       9, "4.81583622" },
1199 		{  "99.999E+8",   9, "23.0258409" },
1200 		{  "99.999E+8",   7, "23.0258409" },
1201 		{  "99.999E+8",  15, "23.0258409298905" },
1202 		{  "99.999E+8",   9, "23.0258409" },
1203 	];
1204 	auto f = FunctionTest!(S,TD)("log");
1205 	foreach (t; s) f.test(t, log(t.x, t.p), t.p);
1206   writefln(f.report);
1207 }
1208 
1209 
1210 /*/// Decimal version of std.math function.
1211 /// Required by General Decimal Arithmetic Specification
1212 package D exp(D)(D x, Context inContext) if (isDecimal!D)
1213 {
1214   if (x.isInfinite)
1215   {
1216     return x.isNegative ? D.zero : x;
1217   }
1218   bool negative = x.isNegative;
1219   if (negative) x = x.copyAbs;
1220   auto context = guard(inContext);
1221   D sqrx = sqr(x, context);
1222   long n = 1;
1223   D fact = 1;
1224   D t1   = D.one;
1225   D t2   = x;
1226   D term = add(t1, t2, context);
1227   D sum  = term;
1228   while (term > D.epsilon(context))
1229   {
1230     n   += 2;
1231     t1   = mul(t2, mul(x, n, context), context);
1232     t2   = mul(t2, sqrx, context);
1233     fact = mul(fact, n*(n-1), context);
1234     term = div(add(t1, t2, context), fact, context);
1235     sum  = add(sum, term, context);
1236   }
1237   if (negative) sum = div(D.one, sum, context);
1238   return round(sum, inContext);
1239 }
1240 
1241 unittest
1242 {  // exp
1243   static struct S { TD x; int p; TD expect; }
1244   S[] s =
1245   [
1246     {  1, 9, "2.71828183" },
1247     {  2, 9, "7.3890560989306502272" },
1248     { -2, 9, "0.13533528324" },
1249     {  1, 9, "2.71828183" },
1250     {  1, 11, "2.7182818285" },
1251     {  1, 15, "2.71828182845905" },
1252     {  2, 15, "7.3890560989306502272" },
1253     {  2, 11, "7.3890560989306502272" },
1254     { -2, 11, "0.13533528324" },
1255   ];
1256   auto f = FunctionTest!(S,TD)("exp");
1257   foreach (t; s) f.test(t, exp(t.x, t.p), t.p);
1258   writefln(f.report);
1259 }
1260 */
1261 /+
1262 /**
1263  * Decimal version of std.math function.
1264  * 2^x
1265  */
1266 public Decimal exp2T)( arg) {
1267 	Decimal result;
1268 	return result;
1269 }
1270 
1271 unittest {
1272 	write("exp2...........");
1273 	writeln("test missing");
1274 }
1275 +/
1276 
1277 mixin (UnaryFunction!("expm1"));
1278 
1279 /// expm1(x) will be more accurate than exp(x) - 1 for x << 1.
1280 /// Decimal version of std.math function.
1281 /// Reference: Beebe, Nelson H. F., "Computation of expm1(x) = exp(x) - 1".
1282 public T expm1(T)(T x, Context inContext) if (isDecimal!T)
1283 {
1284 	// special values
1285 	if (x.isZero) return x;
1286 	if (x.isInfinite) return x.isNegative ? -T.one : T.infinity;
1287 
1288 	auto context = guard(inContext);
1289 	T sum = T.zero;
1290 
1291 	// if too large return exp(x) - 1.
1292 	const T lower = T("-0.7");
1293 	const T upper = T("0.5");
1294 	// ??? what is this --> if (x.copyAbs < lower || x.copyAbs > upper) {
1295 	if (x < lower || x > upper) {
1296 		sum = sub(exp(x, context), 1, context);
1297 		return round(sum, inContext);
1298 	}
1299 
1300 	bool negative = x.isNegative;
1301 	if (negative) x = x.copyAbs;
1302 /*	// if too large return exp(x) - 1.
1303 	if (x < lower || x > upper) {
1304 		sum = sub(exp(x, context), 1, context);
1305 		return round(sum, inContext);
1306 	}*/
1307 
1308 	// otherwise return expm1(x)
1309 	T term = x;
1310 	long n = 1;
1311 	while (term.copyAbs > T.epsilon(context)) {
1312 		sum = add(sum, term, context);
1313 		n++;
1314 		term = mul(term, div(x, n, context), context);
1315 	}
1316 	if (negative) sum = div(T.one, sum, context);
1317 	return round(sum, inContext);
1318 }
1319 
1320 unittest
1321 {	// expm1
1322 	static struct S { TD x; int p; TD expect; }
1323 	S[] s =
1324 	[
1325 		{  "0.1", 9, "0.105170918" },
1326 	// FIXTHIS: incorrect result for negative numbers.
1327 		{ "-0.4", 9, "-0.329679954" },
1328 		{ "-2",   9, "-0.864664717" },
1329 	];
1330 	auto f = FunctionTest!(S,TD)("expm1");
1331 	foreach (t; s) f.test(t, expm1(t.x, t.p), t.p);
1332   writefln(f.report);
1333 }
1334 
1335 //mixin (UnaryFunction!("log"));
1336 mixin (UnaryFunction!("log1p"));
1337 mixin (UnaryFunction!("log10"));
1338 mixin (UnaryFunction!("log2"));
1339 
1340 /+
1341 	"/// Returns the value of the function at the specified precision.
1342 	public T " ~ name ~ "(T)(T x, int precision = T.precision) if (isDecimal!T)
1343 	{
1344 		if (x.isNaN) {
1345 			contextFlags.set(INVALID_OPERATION);
1346 			return T.nan;
1347 		}
1348 		Context context = Context(precision, T.maxExpo, HALF_EVEN);
1349 		return " ~ name ~ "!T(x, context);
1350 	}
1351 +/
1352 
1353 // TODO: (behavior) add log(number, base) function (will have to have a different name -- logBase or something
1354 /// Decimal version of std.math function.
1355 /// Required by General Decimal Arithmetic Specification
1356 // TODO: efficiency) see Natural Logarithm, Wikipedia.
1357 /**
1358  * log1p (== log(1 + x)).
1359  * Decimal version of std.math function.
1360  */
1361 public T log1p(T)(T x, Context inContext) if (isDecimal!T)
1362 {
1363 	// special cases
1364 	if (x.isNaN || x < T.NEG_ONE) 	// use compare(x, T.NEG_ONE) == -1?
1365 	{
1366 		contextFlags.set(INVALID_OPERATION);
1367 		return T.nan;
1368 	}
1369 	// check for infinite argument
1370 	if (x.isInfinite) return T.infinity;
1371 
1372 	if (x.isZero) return T.zero(x.sign);
1373 
1374 	if (equals(x, T.NEG_ONE, inContext)) return T.infinity(true);
1375 
1376 	// TODO: There's probably a better breakeven point
1377 	if (x.copyAbs >= T.one) return log(add(T.one, x, inContext), inContext);
1378 
1379 	T term = x;
1380 	T pwr  = x;
1381 	T sum  = T.zero;
1382 	T n    = T.one;
1383 	auto context = guard(inContext);
1384 	while (term.copyAbs >= T.epsilon(context))
1385 	{
1386 		sum = add(term, sum, context);
1387 		pwr = mul(-pwr, x, context);// * x;
1388 		n++;
1389 		term = div(pwr, n, context);
1390 	}
1391 	sum = add(term, sum, context);
1392 //if (!__ctfe) writeln;
1393 //if (!__ctfe) writefln("sum = %s", abstractForm(sum));
1394 //if (!__ctfe) writefln("sum.digits = %s", sum.digits);
1395 //if (!__ctfe) writefln("inContext.precision = %s", inContext.precision);
1396 
1397 	sum = round(sum, inContext);
1398 //if (!__ctfe) writefln("sum = %s", abstractForm(sum));
1399 //if (!__ctfe) writefln("sum.digits = %s", sum.digits);
1400 	return sum;
1401 //	return round(sum, inContext);
1402 }
1403 
1404 // TODO: (testing) unittest this.
1405 unittest {
1406 	write("-- log1p............");
1407 	TD x = "0.1";
1408 	assertEqual(log1p(x), "0.09531017980432486");
1409 	writeln("passed");
1410 }
1411 
1412 /// Decimal version of std.math.log10.
1413 /// Required by General Decimal Arithmetic Specification
1414 public T log10(T)(T x, Context inContext) if (isDecimal!T)
1415 {
1416 	if (x.isZero) {
1417 		contextFlags.set(DIVISION_BY_ZERO);
1418 		return T.infinity;
1419 	}
1420 	if (x.isNegative) {
1421 		return T.nan;
1422 	}
1423 	auto context = guard(inContext);
1424 	int k = ilogb(x) + 1;
1425 	x.expo = x.expo - k;
1426 //	x.expo -= k;
1427 	T lg10 = add(div(log(x, context), ln10!T(context)), k);
1428 	return round(lg10, inContext);
1429 }
1430 
1431 unittest {
1432 	write("-- log10............");
1433 	TD x = TD("2.55");
1434 	assertEqual(log10(x), TD("0.4065401804339552"));
1435 	x = 123.456;
1436 	assertEqual(log10(x), TD("2.091512201627772"));
1437 	x = 10.0;
1438 	assertEqual(log10(x), 1);
1439 	writeln("passed");
1440 }
1441 
1442 /**
1443  * Decimal version of std.math.log2.
1444  * Required by General Decimal Arithmetic Specification
1445  */
1446 public T log2(T)(T x, Context inContext) if (isDecimal!T)
1447 {
1448 	auto context = guard(inContext);
1449 	T lg2 = div(log(x, context), ln2!T(context), context);
1450 	return round(lg2, inContext);
1451 }
1452 
1453 unittest {
1454 	write("-- log2.............");
1455 	assertEqual(log2(TD(10)), TD("3.321928094887362"));
1456 	assertEqual(log2(e!TD), TD("1.442695040888963"));
1457 	writeln("passed");
1458 }
1459 
1460 /**
1461  * Decimal version of std.math.pow.
1462  * Required by General Decimal Arithmetic Specification
1463  */
1464  // TODO: (behavior) add context
1465 public T pow(T)(T x, T y) if (isDecimal!T)
1466 {
1467 	return exp(x*log(y));
1468 }
1469 
1470 unittest {
1471 	write("pow..........");
1472 	writeln("test missing");
1473 }
1474 
1475 mixin (BinaryFunction!("hypot"));
1476 
1477 /// Returns the square root of the sum of the squares in the specified context.
1478 /// Decimal version of std.math.hypot.
1479 public T hypot(T)(T x, T y, Context context) if (isDecimal!T)
1480 {
1481 	// special values
1482 	if (x.isInfinite || y.isInfinite) return T.infinity();
1483     if (x.isZero) return y;
1484 	if (y.isZero) return x;
1485 	if (x.isNaN || y.isNaN) {
1486 		contextFlags.set(INVALID_OPERATION);
1487 		return T.nan;
1488 	}
1489 
1490 	T a = x.copyAbs;
1491     T b = y.copyAbs;
1492 	if (a < b) {
1493 		//swap operands
1494 		T t = a;
1495 		a = b;
1496 		b = t;
1497 	}
1498     b = div(b, a, context);
1499     return mul(a, sqrt(add(T.one, sqr(b, context), context), context));
1500 }
1501 
1502 // TODO: (testing) Need to test operation near precisions where this operation is really useful.
1503 unittest
1504 {	// hypot
1505 	static struct S { TD x; TD y; TD expect; }
1506 	S[] s =
1507 	[
1508 		{  "3", "4", "5" },
1509 	];
1510 	auto f = FunctionTest!(S,TD)("hypot");
1511 	foreach (t; s) f.test(t, hypot(t.x, t.y));
1512   writefln(f.report);
1513 }
1514 
1515 //--------------------------------
1516 // TRIGONOMETRIC FUNCTIONS
1517 //--------------------------------
1518 
1519 //mixin (UnaryFunction!("sin"));
1520 //mixin (UnaryFunction!("cos"));
1521 
1522 
1523 // Returns the reduced argument and the quadrant.
1524 // Reduced argument |x| <= pi/4.
1525 private T reduceAngle(T)(in T x,
1526 	out int n, in Context inContext = T.context) if (isDecimal!T)
1527 {
1528 	auto context = guard(inContext);
1529 	T M_2_PI = M_2_PI!T(context);
1530 	T pi_2 = mul(pi!T(context.precision), T.HALF);
1531 	T y = mul(x, M_2_PI, context);
1532 	int k = rint(y).toInt;
1533 	n = k % 4;
1534 	T f = sub(y, k, context);
1535 	T r = mul(f, pi_2, context);
1536 	return r;
1537 }
1538 
1539 /// Decimal version of std.math function.
1540 public T sin(T)(in T x, int precision = T.precision) if (isDecimal!T)
1541 {
1542 	if (x.isNaN) {
1543 		contextFlags.set(INVALID_OPERATION);
1544 		return T.nan;
1545 	}
1546 
1547 	auto context = Context(precision, T.maxExpo, HALF_EVEN);
1548 	int k;
1549 	T red = reduceAngle(x, k, context);
1550 	switch (k) {
1551 		case 0: return( sin( red, context));
1552 		case 1: return( cos( red, context));
1553 		case 2: return(-sin( red, context));
1554 		case 3: return(-cos( red, context));
1555 		default: return T.nan;
1556 	}
1557 //	return T.nan;
1558 }
1559 
1560 // Decimal version of std.math function.
1561 // Precondition: x is in 1st quadrant.
1562 package T sin(T)(in T x, Context inContext) if (isDecimal!T)
1563 {
1564 	auto context = guard(inContext);
1565 	T sum = 0;
1566 	int n = 1;
1567 	T powx = x.copy;
1568 	T sqrx = sqr(x, context);
1569 	T fact = 1;
1570 	T term = powx;
1571 	while (term.copyAbs > T.epsilon(context)) {
1572 		sum = add(sum, term, context);
1573 		n += 2;
1574 		powx = mul(powx.copyNegate, sqrx, context);
1575 		fact = mul(fact, n*(n-1), context);
1576 		term = div(powx, fact, context);
1577 	}
1578 	return round(sum, inContext);
1579 }
1580 
1581 unittest
1582 {	// sin
1583 	static struct S { TD x; int p; TD expect; }
1584 	S[] s =
1585 	[
1586 		{ "0.1",   9, "0.0998334166" },
1587 		{ "0.1",   2, "0.10" },
1588 		{ "0.333", 9, "0.326879693" },
1589 		{ "5.0",   9, "-0.958924275" },
1590 		{ "1.0",   9, "0.8414709848" },
1591 		{ "1.0",  16, "0.8414709848078965" },
1592 		{ "2.0",  16, "0.9092974268256817" },
1593 	];
1594 	auto f = FunctionTest!(S,TD)("sin");
1595 	foreach (t; s) f.test(t, sin(t.x, t.p), t.p);
1596   writefln(f.report);
1597 }
1598 
1599 unittest {
1600 	write("-- sin..............");
1601 //	TD difficult = TD(5678900000);
1602 	TD difficult = TD(5);
1603 writefln("difficult = %s", difficult);
1604 // FIXTHIS: throws div by zero exception...
1605 writefln("sin(difficult) = %s", sin(difficult));
1606 //	assertEqual(sin(difficult), TD(0));
1607 	// TODO: (testing) one value from each quadrant, reduced value.
1608 	// TODO: (behavior) this is a notoriously difficult value "sin(10^^22)"
1609 	writeln("passed");
1610 }
1611 
1612 /// Decimal version of std.math function.
1613 public T cos(T)(in T x, int precision = T.precision) if (isDecimal!T)
1614 {
1615 	if (x.isNaN) {
1616 		contextFlags.set(INVALID_OPERATION);
1617 		return T.nan;
1618 	}
1619 	auto context = Context(precision, T.maxExpo, HALF_EVEN);
1620 	int quadrant;
1621 	T red = reduceAngle(x, quadrant, context);
1622 	switch (quadrant) {
1623 		case 0: return( cos(red, context));
1624 		case 1: return(-sin(red, context));
1625 		case 2: return(-cos(red, context));
1626 		case 3: return( sin(red, context));
1627 		default: return T.nan;
1628 	}
1629 }
1630 
1631 /// Decimal version of std.math function.
1632 /// Precondition: x is in 1st quadrant.
1633 package T cos(T)(in T x, Context inContext) {
1634 	auto context = guard(inContext);
1635 	T sum = 0;
1636 	int n = 0;
1637 	T powx = 1;
1638 	T sqrx = sqr(x, context);
1639 	T fact = 1;
1640 	T term = powx;
1641 	while (term.copyAbs > T.epsilon(context)) {
1642 		sum = add(sum, term, context);
1643 		n += 2;
1644 		powx = mul(powx.copyNegate, sqrx, context);
1645 		fact = mul(fact, n*(n-1), context);
1646 		term = div(powx, fact, context);
1647 	}
1648 	return round(sum, inContext);
1649 }
1650 
1651 unittest
1652 {	// cos
1653 	static struct S { TD x; int p; TD expect; }
1654 	S[] s =
1655 	[
1656 		{ "1.0",   9, "0.5403023058681397174009" },
1657 		{ "0.333", 9, "0.945065959" },
1658 		{ "5.0",   9, "0.283662185" },
1659 		{ "1.0",  23, "0.540302306" },
1660 		{ "2.0",  16, "-0.416146837" },
1661 	];
1662 	auto f = FunctionTest!(S,TD)("cos");
1663 	foreach (t; s) f.test(t, cos(t.x, t.p), t.p);
1664   writefln(f.report);
1665 }
1666 
1667 public void sincos(T)(T x, out T sine, out T cosine, int precision = T.precision) {
1668 	auto context = Context(precision, T.maxExpo, HALF_EVEN);
1669 	int quadrant;
1670 	T red = reduceAngle(x, quadrant, context);
1671 	sincos(red, sine, cosine, context);
1672 /*	switch (quadrant) {
1673 //sin:
1674 		case 0: break;
1675 		case 1:
1676 			sine = cosine;
1677 			cosine = -sine;
1678 			break;
1679 		case 2:
1680 			sine = -sine;
1681 			cosine = -cosine;
1682 			break;
1683 		case 3:
1684 			sine = -cosine;
1685 			cosine = sine;
1686 			break;
1687 		default:
1688 			sine = T.nan;
1689 			cosine = T.nan;
1690 	}*/
1691 }
1692 /**
1693  * Replaces std.math function expi
1694  *
1695  */
1696 // TODO: (behavior) context, angle reduction
1697 public void sincos(T)(const T x, out T sine, out T cosine,
1698 		Context inContext) if (isDecimal!T)
1699 {
1700 	auto context = guard(inContext);
1701 	T csum, cterm, cx;
1702 	T ssum, sterm, sx;
1703 	T sqrx = sqr(x, context);
1704 	long n = 2;
1705 	T fact = 1;
1706 	cx = 1;	cterm = cx;	csum = cterm;
1707 	sx = x;	sterm = sx;	ssum = sterm;
1708 	while (sterm.copyAbs > T.epsilon) {
1709 		cx = mul(cx.copyNegate, sqrx, context);
1710 		fact = mul(fact, n++, context);
1711 		cterm = div(cx, fact, context);
1712 		csum = add(csum, cterm, context);
1713 		sx = mul(sx.copyNegate, sqrx, context);
1714 		fact = mul(fact, n++, context);
1715 		sterm = div(sx, fact, context);
1716 		ssum = add(ssum, sterm, context);
1717 	}
1718     sine   = round(ssum, inContext);
1719 	cosine = round(csum, inContext);
1720 }
1721 
1722 unittest {
1723 	write("sincos.......");
1724 	TD sine;
1725 	TD cosine;
1726 	sincos(TD("1.0"), sine, cosine);
1727 if (!__ctfe) writefln("sine = %s", sine);
1728 if (!__ctfe) writefln("cosine = %s", cosine);
1729 	writeln("..failed");
1730 }
1731 
1732 /**
1733  * Decimal version of std.math function.
1734  *
1735  */
1736 // TODO: (efficiency) compare divTan with tan.
1737 public T divTan(T)(T x) if (isDecimal!T)
1738 {
1739 	T sine;
1740 	T cosine;
1741 	sincos(x, sine, cosine);
1742 	if (sine == T.zero) return T.infinity;
1743 	return sine/cosine;
1744 }
1745 
1746 public T tan(T)(T x, int precision = T.precision) if (isDecimal!T)
1747 {
1748 	if (x.isNaN) {
1749 		contextFlags.set(INVALID_OPERATION);
1750 		return T.nan;
1751 	}
1752 	auto context = Context(precision, T.maxExpo, HALF_EVEN);
1753 	int quadrant;
1754 	T red = reduceAngle(x, quadrant, context);
1755 	T sine;
1756 	T cosine;
1757 	sincos(red, sine, cosine, context);
1758 	switch (quadrant) {
1759 		case 0: return( sine/cosine);
1760 		case 1: return(-cosine/sine);
1761 		case 2: return( sine/cosine);
1762 		case 3: return(-sine/cosine);
1763 		default: return T.nan;
1764 	}
1765 }
1766 
1767 unittest
1768 {	// tan
1769 	static struct S { TD x; int p; TD expect; }
1770 	S[] s =
1771 	[
1772 		{ "1.0",   9, "1.55740772465490223" },
1773 		{ "1.0",   14, "1.55740772465490223" },
1774 		{ "0.333", 9, "0.345880295" },
1775 	];
1776 	auto f = FunctionTest!(S,TD)("tan");
1777 	foreach (t; s) f.test(t, tan(t.x, t.p), t.p);
1778   writefln(f.report);
1779 }
1780 
1781 mixin (UnaryFunction!("atan"));
1782 mixin (UnaryFunction!("asin"));
1783 mixin (UnaryFunction!("acos"));
1784 
1785 /// Returns the arctangent of the argument in the specified context.
1786 /// Algorithm uses Taylor's theorem for arctangent.
1787 public T atan(T)(T x, Context inContext) if (isDecimal!T)
1788 {
1789 	auto context = guard(inContext, 3);
1790 	long k = 1;
1791 	// reduce the input angle
1792 	while (x > T(0.5)) {
1793 		T a = sqr(x, context);
1794 		T b = add(a, 1, context);
1795 		T c = sqrt(b, context);
1796 		T d = add(c, 1, context);
1797 		x = div(x, d, context);
1798 		k *= 2;
1799 	}
1800 	T sum = 0;
1801 	T powx = x;
1802 	T sqrx = sqr(x, context);
1803 	long dvsr = 1;
1804 	T term = powx;
1805 	while (term.copyAbs > T.epsilon(context)) {
1806 		sum = add(sum, term, context);
1807 		powx = mul(powx.copyNegate, sqrx, context);
1808 		dvsr = dvsr + 2;
1809 		term = div!T(powx, dvsr, context);
1810 	}
1811 	return round(mul(sum, k, context), inContext);
1812 }
1813 
1814 
1815 unittest
1816 {	// atan
1817 	static struct S { TD x; TD expect; }
1818 	S[] s =
1819 	[
1820 //		{ "1.0",   "0.785398163397" },
1821 //		{ "0.5",   "0.463647609" },
1822 //		{ "0.333", "0.32145052439664" },
1823 //		{ "0.1", "0.099668652491162038065120043484057532623410224914551" },
1824 //		{ "0.9", "0.73281510178650655085164089541649445891380310058594" },
1825 	];
1826 	auto f = FunctionTest!(S,TD)("atan");
1827 	foreach (t; s) f.test(t, atan(t.x));
1828   writefln(f.report);
1829 }
1830 
1831 /// Decimal version of std.math function.
1832 // TODO: (behavior) convert to std unary function.
1833 public T asin(T)(T x) if (isDecimal!T)
1834 {
1835 	T result = 2 * atan!T(x/(1+sqrt(1-sqr(x)))); //^^2)));
1836 	return result;
1837 }
1838 
1839 unittest
1840 {	// asin
1841 	static struct S { TD x; TD expect; }
1842 	S[] s =
1843 	[
1844 		{ "1.0",   "1.570796326794897" },
1845 		{ "0.5",   "0.5235987755982990" },
1846 		{ "0.333", "0.3394833781504900" },
1847 	];
1848 	auto f = FunctionTest!(S,TD)("asin");
1849 	foreach (t; s) f.test(t, asin!TD(t.x));
1850   writefln(f.report);
1851 }
1852 
1853 /// Decimal version of std.math function.
1854 // TODO: (behavior) convert to std unary function.
1855 public T acos(T)(T x) if (isDecimal!T)
1856 {
1857 	T result = 2 * atan!T(sqrt(1-sqr(x))/(1 + x));
1858 	return result;
1859 }
1860 
1861 unittest
1862 {	// acos
1863 	static struct S { TD x; TD expect; }
1864 	S[] s =
1865 	[
1866 		{ "1.0",   "0" },
1867 //		{ "0.5",   "1.04719755120" },
1868 //		{ "0.333", "1.23131294864" },
1869 	];
1870 	auto f = FunctionTest!(S,TD)("acos");
1871 	foreach (t; s) f.test(t, acos(t.x));
1872   writefln(f.report);
1873 }
1874 
1875 /// Decimal version of std.math function.
1876 public TD atan2(T)(T y, TD x) if (isDecimal!T)
1877 {
1878 	TD result;
1879 	return result;
1880 }
1881 
1882 unittest {
1883 	write("atan2........");
1884 	writeln("..failed");
1885 }
1886 
1887 //--------------------------------
1888 // HYPERBOLIC TRIGONOMETRIC FUNCTIONS
1889 //--------------------------------
1890 
1891 mixin (UnaryFunction!("sinh"));
1892 mixin (UnaryFunction!("cosh"));
1893 mixin (UnaryFunction!("tanh"));
1894 //mixin (UnaryFunction!("atanh"));
1895 
1896 /// Decimal version of std.math function.
1897 public T sinh(T)(T x, Context inContext) if (isDecimal!T)
1898 {
1899 	auto context = guard(inContext);
1900 	long n = 1;
1901 	T sum = 0;
1902 	T powx = x;
1903 	T sqrx = sqr(x, context);
1904 	T fact = n;
1905 	T term = powx;
1906 	while (term.copyAbs > T.epsilon(context)) {
1907 		sum  = add(sum, term, context);
1908 		n += 2;
1909 		fact = mul(fact, n*(n-1), context);
1910 		powx = mul(powx, sqrx, context);
1911 		term = div(powx, fact, context);
1912 	}
1913 	return round(sum, inContext);
1914 }
1915 
1916 
1917 unittest
1918 {	// sinh
1919 	static struct S { TD x; TD expect; }
1920 	S[] s =
1921 	[
1922 		{ "1.0",   "1.175201193643801" },
1923 		{ "0.5",   "0.5210953054937474" },
1924 		{ "0.333", "0.3391885521570523" },
1925 	];
1926 	auto f = FunctionTest!(S,TD)("sinh");
1927 	foreach (t; s) f.test(t, sinh(t.x));
1928   writefln(f.report);
1929 }
1930 
1931 /// Decimal version of std.math function.
1932 public T cosh(T)(T x, Context inContext) if (isDecimal!T)
1933 {
1934 	auto context = guard(inContext);
1935 	long n = 0;
1936 	T sum = 0;
1937 	T powx = 1;
1938 	T sqrx = sqr(x, context);
1939 	T fact = 1;
1940 	T term = powx;
1941 	while (term.copyAbs > T.epsilon(context)) {
1942 		sum  = add(sum, term, context);
1943 		n += 2;
1944 		fact = mul(fact, n*(n-1), context);
1945 		powx = mul(powx, sqrx, context);
1946 		term = div(powx, fact, context);
1947 	}
1948 	return round(sum, inContext);
1949 }
1950 
1951 unittest
1952 {	// cosh
1953 	static struct S { TD x; TD expect; }
1954 	S[] s =
1955 	[
1956 		{ "1.0",   "1.543080634815244" },
1957 		{ "0.5",   "1.127625965206381" },
1958 		{ "0.333", "1.055958746312751" },
1959 	];
1960 	auto f = FunctionTest!(S,TD)("cosh");
1961 	foreach (t; s) f.test(t, cosh(t.x));
1962   writefln(f.report);
1963 }
1964 
1965 /// Decimal version of std.math function.
1966 public T tanh(T)(T x, Context inContext) if (isDecimal!T)
1967 {
1968 	auto context = guard(inContext);
1969 	T tan = div(sinh(x, context), cosh(x, context), context);
1970 	return round(tan, inContext);
1971 }
1972 
1973 unittest
1974 {	// tanh
1975 	static struct S { TD x; TD expect; }
1976 	S[] s =
1977 	[
1978 		{ "1.0",   "0.7615941559557649" },
1979 		{ "0.5",   "0.4621171572600098" },
1980 		{ "0.333", "0.3212138289885354" },
1981 	];
1982 	auto f = FunctionTest!(S,TD)("tanh");
1983 	foreach (t; s) f.test(t, tanh(t.x));
1984   writefln(f.report);
1985 }
1986 
1987 mixin (UnaryFunction!("asinh"));
1988 mixin (UnaryFunction!("acosh"));
1989 mixin (UnaryFunction!("atanh"));
1990 
1991 /// Decimal version of std.math function.
1992 public T asinh(T)(T x, Context inContext) if (isDecimal!T)
1993 {
1994 	if (x.isZero) return T.zero;	// TODO: (behavior) special values
1995 	auto context = guard(inContext);
1996 	// TODO: fix the cutoff -- is the series expansion needed?
1997 	if (x.copyAbs >= "1.0E-6")
1998 	{
1999 		T arg = add(x, sqrt(add(sqr(x, context), T.one, context), context), context);
2000 		return round(log(arg, context), inContext);
2001 	}
2002 	else
2003 	{
2004 		T sum = 0;
2005 		T powx = x;
2006 		T sqrx = sqr(x, context);
2007 		T n = 1;
2008 		T term = x;
2009 		T scl = 1;
2010 		int count = 0;
2011 		while (term.copyAbs > T.epsilon(context)) {
2012 			sum = add(sum, term, context);
2013 			powx = mul(-powx, sqrx, context);
2014 			n += 2;
2015 			scl *= (n/(n+1));
2016 			term = mul(T(scl), div(powx, T(n), context), context);
2017 		}
2018 		return round(sum, inContext);
2019 	}
2020 }
2021 
2022 unittest
2023 {	// asinh
2024 	static struct S { TD x; int p; TD expect; }
2025 	S[] s =
2026 	[
2027 		// TODO: add tests for small and large arguments
2028 		{ "1.0",   9, "0.881373587020" },
2029 		{ "0.5",   9,  "0.481211825060" },
2030 		{ "0.333", 9,  "0.327133906664" },
2031 		{ pi!TD,   9,  "1.86229574331" },
2032 		{ "1.1E-3", 9,    "1.1E-3" },
2033 		// FIXTHIS: These tests fail with precision problems.
2034 //		{ "1.0E-3", 9,    "0.000999999998" },
2035 //		{ "0.9E-3", 9,    "0.000899999878500" },
2036 //		{ "1.0E-5", 9,    "1.0E-5" },
2037 //		{ "1.0E-6", 9,    "1.0E-6" },
2038 //		{ "1.0E-7", 9,    "1.0E-7" },
2039 		{ "1.234567E-7",  9,   "1.234567E-7" },
2040 		{ "0.0",   9,  "0.0" },
2041 	];
2042 	auto f = FunctionTest!(S,TD)("asinh");
2043 	foreach (t; s) f.test(t, asinh(t.x, t.p), t.p);
2044   writefln(f.report);
2045 
2046 }
2047 
2048 /// Decimal version of std.math function.
2049 public T acosh(T)(T x, Context inContext) if (isDecimal!T)
2050 {
2051 	if (x.copyAbs < T.one) {
2052 		contextFlags.set(INVALID_OPERATION);
2053 		return T.nan;
2054 	}
2055 	if (x.copyAbs.isOne) {
2056 		return T.zero;
2057 	}
2058 	auto context = guard(inContext);
2059 	// TODO: this is imprecise at small arguments -- Taylor series?
2060 	T arg = add(x, sqrt(sub(sqr(x, context), T.one, context), context), context);
2061 	return round(log(arg, context), inContext);
2062 }
2063 
2064 /*unittest
2065 {	// acosh
2066 	static struct S { TD x; TD expect; }
2067 	S[] s =
2068 	[
2069 		{ "1.0",   "0.0" },
2070 		{ "2.0",   "1.31695790" },
2071 		// FIXTHIS: These tests fail with precision problems.
2072 //		{ "1.0000001",   "0.000447213592" },
2073 //		{ "0.0",   "NaN" },
2074 //		{ "1.5",   "0.962423650119" },
2075 //		{ "1.333", "0.794987388708" },
2076 	];
2077 	auto f = FunctionTest!(S,TD)("acosh");
2078 	foreach (t; s) f.test(t, acosh(t.x));
2079   writefln(f.report);
2080 }*/
2081 
2082 /// Decimal version of std.math function.
2083 public T atanh(T)(T x, Context inContext) if (isDecimal!T)
2084 {
2085 	T abs = x.copyAbs;
2086 	if (abs > T.one) {
2087 		contextFlags.set(INVALID_OPERATION);
2088 		return T.nan;
2089 	}
2090 	if (abs.isOne) {
2091 		return T.infinity(x.sign);
2092 	}
2093 
2094 	auto context = guard(inContext, 3);
2095 	T cutoff = "1.0E-6"; // cutoff point for switch to series expansion
2096 	if(abs > cutoff)
2097 	{	// atanh(x) = 1/2 * log((1+x)/(1-x))
2098 		T n = add(T.one, x, context);
2099 		T d = sub(T.one, x, context);
2100 		T q = div(n, d, context);
2101 		T l = log(q, context);
2102 		T a = mul(T.HALF, l, context);
2103 		return round(a, inContext);
2104 	}
2105 	else
2106 	{	// series expansion
2107 		T sum = 0;
2108 		T powx = x;
2109 		T sqrx = sqr(x, context);
2110 		long dvsr = 1;
2111 		T term = powx;
2112 		int count = 0;
2113 		while (term.copyAbs > T.epsilon(context)) {
2114 			sum = add(sum, term, context);
2115 			powx = mul(powx, sqrx, context);
2116 			dvsr += 2;
2117 			term = div!T(powx, dvsr, context);
2118 		}
2119 		return round(sum, inContext);
2120 	}
2121 }
2122 
2123 unittest
2124 {	// atanh
2125 	static struct S { TD x; int p; TD expect; }
2126 	S[] s =
2127 	[
2128 		{ " 1.0",  9, "Infinity" },
2129 		{ "-1.0",  9, "-Infinity" },
2130 		{ " 1.01", 9, "NaN" },
2131 		{ "-1.01", 9, "NaN" },
2132 		{ "0.9",   9, "1.47221949" },
2133 		{ "0.99999",   9, "6.10303382276" },
2134 		{ "1.0E-7",   9, "1.0E-7" },
2135 		{ "0.5",   12, "0.549306144334" },
2136 		{ "0.333", 11, "0.346198637132" },
2137 		{ "0.333", 12, "0.346198637132" },
2138 	];
2139 	auto f = FunctionTest!(S,TD)("atanh");
2140 	foreach (t; s) f.test(t, atanh!TD(t.x, t.p), t.p);
2141   writefln(f.report);
2142 }
2143 
2144 unittest {
2145 	writeln("==========================");
2146 }