1 // Written in the D programming language
2 
3 /**
4  * Floating-point decimal number and decimal arithmetic library for D.
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 
21 module eris.decimal;
22 
23 import std.array : replace;
24 import std.bitmanip : DoubleRep;
25 import std.conv;
26 import std.string;
27 import std.traits;
28 import std.math;
29 static import std.path;
30 
31 public import std.bigint;
32 public import eris.decimal.context;
33 public import eris.decimal.rounding;
34 public import eris.decimal.arithmetic;
35 public import eris.decimal.conv;
36 static import eris.decimal.math;
37 
38 import eris.decimal.logical;
39 
40 // import std.stdio;  // temporary import for testing
41 
42 version(unittest)
43 {
44   import std.stdio;
45   import eris.decimal.test;
46 }
47 
48 version(unittest)
49 {
50   alias D9 = Decimal!(TestContext);
51   alias D16 = Decimal!(Bid64);
52   alias TD = D16;
53 }
54 
55 /**
56  * A floating-point decimal number.
57  *
58  * The number consists of:
59  * A boolean sign
60  * A integer-type coefficient,
61  * An integer exponent
62  * A tag for special values (NaN, infinity)
63  */
64 struct Decimal(immutable Context _context = DefaultContext)
65 {
66 
67 static if (context == Bid64) {
68   unittest {
69     writeln("==========================");
70     writeln("decimal64............begin");
71     writeln("==========================");
72   }
73 }
74 
75   public static enum IsDecimal;
76 
77   public enum Context context = _context;
78   alias decimal = Decimal!(context);
79   alias D = Decimal!(context);
80 
81   private Tag m_tag     = Tag.QNAN;// special value: default is quiet NaN
82   private bool m_sign   = 0;    // true if the value is negative, false otherwise.
83   private int m_expo    = 0;    // the exponent of the decimal value
84   private BigInt m_coff = 0;    // the coefficient of the decimal value
85   private int m_digits  = 0;      // the number of decimal digits in the coefficient.
86 
87   // special values for NaN, Inf, etc.
88   private enum Tag : byte { NONE=0, INF=1, MINF=-1, QNAN=2, SNAN=3 };
89 
90   // decimal special values
91   private enum NAN  = decimal(Tag.QNAN);
92   private enum SNAN = decimal(Tag.SNAN);
93   private enum INF  = decimal(Tag.INF);
94   private enum MINF = decimal(Tag.MINF);
95 
96   // context-based parameters
97   /// the maximum length of the coefficient in decimal .
98   public enum precision = context.precision;
99   /// maximum value of the exponent.
100   public enum maxExpo = context.maxExpo;
101   /// maximum value of the adjusted exponent.
102   public enum maxAdjustedExpo = maxExpo - (precision - 1);
103   /// smallest normalized exponent.
104   public enum minExpo = 1 - maxExpo;
105   /// smallest non-normalized exponent.
106   public enum tinyExpo = 1 - maxExpo - precision;
107   /// maximum value of the coefficient.
108   public enum maxCoefficient = BigInt(10)^^precision - 1;
109   /// rounding mode.
110   public enum Round mode = context.mode;
111 
112 /*  unittest
113   {  // special values
114     static struct S { TD x; string expect; }
115     S[] s =
116     [
117       { NAN,      "NaN" },
118       { SNAN,  "sNaN" },
119       { INF, "Infinity" },
120       { MINF,  "-Infinity" },
121     ];
122     auto f = FunctionTest!(S,string)("specials");
123     foreach (t; s) f.test(t, t.x.toString);
124       writefln(f.report);
125   }*/
126 
127 //--------------------------------
128 // construction
129 //--------------------------------
130 
131   /// Constructs a decimal number from a tag and an optional sign.
132   @safe
133   private this(Tag tag)
134   {
135     this.m_sign = tag < 0;
136     this.m_tag  = tag;
137   }
138 
139   /// Constructs a decimal number from a boolean value.
140   /// false == 0, true == 1
141   this(bool value)
142   {
143     if (value) {
144       this(BigInt(1));
145     }
146     else
147     {
148       this(BigInt(0));
149     }
150   }
151 
152   // Constructs a decimal number from a string representation
153   this(string str)
154   {
155     this = fromString!decimal(str);
156   }
157 
158   this(U)(U r)
159     if (isFloatingPoint!U)
160   {
161     this = fromBinary!(decimal,U)(r);
162   }
163 
164   this(U)(U coefficient)
165     if (isIntegral!U)
166   {
167     this(BigInt(coefficient));
168   }
169 
170   this(U)(U coefficient)
171     if (is(U == BigInt))
172   {
173     this(coefficient, 0);
174   }
175 
176   this(D)(D that) if (isDecimal!D)
177   {
178     this.m_sign = that.m_sign;
179     this.m_tag   = that.m_tag ;
180     this.m_digits = that.m_digits;
181     this.m_expo  = that.m_expo;
182     this.m_coff  = that.m_coff;
183     if (that.context > this.context)
184       round(this, that.context);
185   }
186 
187   // TODO: reduce the number of constructors
188   /// Constructs a number from a boolean sign, an integer coefficient and
189   /// an optional integer exponent.
190   /// The sign of the number is the value of the sign parameter
191   /// regardless of the sign of the coefficient.
192   /// The intial precision of the number is deduced from the number
193   /// of decimal digits in the coefficient.
194   //@safe
195   this(U)(U coefficient, int exponent)
196     if (is(U == BigInt) || isIntegral!U)
197   {
198     static if (isIntegral!U)
199     {
200       this(BigInt(coefficient), exponent);
201     }
202     else
203     {
204       this = zero();
205       this.m_sign = coefficient < 0;
206       this.m_coff = sign ? -coefficient : coefficient;
207       this.m_expo = exponent;
208       this.m_digits = countDigits(this.m_coff);
209     }
210   }
211 
212   this(U)(U coefficient, int exponent, bool sign)
213     if (is(U == BigInt) || isIntegral!U)
214   {
215     static if (isIntegral!U)
216     {
217       this(BigInt(coefficient), exponent, sign);
218     }
219     else
220     {
221     this = zero();
222     this.m_sign = sign;
223     this.m_coff = coefficient >= 0 ? coefficient : -coefficient;
224     this.m_expo = exponent;
225     this.m_digits = countDigits(this.m_coff);
226     }
227   }
228 
229   // TODO: reduce the number of constructors
230   /// Constructs a number from a boolean sign, an integer coefficient and
231   /// an optional integer exponent.
232   /// The sign of the number is the value of the sign parameter
233   /// regardless of the sign of the coefficient.
234   /// The intial precision of the number is deduced from the number
235   /// of decimal digits in the coefficient.
236   //@safe
237 /*  this(long coefficient, int exponent, bool sign)
238   {
239     this(BigInt(coefficient), exponent, sign);
240   }*/
241 
242 static if (context == Bid64)
243 {
244   unittest
245   {  // this(u,i,b)
246     static struct S { BigInt cf; int exp; bool sign; TD expect; }
247     S[] s =
248     [
249       { 7254, 94, true, "-7.254E+97" },
250       // NOTE: new constructions aren't rounded and may be too large for type
251       { 1,   194, true, "-1E+194" },
252     ];
253     auto f = FunctionTest!(S,TD)("this(uib)");
254     foreach (t; s) f.test(t, TD(t.cf, t.exp, t.sign));
255       writefln(f.report);
256   }
257 
258 }
259 
260 static if (context == Bid64)
261 {
262   unittest
263   {  // this(string)
264     // NOTE: this is a chicken and egg sort of test:
265     // Tests to and from strings at once
266     static struct S { string str; string expect; }
267     S[] s =
268     [
269       { "7254E94",    "7.254E+97" },
270       { "7254.005",    "7254.005" },
271       { "-2.3456E+14",  "-2.3456E+14" },
272       { "-0.1234",    "-0.1234" },
273       { "234568901234",  "234568901234" },
274       { "123.457E+29",  "1.23457E+31" },
275       { "2.71828183",    "2.71828183" },
276       { "2147483646",    "2147483646" },
277       { "2147483648",    "2147483648" },
278       { "-2147483647",  "-2147483647" },
279       { "-2147483649",  "-2147483649" },
280       { "inf",      "Infinity" },
281     ];
282     auto f = FunctionTest!(S, string)("this(str)");
283     foreach (t; s) f.test(t, TD(t.str).toString);
284       writefln(f.report);
285   }
286 }
287 
288 
289 static if (context == Bid64)
290 {
291   unittest
292   {  // this(double)
293     double third = 1.0/3.0;
294     static struct S { double dbl; TD expect; }
295     S[] s =
296     [
297       { double.infinity,    "Infinity" },
298       { 1.0E4,    "1E4" },
299       { 1.0/3.0,     "0.333333333333333" },
300     ];
301     auto f = FunctionTest!(S, TD)("this(dbl)");
302     foreach (t; s) f.test(t, TD(t.dbl));
303       writefln(f.report);
304   }
305 }
306 
307 static if (context == Bid64)
308 {
309 /*  unittest
310   {  // this(flt)
311     assert(TD(-float.infinity) == TD("-infinity"));
312     assert(TD(1.0E4F) == TD("1E4"));
313     assert(TD(1.0f/3.0f) == TD("0.333333"));
314   }*/
315 
316   unittest
317   {  // this(flt)
318     static struct S { float flt; decimal expect; }
319     S[] s =
320     [
321       { -float.infinity,  "-Infinity" },
322       { 1.0E4f,      "1E4" },
323       { 1.0f/3.0f,     "0.333333" },
324     ];
325     auto f = FunctionTest!(S, decimal)("this(flt)");
326     foreach (t; s) f.test(t, decimal(t.flt));
327       writefln(f.report);
328   }
329 }
330 
331   // TODO: (testing) need to test this with 15-17 digit precision
332 static if (context == Bid64)
333 {
334   unittest // real construction
335   {
336     static struct S { real x; TD expect; }
337 
338     static S[] s =
339     [
340       { 0.1L,        "0.1" },
341       { 7254E94,      "7.254E+97" },
342       { 7254.005,      "7254.005" },
343       { -2.3456E+14,    "-2.3456E+14" },
344       { -0.1234,      "-0.1234" },
345 
346       { 234568901234.0,  "234568901234" },
347       { 123.457E+29,    "1.23457E+31" },
348       { 2.71828183,    "2.71828183" },
349       { 2.718281832,    "2.718281832" },
350       { 2147483646.0,    "2147483646" },
351 
352       { 2147483648.0,    "2147483648" },
353       { -2147483647.0,  "-2147483647" },
354       { -2147483649.0,  "-2147483649" },
355       { 0.0,        "0" },
356       { -0.0,        "-0" },
357 
358       { 1E54,        "1E54" },
359 
360       { double.max,     "1.79769313486231571E+308" },
361       { -real.infinity,   "-Infinity" },
362     ];
363 
364       auto f = FunctionTest!(S, TD)("this(real)");
365       foreach (t; s) f.test(t, TD(t.x));
366         writefln(f.report);
367   }
368 }
369 
370 //--------------------------------
371 // member properties
372 //--------------------------------
373 
374   /// Returns the exponent of this number
375   @property
376   @safe
377   int expo() const
378   {
379     if (isSpecial) return 0;
380     return this.m_expo;
381   }
382 
383 
384   // NOTE: (language) What does it take to make this an l-value?
385   /// sets the exponent of this number
386   @property
387   @safe
388   int expo(int exp)
389   {
390     this.m_expo = exp;
391     return this.m_expo;
392   }
393 
394   @property
395   @safe
396   BigInt coff() const
397   {
398 //    if (isSpecial) return BigInt(0);
399     return this.m_coff;
400   }
401 
402   @property
403   @safe
404   BigInt coff(BigInt m_coff)
405   {
406     this.m_coff = m_coff;
407     return this.m_coff;
408   }
409 
410   @property
411   @safe
412   BigInt coff(long m_coff)
413   {
414     this.m_coff = m_coff;
415     return this.m_coff;
416   }
417 
418 /*  @property
419   @safe
420   ushort payload() const
421   {
422     if (this.isNaN) {
423       return cast(ushort)(this.m_coff.toLong);
424     }
425     return 0;
426   }
427 
428   @property
429   @safe
430   ushort payload(const ushort value)
431   {
432     if (this.isNaN) {
433       this.m_coff = BigInt(value);
434       return value;
435     }
436     return 0;
437   }*/
438 
439   /// Returns the adjusted exponent of this number
440   @property
441   @safe
442   int adjExpo() const
443   {
444     if (isSpecial) return 0;
445     return m_expo + m_digits - 1;
446   }
447 
448   /// Returns the number of decimal digits in the coefficient of this number
449   @property
450   @safe
451   int digits() const
452   {
453     if (isSpecial) return 0;
454     return this.m_digits;
455   }
456 
457   @property
458   @safe
459   int digits(in int count)
460   {
461     if (isSpecial) return 0;
462     return this.m_digits = count;
463   }
464 
465   @property
466 //  @safe
467   bool sign() const
468   {
469     return cast(bool) m_sign & 1;
470   }
471 
472   @property
473 //  @safe
474   bool sign(const bool value)
475   {
476     m_sign = value; // | 1 -- may incorporate nan,inf flags into sign byte
477     return m_sign & 1;
478   }
479 
480 //--------------------------------
481 // floating point properties
482 //--------------------------------
483 
484   /// Returns the default value for this type (NaN)
485   @safe
486   static D init()
487   {
488     return NAN;
489   }
490 
491   /// Returns NaN
492   @safe
493   static D nan(ushort payload = 0, bool sign = false)
494   {
495     D dec = NAN;
496     dec.m_coff = payload;
497     dec.m_sign = sign;
498     return dec;
499   }
500 
501   /// Returns signaling NaN
502   @safe
503   static D snan(ushort payload = 0, bool sign = false)
504   {
505     D dec = SNAN;
506     dec.m_coff = payload;
507     dec.m_sign = sign;
508     return dec;
509   }
510 
511   /// Returns infinity.
512   @safe
513   static D infinity(bool sign = false)
514   {
515     return sign ? MINF : INF;
516   }
517 
518   /// Returns the maximum representable normal value in the current context.
519   static D max()
520   {
521     static initialized = false;
522     static D maxVal;
523     if (!initialized)
524     {
525       maxVal = D(maxCoefficient, maxAdjustedExpo);
526       initialized = true;
527       return maxVal;
528     }
529     else
530     {
531       return maxVal;
532     }
533   }
534 
535   /// Returns the minimum representable normal value in this context.
536   @safe
537   enum D min_normal = D(1L, minExpo);
538 
539   /// Returns the minimum representable subnormal value in this context.
540   @safe
541   enum D min = D(1, tinyExpo);
542 
543   /// Returns the smallest available increment to 1.0 in this context
544   static enum D epsilon(in Context inContext = context) {
545     return D(1, -inContext.precision);}
546 
547   /// Returns the radix, which is always ten for D numbers.
548   @safe
549   enum int radix = 10;
550 
551   // TODO: need to determine what constants it makes sense to include
552   // common D numbers
553   enum D ZERO    = D(Tag.NONE);
554   enum D NEG_ZRO = -ZERO; // D(Tag.NONE, true);
555   enum D HALF    = D(5, -1);
556   enum D ONE     = D(1);
557   enum D NEG_ONE = D(-1);
558   enum D TWO     = D(2);
559 //  enum D THREE   = D(3);
560   enum D FIVE    = D(5);
561   enum D TEN     = D(10);
562 
563   /// Returns zero.
564   @safe
565   static enum D zero(bool sign = false)
566   {
567     return sign ? NEG_ZRO : ZERO;
568   }
569 
570   /// Returns 1.
571   //@safe
572   static D one(bool sign = false) {
573     return sign ? NEG_ONE : ONE;
574   }
575 
576 static if (context == Bid64)
577 {
578   unittest
579   {  // constants
580     static struct S { TD x; string expect; }
581     S[] s =
582     [
583       { TD.HALF,    "0.5" },
584       { TD.ONE,    "1"   },
585     ];
586     auto f = FunctionTest!(S, string)("constants");
587     foreach (t; s) f.test(t, t.x.toString);
588       writefln(f.report);
589   }
590 }
591 
592   // copy constructor
593   @safe
594   public this(const decimal that)
595   {
596     this.m_sign = that.m_sign;
597     this.m_tag   = that.m_tag ;
598     this.m_digits = that.m_digits;
599     this.m_expo  = that.m_expo;
600     this.m_coff  = that.m_coff;
601   };
602 
603 //--------------------------------
604 // copy functions
605 //--------------------------------
606 
607   /// dup property
608   //@safe
609   public decimal dup() const
610   {
611     return decimal(this);
612   }
613 
614   // TODO: modify this to use a compareTotal?
615   unittest
616   {  // copy
617     static struct S { TD x; TD expect; }
618     S[] s =
619     [
620       { 1.0, 1.0 },
621       { 2.0, 2.0 },
622       { 1.0E5, 1.0E5 },
623       { 0.1, 0.1 },
624       {123.456, 123.456},  // passes! fails because r == r only when exact
625       { 32E-27, 32E-27 },
626       { double.max, double.max },
627       { real.max, real.max },
628     ];
629     auto f = FunctionTest!(S,TD)("copy");
630     foreach (t; s) f.test(t, t.x.copy);
631     writefln(f.report);
632   }
633 
634 /*  unittest {  // dup
635     write("-- dup..............");
636     TD num, copy;
637     // TODO: add tests for these values
638     num = std.math.LB;
639     num = std.math.PI;
640     num = std.math.LB;
641     copy = TD(num);
642 //    assertCopy!TD(num, copy);
643     assertZero(compareTotal(num, copy));
644     num = TD(std.math.PI);
645     copy = num.dup;
646     assertEqual(num, copy);
647     writeln("passed");
648   }*/
649 
650   /// Returns a copy of the operand.
651   /// The copy is unaffected by context and is quiet -- no flags are changed.
652   /// Implements the 'copy' function in the specification. (p. 43)
653   //@safe
654   public decimal copy() const
655   {
656     return dup;
657   }
658 
659   /// Returns a copy of the operand with a positive sign.
660   /// The copy is unaffected by context and is quiet -- no flags are changed.
661   /// Implements the 'copy-abs' function in the specification. (p. 44)
662   //@safe
663   public decimal copyAbs() const
664   {
665     decimal copy = dup;
666     copy.sign = false;
667     return copy;
668   }
669 
670   /// Returns a copy of the operand with the sign inverted.
671   /// The copy is unaffected by context and is quiet -- no flags are changed.
672   /// Implements the 'copy-negate' function in the specification. (p. 44)
673   //@safe
674   public decimal copyNegate() const
675   {
676     decimal copy = dup;
677     copy.sign = !sign;
678     return copy;
679   }
680 
681   /// Returns a copy of the first operand with the sign of the second operand.
682   /// The copy is unaffected by context and is quiet -- no flags are changed.
683   /// Implements the 'copy-sign' function in the specification. (p. 44)
684   //@safe
685   public decimal copySign()(in decimal arg) const
686   {
687     decimal copy = dup;
688     copy.sign = arg.sign;
689     return copy;
690   }
691 
692   unittest {  // copy
693     write("-- copy.............");
694     TD arg, expect;
695     arg = TD("2.1");
696     expect = TD("2.1");
697     assertZero(compareTotal(arg.copy,expect));
698     arg = TD("-1.00");
699     expect = TD("-1.00");
700     assertZero(compareTotal(arg.copy,expect));
701     // copyAbs
702     arg = 2.1;
703     expect = 2.1;
704     assertZero(compareTotal(arg.copyAbs,expect));
705     arg = TD("-1.00");
706     expect = TD("1.00");
707     assertZero(compareTotal(arg.copyAbs,expect));
708     // copyNegate
709     arg  = TD("101.5");
710     expect = TD("-101.5");
711     assertZero(compareTotal(arg.copyNegate,expect));
712     // copySign
713     TD arg1, arg2;
714     arg1 = 1.50; arg2 = 7.33; expect = 1.50;
715     assertZero(compareTotal(arg1.copySign(arg2),expect));
716     arg2 = -7.33;
717     expect = -1.50;
718     assertZero(compareTotal(arg1.copySign(arg2),expect));
719     writeln("passed");
720   }
721 
722 //--------------------------------
723 //  classification properties
724 //--------------------------------
725 
726   /// Returns true if this number's representation is canonical.
727   ///
728   /// Always returns true. All decimal numbers are canonical,
729   /// whether or not they are reduced to their simplest form.
730   @safe
731   const bool isCanonical()
732   {
733     return true;
734   }
735 
736 static if (context == Bid64)
737 {
738   unittest
739   {  // isCanonical
740     static struct S { string str; bool expect; }
741     S[] s =
742     [
743       { "7254E94",    true },
744       { "inf",      true },
745     ];
746     auto f = FunctionTest!(S, bool)("isCanonical");
747     foreach (t; s) f.test(t, TD(t.str).isCanonical);
748       writefln(f.report);
749   }
750 }
751 
752   /// Returns true if this number is exactly one.
753   //@safe
754   const bool isOne()
755   {
756     if (isNegative || isZero || isSpecial) {
757       return false;
758     }
759     if (coff == 1 && expo == 0) {
760       return true;
761     }
762     return this.reduce.isSimpleOne;
763   }
764 
765   /// Returns true if this number is exactly (false, 1, 0).
766   @safe
767   const bool isSimpleOne()
768   {
769     return isFinite && !isNegative && coff == 1 && expo == 0;
770   }
771 
772 static if (context == Bid64)
773 {
774   unittest
775   {  // isNaN, isQuiet, isSignal
776     static struct S { string str; bool expect; }
777 
778     S[] s1 =
779     [
780       { "1",    true },
781       { "10E-1",  true },
782       { "sNaN",  false },
783     ];
784     auto f1 = FunctionTest!(S, bool)("isOne");
785     foreach (t; s1) f1.test(t, TD(t.str).isOne);
786       writefln(f1.report);
787 
788     S[] s2 =
789     [
790       { "1",    true },
791       { "10E-1",  false },
792       { "sNaN",  false },
793     ];
794     auto f2 = FunctionTest!(S, bool)("isSimpleOne");
795     foreach (t; s2) f2.test(t, TD(t.str).isSimpleOne);
796       writefln(f2.report);
797   }
798 }
799 
800   /// Returns true if this number is + or - zero.
801   @safe
802   const bool isZero()
803   {
804     return isFinite && coff == 0;
805   }
806 
807 static if (context == Bid64)
808 {
809   unittest
810   {  // isZero
811     static struct S { string str; bool expect; }
812     S[] s =
813     [
814       { "0",    true },
815       { "2.50",  false },
816       { "-0E2",  true },
817     ];
818     auto f = FunctionTest!(S, bool)("isZero");
819     foreach (t; s) f.test(t, TD(t.str).isZero);
820       writefln(f.report);
821   }
822 }
823 
824 
825   /// Returns true if this number is a quiet or signaling NaN.
826   @safe
827   const bool isNaN()
828   {
829     return this.m_tag  == Tag.QNAN
830         || this.m_tag  == Tag.SNAN;
831   }
832 
833   /// Returns true if this number is a signaling NaN.
834   @safe
835   const bool isSignal()
836   {
837     return this.m_tag  == Tag.SNAN;
838   }
839 
840   /// Returns true if this number is a quiet NaN.
841   @safe
842   const bool isQuiet()
843   {
844     return this.m_tag  == Tag.QNAN;
845   }
846 
847 static if (context == Bid64)
848 {
849   unittest
850   {  // isNaN, isQuiet, isSignal
851     static struct S { string str; bool expect; }
852 
853     S[] s1 =
854     [
855       { "2.50",  false },
856       { "NaN",  true },
857       { "sNaN",  true },
858     ];
859     auto f1 = FunctionTest!(S, bool)("isNaN");
860     foreach (t; s1) f1.test(t, TD(t.str).isNaN);
861       writefln(f1.report);
862 
863     S[] s2 =
864     [
865       { "2.50",  false },
866       { "NaN",  true },
867       { "sNaN",  false },
868     ];
869     auto f2 = FunctionTest!(S, bool)("isQuiet");
870     foreach (t; s2) f2.test(t, TD(t.str).isQuiet);
871       writefln(f2.report);
872 
873     S[] s3 =
874     [
875       { "2.50",  false },
876       { "NaN",  false },
877       { "sNaN",  true },
878     ];
879     auto f3 = FunctionTest!(S, bool)("isSignal");
880     foreach (t; s3) f3.test(t, TD(t.str).isSignal);
881       writefln(f3.report);
882   }
883 }
884 
885 static if (context == Bid64)
886 {
887   unittest
888   {  // isNaN
889     static struct S { string str; bool expect; }
890     S[] s =
891     [
892       { "NaN",  true },
893       { "2.50",  false },
894       { "-sNaN",  true },
895     ];
896     auto f = FunctionTest!(S, bool)("isNaN");
897     foreach (t; s) f.test(t, TD(t.str).isNaN);
898       writefln(f.report);
899   }
900 }
901 
902   /// Returns true if this number is + or - infinity.
903   @safe
904   const bool isInfinite()
905   {
906     return m_tag == Tag.INF
907       || m_tag == Tag.MINF;
908   }
909 
910   /// Returns true if this number is not an infinity or a NaN.
911   @safe
912   const bool isFinite()
913   {
914     return m_tag  != Tag.INF
915       && m_tag  != Tag.MINF
916       && m_tag  != Tag.QNAN
917       && m_tag  != Tag.SNAN;
918   }
919 
920 static if (context == Bid64)
921 {
922   unittest
923   {  // isFinite
924     static struct S { string str; bool expect; }
925 
926     S[] s1 =
927     [
928       { "2.50",  true },
929       { "-0.3",  true },
930       { "0",    true },
931       { "-Inf",  false },
932       { "NaN",  false },
933     ];
934     auto f1 = FunctionTest!(S, bool)("isFinite");
935     foreach (t; s1) f1.test(t, TD(t.str).isFinite);
936       writefln(f1.report);
937 
938     S[] s2 =
939     [
940       { "2.50",  false },
941       { "-0.3",  false },
942       { "0",    false },
943       { "-Inf",  true },
944       { "NaN",  false },
945     ];
946     auto f2 = FunctionTest!(S, bool)("isInfinite");
947     foreach (t; s2) f2.test(t, TD(t.str).isInfinite);
948       writefln(f2.report);
949   }
950 }
951 
952   /// Returns true if this number is a NaN or infinity.
953   @safe
954   const bool isSpecial()
955   {
956     return m_tag  == Tag.INF
957       || m_tag  == Tag.MINF
958       || m_tag  == Tag.QNAN
959       || m_tag  == Tag.SNAN;
960   }
961 
962 static if (context == Bid64)
963 {
964   unittest
965   {  // isSpecial
966     static struct S { string str; bool expect; }
967     S[] s =
968     [
969       { "-Infinity",  true },
970       { "-NaN",    true },
971       { "sNan1234",  true },
972       { "12378.34",  false },
973     ];
974     auto f = FunctionTest!(S, bool)("isSpecial");
975     foreach (t; s) f.test(t, TD(t.str).isSpecial);
976       writefln(f.report);
977   }
978 }
979 
980   /// Returns true if this number is negative. (Includes -0)
981   @safe
982   bool isNegative() const
983   {
984     return sign;
985   }
986 
987   /// Returns true if this number is positive. (Excludes -0)
988   @safe
989   const bool isPositive()
990   {
991     return !sign;
992   }
993 
994 static if (context == Bid64)
995 {
996   unittest
997   {  // isSpecial
998     static struct S { string str; bool expect; }
999     S[] s =
1000     [
1001       { "2.50",  false },
1002       { "-12",  true },
1003       { "-0",    true },
1004       { "-Inf",  true },
1005       { "Inf",  false },
1006     ];
1007     auto f = FunctionTest!(S, bool)("isNegative");
1008     foreach (t; s) f.test(t, TD(t.str).isNegative);
1009       writefln(f.report);
1010   }
1011 }
1012 
1013   /// Returns true if this number is normal.
1014   @safe
1015   const bool isNormal(int minExponent = minExpo)
1016   {
1017     if (isFinite && !isZero) {
1018       return adjExpo >= minExponent;
1019     }
1020     return false;
1021   }
1022 
1023   /// Returns true if this number is subnormal.
1024   @safe
1025   const bool isSubnormal(int minExponent = minExpo)
1026   {
1027 //    int subExponent = minExponent - precision;
1028     if (!isFinite) return false;
1029     return adjExpo < minExponent;
1030 //      && adjExpo >= subExponent;
1031   }
1032 
1033 static if (context == Bid64)
1034 {
1035   unittest
1036   {  // isNormal, isSubnormal
1037     static struct S { string str; bool expect; }
1038 
1039     S[] s1 =
1040     [
1041       { "2.50",    true },
1042       { "1.0E-368",  true },
1043       { "0.9E-368",  false },
1044       { "1.0E-384",  false },
1045       { "0.9E-384",  false },
1046       { "0.00",    false },
1047       { "-Inf",    false },
1048       { "NaN",    false },
1049     ];
1050     auto f1 = FunctionTest!(S, bool)("isNormal");
1051     foreach (t; s1) f1.test(t, TD(t.str).isNormal);
1052       writefln(f1.report);
1053 
1054     S[] s2 =
1055     [
1056       { "2.50",    false },
1057       { "1.0E-368",  false },
1058       { "0.9E-368",  true },
1059       { "1.0E-384",  true },
1060       { "0.9E-384",  true },
1061       { "0.00",    false },
1062       { "-Inf",    false },
1063       { "NaN",    false },
1064     ];
1065     auto f2 = FunctionTest!(S, bool)("isSubnormal");
1066     foreach (t; s2) f2.test(t, TD(t.str).isSubnormal);
1067       writefln(f2.report);
1068   }
1069 }
1070 
1071   /// Returns true if the number is an integer (the fractional part is zero).
1072   bool isIntegralValued()
1073   {
1074     if (isSpecial) return false;
1075     if (expo >= 0) return true;
1076     int exp = -expo;
1077     if (exp >= context.precision) return false;
1078     int zeros = trailingZeros(coff, digits);
1079     if (zeros) {
1080       exp += zeros;
1081       if (exp >= 0) return true;
1082     }
1083     return false;
1084   }
1085 
1086 static if (context == Bid64)
1087 {
1088   unittest {  // isIntegralValued
1089     write("-- isIntegralValued.");
1090     TD num;
1091     num = 12345;
1092     assertTrue(num.isIntegralValued);
1093 //    num = TD("123456098420234978023480");
1094 //    assertTrue(num.isIntegralValued);
1095     num = 1.5;
1096     assertTrue(!num.isIntegralValued);
1097     num = 1.5E+1;
1098     assertTrue(num.isIntegralValued);
1099     num = 0;
1100     assertTrue(num.isIntegralValued);
1101     num = "2.19000000E+5";
1102     num = "21900.000E-2";
1103     assertTrue(num.isIntegralValued);
1104     writeln("passed");
1105   }
1106 }
1107 
1108   /// Returns true if this number is a true value.
1109   /// Non-zero finite numbers are true.
1110   /// Infinity is true and NaN is false.
1111   @safe
1112   const bool isTrue()
1113   {
1114     return isFinite && !isZero || isInfinite;
1115   }
1116 
1117   /// Returns true if this number is a false value.
1118   /// Finite numbers with zero coefficient are false.
1119   /// Infinity is true and NaN is false.
1120   @safe
1121   @property
1122   const bool isFalse()
1123   {
1124     return isNaN || isZero;
1125   }
1126 
1127 static if (context == Bid64)
1128 {
1129   unittest {  //isTrue/isFalse
1130     write("-- isTrue/isFalse...");
1131 //    assertTrue(TD(1));
1132 //    assert(ONE);
1133 //    assertEqual(ONE, true);
1134 //    assertTrue(cast(bool)ONE);
1135     assertTrue(TD("1").isTrue);
1136     assertFalse(TD("0").isTrue);
1137     assertTrue(infinity.isTrue);
1138     assertFalse(nan.isTrue);
1139     assertTrue(TD("0").isFalse);
1140     assertFalse(TD("1").isFalse);
1141     assertFalse(infinity.isFalse);
1142     assertTrue(nan.isFalse);
1143     writeln("passed");
1144   }
1145 }
1146 
1147 /*  @safe
1148   const bool isZeroCoefficient() {
1149     return !isSpecial && coefficient == 0;
1150   }*/
1151 
1152 static if (context == Bid64)
1153 {
1154 /*  unittest {  // isZeroCoefficient
1155     write("-- isZeroCoeff......");
1156     TD num;
1157     num = 0;
1158     assertTrue(num.isZeroCoefficient);
1159     num = BigInt("-0");
1160     assertTrue(num.isZeroCoefficient);
1161     num = TD("0E+4");
1162     assertTrue(num.isZeroCoefficient);
1163     num = 12345;
1164     assertFalse(num.isZeroCoefficient);
1165     num = 1.5;
1166     assertFalse(num.isZeroCoefficient);
1167     num = TD.NaN;
1168     assertFalse(num.isZeroCoefficient);
1169     num = TD.Infinity;
1170     assertFalse(num.isZeroCoefficient);
1171     writeln("passed");
1172   }*/
1173 }
1174 
1175 //--------------------------------
1176 // assignment
1177 //--------------------------------
1178 
1179   /// Assigns a decimal number (makes a copy)
1180   void opAssign(T:decimal)(in T that)
1181   {
1182     this.m_tag    = that.m_tag ;
1183     this.m_digits  = that.m_digits;
1184     this.m_sign  = that.m_sign;
1185     this.m_expo   = that.m_expo;
1186     this.m_coff   = that.m_coff;
1187   }
1188 
1189   ///  Assigns an BigInt value.
1190   void opAssign(T:BigInt)(T that)
1191   {
1192     this = decimal(that);
1193   }
1194 
1195   ///  Assigns an boolean value.
1196   void opAssign(T:bool)(T that)
1197   {
1198     this = decimal(that);
1199   }
1200 
1201   /// Assigns an value.
1202   void opAssign(T)(in T that) if (isIntegral!T)
1203   {
1204       this = decimal(BigInt(that));
1205   }
1206 
1207   /// Assigns a floating point value.
1208   void opAssign(T:real)(in T that) if (isFloatingPoint!T)
1209   {
1210     this = decimal(that);
1211   }
1212 
1213   ///  Assigns a string value.
1214   void opAssign(T:string)(in T that)
1215   {
1216     this = decimal(that);
1217   }
1218 
1219 static if (context == Bid64)
1220 {
1221   unittest {  // opAssign
1222     write("-- opAssign.........");
1223     TD num;
1224     string str;
1225     num = TD(245, 8, true);
1226     str = "-2.45E+10";
1227     assertStringEqual(num,str);
1228     num = long.max;
1229     str = "9223372036854775807";
1230     assertStringEqual(num,str);
1231 //    num = (int.max - 12);
1232 //    str = "-13";
1233     assertStringEqual(num,str);
1234     num = 237UL;
1235     str = "237";
1236     assertStringEqual(num,str);
1237 //if (!__ctfe) writefln("real.max = %.18G", real.max);
1238 //if (!__ctfe) writefln("real.dig = %s", real.dig);
1239 //if (!__ctfe) writefln("real.max_10_exp = %s", real.max_10_exp);
1240     num = real.max;
1241 //if (!__ctfe) writefln("num = %s", num);
1242     str = "1.18973149535723176E+4932";
1243 //if (!__ctfe) writefln("str = %s", str);
1244     assertStringEqual(num, str);
1245     num = BigInt("123456098420234978023480");
1246     str = "123456098420234978023480";
1247     assertStringEqual(num, str);
1248     num = "123456098420234978023480";
1249     assertStringEqual(num, str);
1250     writeln("test missing");
1251   }
1252 }
1253 
1254 //--------------------------------
1255 // toString functions
1256 //--------------------------------
1257 
1258   /// Converts a number to the default string representation.
1259   public string toString(string fmStr = "%s") const
1260   {
1261     return eris.decimal.conv.toString(this, fmStr);
1262   }
1263 
1264   /// Converts a number to an abstract string representation.
1265   public string toAbstract() const
1266   {
1267     return abstractForm(this);
1268   }
1269 
1270   /// Converts a number to a full string representation.
1271   public string toFull() const
1272   {
1273     return fullForm(this);
1274   }
1275 
1276   /// Converts a number to a "scientific notation" string representation.
1277   public string toScientific() const
1278   {
1279     return sciForm(this);
1280   }
1281 
1282   /// Converts a number to an "engineering notation" string representation.
1283   public string toEngineering() const
1284   {
1285     return engForm(this);
1286   }
1287 
1288 //--------------------------------
1289 // comparison
1290 //--------------------------------
1291 
1292   /// Returns -1, 0 or 1, if this number is less than, equal to,
1293   /// or greater than the argument, respectively. NOTE: The comparison
1294   /// is made to the current precision.
1295   const int opCmp(T:decimal)(T that)
1296   {
1297     return compare(this, that);
1298   }
1299 
1300   /// Returns -1, 0 or 1, if this number is less than, equal to,
1301   /// or greater than the argument, respectively.
1302   const int opCmp(T)(T that)
1303   {
1304     return opCmp(decimal(that));
1305   }
1306 
1307   /// Returns true if this number is equal to the argument.
1308   /// Finite numbers are equal if they are numerically equal
1309   /// to the current precision.
1310   /// Infinities are equal if they have the same sign.
1311   /// Zeros are equal regardless of sign.
1312   /// A NaN is not equal to any number, not even to another NaN.
1313   /// A number is not even equal to itself (this != this) if it is a NaN.
1314   const bool opEquals(T:decimal)(T that)
1315   {
1316     return equals(this, that);
1317   }
1318 
1319   /// Returns true if this number is equal to the argument.
1320   const bool opEquals(T)(T that)
1321   {
1322     return opEquals(decimal(that));
1323   }
1324 
1325 static if (context == Bid64)
1326 {
1327   unittest {  // comparison
1328     write("-- comparison.......");
1329     TD num1, num2;
1330     num1 = 105;
1331     num2 = 10.543;
1332     assert(num1 == 105L);
1333     assertGreaterThan(num1, num2);
1334     assertNotEqual(num1, num2);
1335     assertGreaterThan(num1, num2);
1336     assertLessThan(num2, num1);
1337     num1 = 10.543;
1338     assertNotLessThan(num1, num2);
1339     assertNotGreaterThan(num2, num1);
1340     assertEqual(num1, num2);
1341     writeln("passed");
1342   }
1343 }
1344 
1345 //--------------------------------
1346 // unary arithmetic operators
1347 //--------------------------------
1348 
1349   /// Returns the result of the
1350   /// unary operation on this number.
1351   //@safe
1352   public decimal opUnary(string op)()
1353   {
1354     static if (op == "+")
1355     {
1356       return plus(this);
1357     }
1358     else static if (op == "-")
1359     {
1360       return minus(this);
1361     }
1362     else static if (op == "++")
1363     {
1364       this = add(this, 1);
1365       return this;
1366     }
1367     else static if (op == "--")
1368     {
1369       this = sub(this, 1);
1370       return this;
1371     }
1372   }
1373 
1374 static if (context == Bid64)
1375 {
1376   unittest {  // opUnary
1377     write("-- opUnary..........");
1378     TD num, actual, expect;
1379     num = 134;
1380     expect = num;
1381     actual = +num;
1382     assertEqual(actual, expect);
1383     num = "134.02";
1384     expect = "-134.02";
1385     actual = -num;
1386     assertEqual(actual, expect);
1387     num = 134;
1388     expect = 135;
1389     actual = ++num;
1390     assertEqual(actual, expect);
1391     num = 1.00E8;
1392     expect = num - 1;
1393     actual = --num;
1394     assertEqual(actual, expect);
1395     num = 1.00E8;
1396     expect = num;
1397     actual = num--;
1398     assertEqual(actual, expect);
1399     num = TD(9999999, 90);
1400     expect = num;
1401     actual = num++;
1402     assertEqual(actual, expect);
1403     num = 12.35;
1404     expect = 11.35;
1405     actual = --num;
1406     assertEqual(actual, expect);
1407     writeln("passed");
1408   }
1409 }
1410 
1411 //--------------------------------
1412 //  binary arithmetic operators
1413 //--------------------------------
1414 
1415   /// Returns the result of the specified
1416   /// binary operation on this number and the argument.
1417   public decimal opBinary(string op, D:decimal)(in D that) const
1418   {
1419     static if (op == "+")
1420     {
1421       return add(this, that);
1422     }
1423     else static if (op == "-")
1424     {
1425       return sub(this, that);
1426     }
1427     else static if (op == "*")
1428     {
1429       return mul(this, that);
1430     }
1431     else static if (op == "/")
1432     {
1433       return div(this, that);
1434     }
1435     else static if (op == "%")
1436     {
1437       return remainder(this, that);
1438     }
1439   }
1440 
1441 static if (context == Bid64)
1442 {
1443   unittest
1444   {  // opBinary
1445     write("-- opBinary.........");
1446     struct S { string op; string x; string y; string z; }
1447     S[] tests =
1448     [
1449       { "+", "4", "8", "12" },
1450       { "-", "4", "8", "-4" },
1451       { "*", "4", "8", "32" },
1452       { "/", "5", "2", "2.5" },
1453       { "/", "2", "5", "0.4" },
1454 
1455       { "%", "10", "3", "1" },
1456       { "%", "3", "10", "3" },
1457       { "&", "00011010", "10001110", "1010" },
1458       { "|", "00011010", "10001110", "10011110" },
1459       { "^", "00011010", "10001110", "10010100" },
1460     ];
1461     foreach (i, s; tests)
1462     {
1463       testBinaryOp(s.op, s.x, s.y, s.z);
1464     }
1465     writeln("passed");
1466   }
1467 }
1468 
1469   /// Returns the result of performing the specified
1470   /// binary operation on this number and the argument.
1471   decimal opBinary(string op, T)(T x) const
1472   {
1473     return opBinary!op(decimal(x));
1474   }
1475 
1476   /// Returns the result of performing the specified
1477   /// binary operation on this number and the argument.
1478   decimal opBinaryRight(string op, T)(in T x) const
1479   {
1480     static if (op == "+")
1481     {
1482       return add(this, x, decimal.context);
1483     }
1484     else static if (op == "-")
1485     {
1486       return sub(decimal(x), this, decimal.context);
1487     }
1488     else static if (op == "*")
1489     {
1490       return mul(this, x, decimal.context);
1491     }
1492     else static if (op == "/")
1493     {
1494       return div(decimal(x), this, decimal.context);
1495     }
1496     else static if (op == "%")
1497     {
1498       return remainder(decimal(x), this, decimal.context);
1499     }
1500     assert(false);
1501   }
1502 
1503 //-----------------------------
1504 // operator assignment
1505 //-----------------------------
1506 
1507   /// Performs the specified binary operation on this number
1508   /// and the argument then assigns the result to this number.
1509   ref decimal opOpAssign(string op, T:decimal) (T x)
1510   {
1511     this = opBinary!op(x);
1512     return this;
1513   }
1514 
1515   /// Performs the specified binary operation on this number
1516   /// and the argument then assigns the result to this number.
1517   ref decimal opOpAssign(string op, T) (T x)
1518   {
1519     this = opBinary!op(decimal(x));
1520     return this;
1521   }
1522 
1523 static if (context == Bid64)
1524 {
1525   unittest {  // opOpAssign
1526     write("-- opOpAssign.......");
1527     TD op1, op2, actual, expect;
1528     op1 = 23.56;
1529     op2 = -2.07;
1530     op1 += op2;
1531     expect = 21.49;
1532     actual = op1;
1533     assertEqual(actual, expect);
1534     op1 *= op2;
1535     expect = -44.4843;
1536     actual = op1;
1537     assertEqual(actual, expect);
1538     writeln("passed");
1539   }
1540 }
1541 
1542 //--------------------------------
1543 // mathematical constants
1544 //--------------------------------
1545 
1546 /*  enum decimal RealMax = decimal("1.1897314953572317649E+4932");
1547   enum decimal RealMin = RealMax.copyNegate;
1548   enum decimal RealMinNorm = decimal("3.362103143112093506E-4932");
1549 
1550   enum decimal DoubleMax = decimal("1.7976931348623157079E+308");
1551   enum decimal DoubleMin = DoubleMax.copyNegate;
1552   enum decimal DoubleMinNorm = decimal("2.2250738585072013832E-308");
1553   enum decimal LongMax = decimal("9223372036854775807");
1554   enum decimal LongMin = decimal("-9223372036854775808");
1555   enum decimal IntMax = decimal("2147483647");
1556   enum decimal IntMin = decimal("-2147483648");*/
1557 
1558 //  mixin Constant!("REAL_MAX", "1.1897314953572317649E+4932");
1559 
1560 //-----------------------------
1561 // nextUp, nextDown, nextAfter
1562 //-----------------------------
1563 
1564   /// Returns the smallest representable number that is larger than
1565   /// this number.
1566   decimal nextUp() const
1567   {
1568     return nextPlus(this, decimal.context);
1569   }
1570 
1571   /// Returns the largest representable number that is smaller than
1572   /// this number.
1573   decimal nextDown() const
1574   {
1575     return nextMinus(this, decimal.context);
1576   }
1577 
1578   /// Returns the representable number that is closest to the
1579   /// this number (but not this number) in the
1580   /// direction toward the argument.
1581   decimal nextAfter(decimal x) const
1582   {
1583     return nextToward(this, x, decimal.context);
1584   }
1585 
1586   static if (context == Bid64) {
1587   unittest {  // nextUp, nextDown, nextAfter
1588     write("-- next.............");
1589     TD big = 123.45;
1590     assertEqual(big.nextUp,   TD("123.4500000000001"));
1591     assertEqual(big.nextDown, TD("123.4499999999999"));
1592     assertEqual(big.nextAfter(TD(123.46)), big.nextUp);
1593     assertEqual(big.nextAfter(TD(123.44)), big.nextDown);
1594     writeln("passed");
1595   }}
1596 
1597 
1598   static if (context == Bid64) {
1599   unittest {
1600     writeln("==========================");
1601     writeln("decimal64..............end");
1602     writeln("==========================");
1603   }}
1604 }
1605 
1606 unittest {
1607   writeln("==========================");
1608   writeln("decimal..............begin");
1609   writeln("==========================");
1610 }
1611 
1612 package BigInt pow10b(uint n)
1613 {
1614   enum BigInt[19] tens =
1615   [
1616     BigInt(1),
1617     BigInt(10),
1618     BigInt(100),
1619     BigInt(1000),
1620     BigInt(10000),
1621     BigInt(100000),
1622     BigInt(1000000),
1623     BigInt(10000000),
1624     BigInt(100000000),
1625     BigInt(1000000000),
1626     BigInt(10000000000),
1627     BigInt(100000000000),
1628     BigInt(1000000000000),
1629     BigInt(10000000000000),
1630     BigInt(100000000000000),
1631     BigInt(1000000000000000),
1632     BigInt(10000000000000000),
1633     BigInt(100000000000000000),
1634     BigInt(1000000000000000000)
1635   ];
1636 
1637   if (n < 19) return tens[n];
1638   return BigInt(10)^^n;
1639 }
1640 
1641 unittest
1642 {
1643   for(uint n = 0; n < 19; n++)
1644   {
1645 //if (!__ctfe) writefln("pow10b(n) = %s", pow10b(n));
1646   }
1647 }
1648 
1649 //package BigInt pow10b(int n)
1650 //{
1651 //  const BigInt ten = 10;
1652 //  if (n < 19) return btens[n];
1653 //  return ten^^n;
1654 //}
1655 
1656 /// Returns true if the parameter is convertible to a decimal number.
1657 public enum bool isConvertible(T) =
1658   is(T:BigInt) || std.traits.isNumeric!T ||
1659   is(T:string) || isBoolean!T;
1660 
1661 unittest {
1662   write("-- isConvertible....");
1663   assertTrue(isConvertible!int);
1664   assertTrue(isConvertible!bool);
1665   assertTrue(isConvertible!string);
1666   assertTrue(isConvertible!BigInt);
1667   assertTrue(isConvertible!double);
1668 //  assertFalse(isConvertible!creal);
1669   assertFalse(isConvertible!TD);
1670   writeln("passed");
1671 }
1672 
1673 public enum bool isInteger(T) =
1674   is(T:BigInt) || isIntegral!T;
1675 
1676 unittest {
1677   write("-- isInteger........");
1678   assertTrue(isInteger!long);
1679   assertTrue(isInteger!int);
1680   assertFalse(isInteger!float);
1681   assertFalse(isInteger!bool);
1682   assertTrue(isInteger!BigInt);
1683   assertTrue(isInteger!byte);
1684   assertTrue(isInteger!ubyte);
1685   writeln("passed");
1686 }
1687 
1688 /// Returns true if the parameter is a decimal number.
1689 public enum bool isDecimal(D) = hasMember!(D, "IsDecimal");
1690 //public enum bool isDecimal(D) = is(D:decimal);
1691 unittest
1692 {  // constants
1693   static struct S { bool x; bool expect; }
1694   S[] s =
1695   [
1696     { isDecimal!TD, true },
1697     { isDecimal!int, true },
1698   ];
1699   auto f = FunctionTest!(S,bool)("isDecimal");
1700   foreach (t; s) f.test(t, t.x);
1701   writefln(f.report);
1702 }
1703 
1704 unittest {
1705   write("-- isDecimal........");
1706   TD dummy;
1707   assertTrue(isDecimal!TD);
1708   assertFalse(isDecimal!int);
1709 //  assertTrue(isDecimal!Dec64);
1710   writeln("passed");
1711 }
1712 
1713 
1714 // TODO: move these to math
1715 //--------------------------------
1716 // decimal constant templates
1717 //--------------------------------
1718 
1719 /// mixin template to create a constant at the type precision,
1720 /// with an option to create an arbitrary precision constant.
1721 /*mixin template Constant(string name)
1722 {
1723   mixin ("public static decimal " ~ name ~ "(int precision = decimal.precision)"
1724     ~ "{"
1725       ~ "if (precision != decimal.precision)"
1726       ~ "{"
1727         ~ "return eris.decimal.math." ~ name ~ "!decimal(precision);"
1728       ~ "}"
1729     ~ "return " ~ name.toUpper ~ ";"
1730     ~ "}");
1731 }*/
1732 
1733 /*mixin template Constant(string name, string value)
1734 {
1735   mixin
1736   (
1737     "static decimal " ~ name ~ "()"
1738   ~ "{"
1739     ~ "static bool initialized = false;"
1740     ~ "static decimal " ~ name ~ ";"
1741     ~ "if (!initialized)"
1742     ~ "{"
1743       ~ name ~ " = decimal(\"" ~ value ~ "\");"
1744       ~ "initialized = true;"
1745     ~ "}"
1746     ~ "return " ~ name ~ ";"
1747   ~ "}"
1748   );
1749 }*/
1750 
1751 /*
1752 /// mixin template to create a constant at the type precision,
1753 /// with an option to create an arbitrary precision constant.
1754 mixin template Constant(string lcName, string ucName)
1755 {
1756   mixin ("public static decimal " ~ lcName ~ "(int precision = decimal.precision)"
1757     ~ "{"
1758       ~ "if (precision != decimal.precision)"
1759       ~ "{"
1760         ~ "return eris.decimal.math." ~ lcName ~ "!decimal(precision);"
1761       ~ "}"
1762     ~ "return " ~ ucName ~ ";"
1763     ~ "}");
1764 }
1765 */
1766 
1767 // TODO: move this to rounding.d
1768 
1769 version(unittest)
1770 {
1771 
1772   public enum bool testBinaryOp(D)(string op, D x, D y, D z,
1773       string file = __FILE__, int line = __LINE__)
1774     if (isDecimal!D)
1775   {
1776     switch (op)
1777     {
1778     // infix operators
1779     case "+":
1780       return assertBinaryOp("plus", x, y, x + y, z, file, line);
1781     case "-":
1782       return assertBinaryOp("minus", x, y, x - y, z, file, line);
1783     case "*":
1784       return assertBinaryOp("times", x, y, x * y, z, file, line);
1785     case "/":
1786       return assertBinaryOp("divided by", x, y, x / y, z, file, line);
1787     case "%":
1788       return assertBinaryOp("mod", x, y, x % y, z, file, line);
1789     default:
1790       return false;
1791     }
1792   }
1793 
1794   public enum bool testBinaryOp(D)
1795     (string op, D x, D y, D z, string file = __FILE__, int line = __LINE__)
1796     if (!isDecimal!D && isConvertible!D)
1797   {
1798     return testBinaryOp!TD
1799       (op, TD(x), TD(y), TD(z), file, line);
1800   }
1801 
1802   private bool assertBinaryOp(D)
1803     (string op, D x, D y, D computed, D expected, string file, int line)
1804   {
1805     if (computed == expected)
1806     {
1807       return true;
1808     }
1809     else
1810     {
1811       writeln("failed at ", std.path.baseName(file), "(", line, "): \"",
1812         x , "\" " , op, " \"", y , "\" equals \"",
1813         computed, "\" not \"", expected, "\".");
1814       return false;
1815     }
1816   }
1817 
1818   // TODO: (efficiency) can this take advantage of small numbers? i.e. < long.max?
1819   public U pow10(U)(int n) if (is(U!BigInt) || is(U!long))
1820   {
1821     auto ten = U(10);
1822 //    if (n < 0) throw new InvalidOperationException();
1823     if (n == 0) return ten;
1824     return ten^^n;
1825   }
1826 
1827 /*  public enum double pow10Dbl(int n)
1828   {
1829     static double[23] dtens;
1830     static bool initialized = false;
1831     if (!initialized)
1832     {
1833       dtens[0] = 1.0;
1834       for (size_t i = 1; i < dtens.length; i++)
1835       {
1836         dtens[i] = dtens[i-1] * 10.0;
1837       }
1838       initialized = true;
1839     }
1840     if (n > 22) return double.nan;
1841     return dtens[n];
1842   }*/
1843 
1844 // ======================================================== //
1845 // dead code
1846 // ======================================================== //
1847 
1848 /+
1849   /// Converts a decimal number to a real number. The decimal will be
1850   /// rounded to the RealContext before conversion, if necessary.
1851   public real toReal() const
1852   {
1853     // special values
1854     if (this.isNaN) return real.nan;
1855     if (this.isInfinite) return sign ? -real.infinity : real.infinity;
1856     if (this.isZero) return sign ? -0.0 : 0.0;
1857     int realMinExpo = 1 - RealContext.maxExpo;
1858     if (this.isSubnormal(realMinExpo)) return real.nan;
1859 
1860     // if this number is larger than the largest real value,
1861     // return infinity
1862     if (this.m_expo >= real.max_10_exp) {
1863       if (this > RealMax)  return  real.infinity;
1864       if (this < RealMin) return -real.infinity;
1865     }
1866 
1867     // if smaller than the smallest value, return zero
1868     if (this.m_expo <= real.min_10_exp) {
1869       if (this.copyAbs < RealMinNorm) return this.sign ? -0.0 : 0.0;
1870     }
1871 
1872     // will the coefficent fit into a long integer?
1873     if (this.coff.ulongLength <= 2)
1874     {
1875       return longToReal(this);
1876     }
1877 
1878     // NOTE: There are real numbers that will be rounded unnecessarily
1879     // (i.e. more than 18 digits but less than long.max)
1880     // the reduced coefficient will fit
1881     bigd reduced = this.reduce(RealContext);
1882     if (reduced.coff.ulongLength <= 2)
1883     {
1884       return longToReal(reduced);
1885     }
1886 
1887     return real.nan;  // NOTE: nan or infinity?
1888   }
1889 
1890   static if (context == TestContext) {
1891   unittest {  // toReal, toDecimal
1892     write("-- toReal...........");
1893     static real[] tests =
1894     [
1895       1.0,
1896       2.0,
1897       1.0E5,
1898       0.1,
1899       123.456,
1900       32E-27,
1901       double.max,
1902       real.max,
1903     ];
1904 
1905     foreach (i, s; tests)
1906     {
1907       bigd d = toDecimal(s);
1908       real r = d.toReal();
1909       assertEqual(r, d, i);
1910     }
1911     writeln("passed");
1912   }}
1913 
1914 
1915   public double toDouble() const
1916   {
1917     // try for an exact conversion...
1918     if (digits <= 15) {
1919       int absExpo = std.math.abs(m_expo);
1920       if (absExpo <= 22) {
1921         double s = cast(double)(coefficient.toLong);
1922         if (absExpo == 0) return s;
1923         double p = pow10Dbl(absExpo);
1924         if (m_expo > 0) return s * p;
1925         if (m_expo < 0) return s / p;
1926       }
1927     }
1928     // TODO: (behavior) add method for other values
1929     return double.nan;
1930   }
1931 
1932   // TODO: (testing) add unit tests
1933   unittest {
1934     write("toDouble...");
1935     TD x = "3.14159";
1936     writefln("x.toDouble = %s", x.toDouble);
1937     writeln("test missing");
1938   }
1939 
1940 //--------------------------------
1941 // casts
1942 //--------------------------------
1943 
1944    bool opCast(T:bool)() const
1945   {
1946     return isTrue;
1947   }
1948 
1949    T opCast(T)() const if (isDecimal!T)
1950   {
1951     return T(this);
1952   }
1953 
1954    T opCast(T)() const if (isFloatingPoint!T)
1955   {
1956     return T(this);
1957   }
1958 
1959   static if (context == TestContext) {
1960   unittest {
1961     write("-- opCast...........");
1962 /*    assertFalse(TD.init);
1963     TD abc = TD(12,4);
1964     assertTrue(abc);
1965     dec99 def = cast(dec99)abc;
1966     assertEqual(abc, def);
1967     TD def2 = cast(dec99)abc;
1968     assertEqual(def, def2);
1969     int n = 7;
1970     TD bdn = cast(TD)n;
1971     assertEqual(bdn, TD(7));
1972     auto tr = cast(TD)12;
1973     assertEqual(typeid(tr), typeid(bdn));
1974 //    assertTrue(is(tr:bdn));
1975     dec99 big = 1234567890123;
1976     TD klm = TD(big);
1977     assertEqual(klm, big);  // klm has not been rounded.
1978     assertNotEqual(abs(klm), big);  // klm has been rounded.
1979     dec99 spcl = dec99.infinity(true);
1980     klm = TD(spcl);
1981     assertEqual(klm, TD("-Infinity"));*/
1982     writeln("test missing");
1983   }}
1984 
1985 +/
1986 
1987 // ======================================================== //
1988 // end dead code
1989 // ======================================================== //
1990 
1991 
1992 
1993 }