comparison src/decimal/decimal.d @ 0:42cf4db6be32

Creation
author Paul (paul.d.anderson@comcast.net)
date Sat, 13 Mar 2010 13:22:25 -0800
parents
children a984d3056cc4
comparison
equal deleted inserted replaced
-1:000000000000 0:42cf4db6be32
1 // TODO: ensure context flags are being set and cleared properly.
2
3 // TODO: add exp() add sqrt() add power():
4
5 // TODO: add a set/getPayload to Decimal
6
7 // TODO: unittest opPostDec && opPostInc.
8
9 // TODO: this(str): add tests for just over/under int.max, int.min
10
11 // TODO: organize by structs, lib functions modules functions, etc.
12
13 // TODO: opEquals unit test should include numerically equal testing.
14
15 // TODO: write some test cases for flag setting. test the add/sub/mul/div functions
16
17 // TODO: to/from real or double (float) values needs definition and implementation.
18
19 // TODO: need to determine the property name for dig and/or digits
20
21 module decimal.decimal;
22
23 import decimal.context;
24 import std.bigint;
25 import std.conv;
26 import std.ctype: isdigit;
27 import std.math: PI, LOG2;
28 import std.stdio: write, writeln;
29 import std.string;
30
31 // special values
32 private enum SpVal {CLEAR, ZERO, INF, QNAN, SNAN};
33
34 // common decimal "numbers"
35 public:
36 static immutable Decimal ONE = {spval:SpVal.CLEAR, ceff:{[1]}};
37 static immutable Decimal TEN = {spval:SpVal.CLEAR, ceff:{[10]}};
38 static immutable Decimal NaN = {spval:SpVal.QNAN};
39 static immutable Decimal POS_INF = {spval:SpVal.INF};
40 static immutable Decimal NEG_INF = {sign:true, SpVal.INF};
41 static immutable Decimal ZERO = {spval:SpVal.ZERO};
42 static immutable Decimal NEG_ZERO = {sign:true, SpVal.ZERO};
43
44 // active context
45 public DecimalContext context = DEFAULT_CONTEXT;
46
47 // singleton ContextStack
48 private ContextStack contextStack;
49
50 /// saves the current context
51 public void pushContext() {
52 contextStack.push();
53 }
54
55 /// restores the previous context
56 public void popContext() {
57 contextStack.pop();
58 }
59
60 /**
61 * A struct representing an arbitrary-precision floating-point number.
62 *
63 * The implementation follows the General Decimal Arithmetic
64 * Specification, Version 1.70 (25 Mar 2009),
65 * http://www.speleotrove.com/decimal. This specification conforms with
66 * IEEE standard 754-2008.
67 */
68 struct Decimal {
69
70 private:
71 SpVal spval = SpVal.QNAN; // special values: default value is quiet NaN
72 bool sign = false; // true if the value is negative, false otherwise.
73 int expo = 0; // the exponent of the Decimal value
74 BigInt ceff; // the coefficient of the Decimal value
75 // NOTE: not a uint -- causes math problems down the line.
76 int digits; // the number of decimal digits in this number.
77 // (unless the number is a special value)
78
79 //--------------------------------
80 // construction
81 //--------------------------------
82
83 public:
84 /**
85 * Constructs a Decimal number from a sign, a BigInt coefficient and
86 * an integer exponent.
87 * The precision of the number is deduced from the number of decimal
88 * digits in the coefficient.
89 */
90 this(const bool sign, const BigInt coefficient, const int exponent) {
91 this.clear();
92 if (coefficient < BIG_ZERO) {
93 this.sign = !sign;
94 this.ceff = -coefficient;
95 }
96 else {
97 this.sign = sign;
98 this.ceff = coefficient;
99 if (coefficient == BIG_ZERO) {
100 this.spval = SpVal.ZERO;
101 }
102 }
103 this.expo = exponent;
104 this.digits = numDigits(this.ceff, 1);
105 }
106
107 /**
108 * Constructs a Decimal number from a sign, an integer coefficient and
109 * an integer exponent.
110 */
111 this(const bool sign, const int coefficient, const int exponent) {
112 this(sign, BigInt(coefficient), exponent);
113 }
114
115 /**
116 * Constructs a Decimal number from a sign, a special value string and
117 * an optional payload.
118 */
119 this(const bool sign, string str, const uint payload = 0) {
120 this.clear();;
121 this.sign = sign;
122 if (icmp(str, "inf") == 0 || icmp(str, "infinity") == 0) {
123 spval = SpVal.INF;
124 return;
125 }
126 if (icmp(str, "snan") == 0) {
127 spval = SpVal.SNAN;
128 }
129 else {
130 spval = SpVal.QNAN;
131 }
132 ceff = payload;
133 }
134
135 /**
136 * Constructs a Decimal from a BigInt coefficient and an int exponent.
137 * The sign of the number is the sign of the coefficient.
138 */
139 this(const BigInt coefficient, const int exponent) {
140 this(false, coefficient, exponent);
141 };
142
143 /**
144 * Constructs a Decimal from a BigInt.
145 */
146 this(const BigInt coefficient) {
147 this(coefficient, 0);
148 };
149
150 /**
151 * Constructs a Decimal from an integer coefficient and an integer exponent.
152 */
153 this(const long coefficient, const int exponent) {
154 this(BigInt(coefficient), exponent);
155 }
156
157 /**
158 * Constructs a Decimal from an integer value.
159 */
160 this(const long coefficient) {
161 this(BigInt(coefficient), 0);
162 }
163
164 /**
165 * Constructs a Decimal from an integer coefficient, exponent and precision.
166 */
167 // TODO: should this set flags? probably not.
168 this(const long coefficient, const int exponent, const int precision) {
169 this(coefficient, exponent);
170 pushContext();
171 context.precision = precision;
172 setDigits(this);
173 popContext();
174 }
175
176 /**
177 * Constructs a Decimal from a real value.
178 */
179 this(const real r) {
180 string str = format("%.*G", cast(int)context.precision, r);
181 this = str;
182 }
183
184 /**
185 * Constructs a Decimal from a double value.
186 * Set to the specified precision
187 */
188 this(const real r, int precision) {
189 string str = format("%.*E", precision, r);
190 this = str;
191 }
192
193 // copy constructor
194 this(const Decimal that) {
195 this = that;
196 };
197
198 // construct from string representation
199 this(const string str) {
200 this = str;
201 };
202
203 unittest {
204 write("construction.");
205 Decimal f = Decimal(BigInt(1234), 567);
206 assert(f.toString() == "1.234E+570");
207 f = Decimal(BigInt(1234));
208 assert(f.toString() == "1234");
209 f = Decimal(BigInt(123400));
210 assert(f.toString() == "123400");
211 f = Decimal(1234, 567);
212 assert(f.toString() == "1.234E+570");
213 f = Decimal(BigInt(1234));
214 assert(f.toString() == "1234");
215 f = Decimal(1234, 0, 9);
216 assert(f.toString() == "1234.00000");
217 Decimal dec = Decimal(1234, 1, 9);
218 assert(dec.toString() == "12340.0000");
219 dec = Decimal(12, 1, 9);
220 assert(dec.toString() == "120.000000");
221 dec = Decimal(int.max, -4, 9);
222 assert(dec.toString() == "214748.365");
223 dec = Decimal(int.max, -4);
224 assert(dec.toString() == "214748.3647");
225 dec = Decimal(1234567, -2, 5);
226 assert(dec.toString() == "12346");
227 writeln("passed");
228 }
229
230 unittest {
231 write("this(str)....");
232 Decimal f;
233 string str = "0";
234 f = str;
235 assert(f.toString() == str);
236 assert(f.toAbstract() == "[0,0,0]");
237 str = "0.00";
238 f = str;
239 assert(f.toString() == str);
240 assert(f.toAbstract() == "[0,0,-2]");
241 str = "0.0";
242 f = str;
243 assert(f.toString() == str);
244 assert(f.toAbstract() == "[0,0,-1]");
245 f = "0.";
246 assert(f.toString() == "0");
247 assert(f.toAbstract() == "[0,0,0]");
248 f = ".0";
249 assert(f.toString() == "0.0");
250 assert(f.toAbstract() == "[0,0,-1]");
251 str = "1.0";
252 f = str;
253 assert(f.toString() == str);
254 assert(f.toAbstract() == "[0,10,-1]");
255 str = "1.";
256 f = str;
257 assert(f.toString() == "1");
258 assert(f.toAbstract() == "[0,1,0]");
259 str = ".1";
260 f = str;
261 assert(f.toString() == "0.1");
262 assert(f.toAbstract() == "[0,1,-1]");
263 f = Decimal("123");
264 assert(f.toString() == "123");
265 f = Decimal("-123");
266 assert(f.toString() == "-123");
267 f = Decimal("1.23E3");
268 assert(f.toString() == "1.23E+3");
269 f = Decimal("1.23E");
270 assert(f.toString() == "NaN");
271 f = Decimal("1.23E-");
272 assert(f.toString() == "NaN");
273 f = Decimal("1.23E+");
274 assert(f.toString() == "NaN");
275 f = Decimal("1.23E+3");
276 assert(f.toString() == "1.23E+3");
277 f = Decimal("1.23E3B");
278 assert(f.toString() == "NaN");
279 f = Decimal("12.3E+007");
280 assert(f.toString() == "1.23E+8");
281 f = Decimal("12.3E+70000000000");
282 assert(f.toString() == "NaN");
283 f = Decimal("12.3E+7000000000");
284 assert(f.toString() == "NaN");
285 f = Decimal("12.3E+700000000");
286 // writeln(f.toString());
287 assert(f.toString() == "1.23E+700000001");
288 f = Decimal("12.3E-700000000");
289 // writeln(f.toString());
290 assert(f.toString() == "1.23E-699999999");
291 // NOTE: since there will still be adjustments -- maybe limit to 99999999?
292 f = Decimal("12.0");
293 assert(f.toString() == "12.0");
294 f = Decimal("12.3");
295 assert(f.toString() == "12.3");
296 f = Decimal("1.23E-3");
297 assert(f.toString() == "0.00123");
298 f = Decimal("0.00123");
299 assert(f.toString() == "0.00123");
300 f = Decimal("-1.23E-12");
301 assert(f.toString() == "-1.23E-12");
302 f = Decimal("-0");
303 assert(f.toString() == "-0");
304 f = Decimal("inf");
305 assert(f.toString() == "Infinity");
306 f = Decimal("NaN");
307 assert(f.toString() == "NaN");
308 f = Decimal("-NaN");
309 assert(f.toString() == "-NaN");
310 f = Decimal("sNaN");
311 assert(f.toString() == "sNaN");
312 f = Decimal("Fred");
313 assert(f.toString() == "NaN");
314 writeln("passed");
315 }
316
317 /**
318 * dup property
319 */
320 const Decimal dup() {
321 Decimal cp;
322 cp.sign = sign;
323 cp.spval = spval;
324 cp.ceff = ceff;
325 cp.expo = expo;
326 return cp;
327 }
328
329 //--------------------------------
330 // assignment
331 //--------------------------------
332
333 /// Assigns a Decimal (makes a copy)
334 void opAssign(const Decimal that) {
335 this.sign = that.sign;
336 this.spval = that.spval;
337 this.digits = that.digits;
338 this.expo = that.expo;
339 this.ceff = that.ceff;
340 }
341
342 /// Assigns a floating point value.
343 void opAssign(const real r) {
344 this = Decimal(r);
345 }
346
347 /// Assign an integer value
348 void opAssign(const long n) {
349 spval = (n == 0) ? SpVal.ZERO : SpVal.CLEAR;
350 sign = n < 0;
351 ceff = sign ? -n : n;
352 expo = 0;
353 digits = numDigits(ceff, 1);
354 }
355
356 /// Assign a BigInt
357 void opAssign(const BigInt big) {
358 spval = (big == BIG_ZERO) ? SpVal.ZERO : SpVal.CLEAR;
359 sign = big < 0;
360 ceff = sign ? -big : big;
361 expo = 0;
362 digits = numDigits(ceff, 1);
363 }
364
365 /// Assigns a string
366 void opAssign(const string numeric_string) {
367 clear();
368 sign = false;
369
370 // strip, copy, tolower
371 char[] str = strip(numeric_string).dup;
372 tolowerInPlace(str);
373
374 // get sign, if any
375 if (startsWith(str,"-")) {
376 sign = true;
377 str = str[1..$];
378 }
379 else if (startsWith(str,"+")) {
380 str = str[1..$];
381 }
382
383 // check for NaN
384 if (startsWith(str,"nan")) {
385 spval = SpVal.QNAN;
386 if (str == "nan") {
387 ceff = BIG_ZERO;
388 return;
389 }
390 // set payload
391 str = str[3..$];
392 // ensure string is all digits
393 foreach(char c; str) {
394 if (!isdigit(c)) {
395 return;
396 }
397 }
398 // convert string to payload
399 ceff = BigInt(str.idup);
400 return;
401 };
402
403 // check for sNaN
404 if (startsWith(str,"snan")) {
405 spval = SpVal.SNAN;
406 if (str == "snan") {
407 ceff = BIG_ZERO;
408 return;
409 }
410 // set payload
411 str = str[4..$];
412 // ensure string is all digits
413 foreach(char c; str) {
414 if (!isdigit(c)) {
415 return;
416 }
417 }
418 // convert string to payload
419 ceff = BigInt(str.idup);
420 return;
421 };
422
423 // check for infinity
424 if (str == "inf" || str == "infinity") {
425 spval = SpVal.INF;
426 return;
427 };
428
429 clear();
430 // check for exponent
431 int pos = find(str, 'e');
432 if (pos > 0) {
433 // if it's just a trailing 'e', return NaN
434 if (pos == str.length - 1) {
435 spval = SpVal.QNAN;
436 return;
437 }
438 // split the string into coefficient and exponent
439 char[] xstr = str[pos+1..$];
440 str = str[0..pos];
441 // assume exponent is positive
442 bool xneg = false;
443 // check for minus sign
444 if (startsWith(xstr, "-")) {
445 xneg = true;
446 xstr = xstr[1..$];
447 }
448 // check for plus sign
449 else if (startsWith(xstr, "+")) {
450 xstr = xstr[1..$];
451 }
452
453 // ensure it's not now empty
454 if (xstr.length < 1) {
455 spval = SpVal.QNAN;
456 return;
457 }
458
459 // ensure exponent is all digits
460 foreach(char c; xstr) {
461 if (!isdigit(c)) {
462 spval = SpVal.QNAN;
463 return;
464 }
465 }
466
467 // trim leading zeros
468 while (xstr[0] == '0' && xstr.length > 1) {
469 xstr = xstr[1..$];
470 }
471
472 // make sure it will fit into an int
473 if (xstr.length > 10) {
474 spval = SpVal.QNAN;
475 return;
476 }
477 if (xstr.length == 10) {
478 // try to convert it to a long (should work) and
479 // then see if the long value is too big (or small)
480 long lex = to!long(xstr);
481 if ((xneg && (-lex < int.min)) || lex > int.max) {
482 spval = SpVal.QNAN;
483 return;
484 }
485 expo = cast(int) lex;
486 }
487 else {
488 // everything should be copacetic at this point
489 expo = to!int(xstr);
490 }
491 if (xneg) {
492 expo = -expo;
493 }
494 }
495 else {
496 expo = 0;
497 }
498
499 // remove trailing decimal point
500 if (endsWith(str, ".")) {
501 str = str[0..$-1];
502 }
503 // strip leading zeros
504 while (str[0] == '0' && str.length > 1) {
505 str = str[1..$];
506 }
507
508 // remove internal decimal point
509 int point = find(str, '.');
510 if (point >= 0) {
511 // excise the point and adjust exponent
512 str = str[0..point] ~ str[point+1..$];
513 int diff = str.length - point;
514 expo -= diff;
515 }
516
517 // ensure string is not empty
518 if (str.length < 1) {
519 spval = SpVal.QNAN;
520 return;
521 }
522
523 // ensure string is all digits
524 foreach(char c; str) {
525 if (!isdigit(c)) {
526 spval = SpVal.QNAN;
527 return;
528 }
529 }
530 // convert string to BigInt
531 ceff = BigInt(str.idup);
532 digits = numDigits(ceff, str.length);
533 if (ceff == BIG_ZERO) spval = SpVal.ZERO;
534
535 }; // end opAssign(string)
536
537 //--------------------------------
538 // string representations
539 //--------------------------------
540
541 /**
542 * Converts a Decimal to an abstract string representation.
543 */
544 private const string toAbstract() {
545 switch (spval) {
546 case SpVal.SNAN:
547 string payload = ceff == BIG_ZERO ? "" : "," ~ ceff.toString();
548 return format("[%d,%s%s]", sign ? 1 : 0, "sNaN", payload);
549 case SpVal.QNAN:
550 string payload = ceff == BIG_ZERO ? "" : "," ~ ceff.toString();
551 return format("[%d,%s%s]", sign ? 1 : 0, "qNaN", payload);
552 case SpVal.INF:
553 return format("[%d,%s]", sign ? 1 : 0, "inf");
554 default:
555 return format("[%d,%s,%d]", sign ? 1 : 0, ceff.toString(), expo);
556 }
557 }
558
559 /**
560 * Converts a Decimal to a string representation.
561 */
562 const string toString() {
563
564 // string representation of special values
565 if (spval > SpVal.ZERO) {
566 string str;
567 switch(spval) {
568 case SpVal.ZERO:
569 str = "0";
570 break;
571 case SpVal.INF:
572 str = "Infinity";
573 break;
574 case SpVal.SNAN:
575 str = "sNaN";
576 break;
577 default:
578 str = "NaN";
579 }
580 if (spval >= SpVal.QNAN && ceff != BIG_ZERO) {
581 str ~= ceff.toString();
582 }
583 return sign ? "-" ~ str : str;
584 }
585
586 // string representation of finite numbers
587 string cstr = ceff.toString();
588 int clen = cstr.length;
589 int adjx = expo + clen - 1;
590
591 // if exponent is small, don't use exponential notation
592 if (expo <= 0 && adjx >= -6) {
593 // if exponent is not zero, insert a decimal point
594 if (expo != 0) {
595 int point = std.math.abs(expo);
596 // if coefficient is too small, pad with zeroes
597 if (point > clen) {
598 cstr = zfill(cstr, point);
599 clen = cstr.length;
600 }
601 // if no chars precede the decimal point, prefix a zero
602 if (point == clen) {
603 cstr = "0." ~ cstr;
604 }
605 // otherwise insert a decimal point
606 else {
607 cstr = insert(cstr, cstr.length - point, ".");
608 }
609 }
610 return sign ? "-" ~ cstr : cstr;
611 }
612 // use exponential notation
613 // else {
614 if (clen > 1) {
615 cstr = insert(cstr, 1, ".");
616 }
617 string xstr = to!string(adjx);
618 if (adjx >= 0) {
619 xstr = "+" ~ xstr;
620 }
621 string str = cstr ~ "E" ~ xstr;
622 if (sign) {
623 return "-" ~ str;
624 }
625 else {
626 return str;
627 }
628 // } // end else
629
630 }; // end toString()
631
632 /**
633 * Converts a Decimal to an engineering string representation.
634 */
635 const string toEngString() {
636 return toString();
637 };
638
639 /**
640 * Converts a Decimal to a scientific string representation.
641 */
642 const string toSciString() {
643 return toString();
644 };
645
646 unittest {
647 write("to-sci-str...");
648 Decimal dec = Decimal(false, 123, 0);
649 assert(dec.toString() == "123");
650 assert(dec.toAbstract() == "[0,123,0]");
651 dec = Decimal(true, 123, 0);
652 assert(dec.toString() == "-123");
653 assert(dec.toAbstract() == "[1,123,0]");
654 dec = Decimal(false, 123, 1);
655 assert(dec.toString() == "1.23E+3");
656 assert(dec.toAbstract() == "[0,123,1]");
657 dec = Decimal(false, 123, 3);
658 assert(dec.toString() == "1.23E+5");
659 assert(dec.toAbstract() == "[0,123,3]");
660 dec = Decimal(false, 123, -1);
661 assert(dec.toString() == "12.3");
662 assert(dec.toAbstract() == "[0,123,-1]");
663 dec = Decimal(false, 123, -5);
664 assert(dec.toString() == "0.00123");
665 assert(dec.toAbstract() == "[0,123,-5]");
666 dec = Decimal(false, 123, -10);
667 assert(dec.toString() == "1.23E-8");
668 assert(dec.toAbstract() == "[0,123,-10]");
669 dec = Decimal(true, 123, -12);
670 assert(dec.toString() == "-1.23E-10");
671 assert(dec.toAbstract() == "[1,123,-12]");
672 dec = Decimal(false, 0, 0);
673 assert(dec.toString() == "0");
674 assert(dec.toAbstract() == "[0,0,0]");
675 dec = Decimal(false, 0, -2);
676 assert(dec.toString() == "0.00");
677 assert(dec.toAbstract() == "[0,0,-2]");
678 dec = Decimal(false, 0, 2);
679 assert(dec.toString() == "0E+2");
680 assert(dec.toAbstract() == "[0,0,2]");
681 dec = Decimal(true, 0, 0);
682 assert(dec.toString() == "-0");
683 assert(dec.toAbstract() == "[1,0,0]");
684 dec = Decimal(false, 5, -6);
685 assert(dec.toString() == "0.000005");
686 assert(dec.toAbstract() == "[0,5,-6]");
687 dec = Decimal(false, 50,-7);
688 assert(dec.toString() == "0.0000050");
689 assert(dec.toAbstract() == "[0,50,-7]");
690 dec = Decimal(false, 5, -7);
691 assert(dec.toString() == "5E-7");
692 assert(dec.toAbstract() == "[0,5,-7]");
693 dec = Decimal(false, "inf");
694 assert(dec.toString() == "Infinity");
695 assert(dec.toAbstract() == "[0,inf]");
696 dec = Decimal(true, "inf");
697 assert(dec.toString() == "-Infinity");
698 assert(dec.toAbstract() == "[1,inf]");
699 dec = Decimal(false, "NaN");
700 assert(dec.toString() == "NaN");
701 assert(dec.toAbstract() == "[0,qNaN]");
702 dec = Decimal(false, "NaN", 123);
703 assert(dec.toString() == "NaN123");
704 assert(dec.toAbstract() == "[0,qNaN,123]");
705 dec = Decimal(true, "sNaN");
706 assert(dec.toString() == "-sNaN");
707 assert(dec.toAbstract() == "[1,sNaN]");
708 writeln("passed");
709 }
710
711
712 //--------------------------------
713 // member properties
714 //--------------------------------
715
716 /// returns the exponent of this Decimal
717 const int exponent() {
718 return this.expo;
719 }
720 /// returns the coefficient of this Decimal
721 const BigInt coefficient() {
722 return this.ceff;
723 }
724
725 /// returns the sign of this Decimal
726 const int sgn() {
727 if (isZero) return 0;
728 return sign ? -1 : 1;
729 }
730
731 /// returns a Decimal with the same exponent as this Decimal
732 /// and a coefficient of 1.
733 const Decimal quantum() {
734 return Decimal(1, this.expo);
735 }
736
737 //--------------------------------
738 // floating point properties
739 //--------------------------------
740
741 static int precision() {
742 return context.precision;
743 }
744
745 /// returns the default value for this type (NaN)
746 static Decimal init() {
747 return NaN;
748 }
749
750 /// Returns NaN
751 static Decimal nan() {
752 return NaN;
753 }
754
755 /// Returns positive infinity.
756 static Decimal infinity() {
757 return POS_INF;
758 }
759
760 //--------------------------------
761 // classification properties
762 //--------------------------------
763
764 /**
765 * Returns true if this number is canonical representation (always true).
766 */
767 const bool isCanonical() {
768 return true;
769 }
770
771 /**
772 * Returns true if this Decimal is +/- zero.
773 */
774 const bool isZero() {
775 return spval == SpVal.ZERO;
776 }
777
778 /**
779 * Returns true if this Decimal is a quiet or signaling NaN.
780 */
781 const bool isNaN() {
782 return this.spval == SpVal.QNAN || this.spval == SpVal.SNAN;
783 }
784
785 /**
786 * Returns true if this Decimal is a signaling NaN.
787 */
788 const bool isSignaling() {
789 return this.spval == SpVal.SNAN;
790 }
791
792 /**
793 * Returns true if this Decimal is a quiet NaN.
794 */
795 const bool isQuiet() {
796 return this.spval == SpVal.QNAN;
797 }
798
799 /**
800 * Returns true if this Decimal is +/- infinity.
801 */
802 const bool isInfinite() {
803 return this.spval == SpVal.INF;
804 }
805
806 /**
807 * Returns true if this Decimal is not +/- infinity and not a NaN.
808 */
809 const bool isFinite() {
810 return spval != SpVal.INF
811 && spval != SpVal.QNAN
812 && spval != SpVal.SNAN;
813 }
814
815 /**
816 * Returns true if this Decimal is a NaN or infinity.
817 */
818 const bool isSpecial() {
819 return spval == SpVal.INF
820 || spval == SpVal.QNAN
821 || spval == SpVal.SNAN;
822 }
823
824 /**
825 * Returns true if this Decimal is negative. (Includes -0)
826 */
827 const bool isSigned() {
828 return this.sign;
829 }
830
831 /**
832 * Returns true if this Decimal is subnormal.
833 */
834 const bool isSubnormal() {
835 if (spval != SpVal.CLEAR) return false;
836 return adjustedExponent < context.eMin;
837 }
838
839 /**
840 * Returns true if this Decimal is subnormal.
841 */
842 const bool isNormal() {
843 if (spval != SpVal.CLEAR) return false;
844 return adjustedExponent >= context.eMin;
845 }
846
847 //--------------------------------
848 // comparison
849 //--------------------------------
850
851 /**
852 * Returns -1, 0 or 1, if this number is less than, equal to or
853 * greater than the argument, respectively.
854 */
855 int opCmp(const Decimal that) {
856 return icompare(this, that);
857 }
858
859 /**
860 * Returns true if this Decimal is equal to the specified Decimal.
861 * A NaN is not equal to any number, not even to another NaN.
862 * Infinities are equal if they have the same sign.
863 * Zeros are equal regardless of sign.
864 * Finite numbers are equal if they are numerically equal to the current precision.
865 * A Decimal may not be equal to itself (this != this) if it is a NaN.
866 */
867 const bool opEquals(ref const Decimal that) {
868 // if either is NaN...
869 if (this.isNaN || that.isNaN) return false;
870
871 // if either is infinite...
872 if (this.isInfinite || that.isInfinite) {
873 return (this.spval == that.spval && this.sign == that.sign);
874 }
875
876 // if either is zero...
877 if (this.isZero || that.isZero) {
878 return (this.isZero && that.isZero);
879 }
880 // if their signs differ
881 if (this.sign != that.sign) {
882 return false;
883 }
884
885 // if they have the same representation, they are equal
886 if (this.expo == that.expo && this.ceff == that.ceff) {
887 return true;
888 }
889
890 // otherwise they are equal if they represent the same value
891 // NOTE: this is only a check to current precision.
892 Decimal result = this - that;
893 return result.isZero;
894 }
895
896 unittest {
897 write("equals.......");
898 Decimal op1;
899 Decimal op2;
900 op1 = "NaN";
901 op2 = "NaN";
902 assert(op1 != op2);
903 op1 = "inf";
904 op2 = "inf";
905 assert(op1 == op2);
906 op2 = "-inf";
907 assert(op1 != op2);
908 op1 = "-inf";
909 assert(op1 == op2);
910 op2 = "NaN";
911 assert(op1 != op2);
912 op1 = 0;
913 assert(op1 != op2);
914 op2 = 0;
915 assert(op1 == op2);
916 writeln("passed");
917 }
918
919 //--------------------------------
920 // unary arithmetic operators
921 //--------------------------------
922
923 /**
924 * unary minus -- returns a copy with the opposite sign.
925 * This operation may set flags -- equivalent to
926 * subtract('0', b);
927 */
928 const Decimal opNeg() {
929 return minus(this);
930 }
931
932 /**
933 * unary plus -- returns a copy.
934 * This operation may set flags -- equivalent to
935 * add('0', a);
936 */
937 const Decimal opPos() {
938 return plus(this);
939 }
940
941 /**
942 * Returns this + 1.
943 */
944 Decimal opPostInc() {
945 this += ONE;
946 return this;
947 }
948
949 /**
950 * Returns this - 1.
951 */
952 Decimal opPostDec() {
953 this -= ONE;
954 return this;
955 }
956
957 //--------------------------------
958 // binary arithmetic operators
959 //--------------------------------
960
961 /// Adds a Decimal to this and returns the Decimal result
962 const Decimal opAdd(T:Decimal)(const T addend) {
963 return add(this, addend);
964 }
965
966 // Adds a number to this and returns the result.
967 const Decimal opAdd(T)(const T addend) {
968 return add(this, Decimal(addend), context);
969 }
970
971 const Decimal opSub(T:Decimal)(const T subtrahend) {
972 return subtract(this, subtrahend);
973 }
974
975 const Decimal opSub(T)(const T subtrahend) {
976 return subtract(this, Decimal(subtrahend), context);
977 }
978
979 const Decimal opMul(T:Decimal)(const T factor) {
980 return multiply(this, factor);
981 }
982
983 const Decimal opMul(T)(const T factor) {
984 return multiply(this, Decimal(factor));
985 }
986
987 const Decimal opDiv(T:Decimal)(const T divisor) {
988 return divide(this, divisor);
989 }
990
991 const Decimal opDiv(T)(const T divisor) {
992 return divide(this, Decimal(divisor));
993 }
994
995 const Decimal opMod(T:Decimal)(const T divisor) {
996 return remainder(this, divisor);
997 }
998
999 const Decimal opMod(T)(const T divisor) {
1000 return remainder(this, Decimal(divisor));
1001 }
1002
1003 //--------------------------------
1004 // arithmetic assignment operators
1005 //--------------------------------
1006
1007 Decimal opAddAssign(T)(const T addend) {
1008 this = this + addend;
1009 return this;
1010 }
1011
1012 Decimal opSubAssign(T)(const T subtrahend) {
1013 this = this - subtrahend;
1014 return this;
1015 }
1016
1017 Decimal opMulAssign(T)(const T factor) {
1018 this = this * factor;
1019 return this;
1020 }
1021
1022 Decimal opDivAssign(T)(const T divisor) {
1023 this = this / divisor;
1024 return this;
1025 }
1026
1027 Decimal opModAssign(T)(const T divisor) {
1028 this = this % divisor;
1029 return this;
1030 }
1031
1032 //-----------------------------
1033 // nextUp, nextDown, nextAfter
1034 //-----------------------------
1035
1036 const Decimal nextUp() {
1037 return nextPlus(this);
1038 }
1039
1040 const Decimal nextDown() {
1041 return nextMinus(this);
1042 }
1043
1044 const Decimal nextAfter(const Decimal dcm) {
1045 return nextToward(this, dcm);
1046 }
1047
1048 private:
1049 /**
1050 * clears the special value flags
1051 */
1052 void clear() {
1053 spval = SpVal.CLEAR;
1054 }
1055
1056 const int adjustedExponent() {
1057 return expo + digits - 1;
1058 }
1059
1060 const bool overflow() {
1061 return adjustedExponent > context.eMax;
1062 }
1063
1064 unittest{
1065 write("overflow.....");
1066 Decimal dec = Decimal(123, 99);
1067 assert(dec.overflow);
1068 dec = Decimal(12, 99);
1069 assert(dec.overflow);
1070 dec = Decimal(1, 99);
1071 assert(!dec.overflow);
1072 dec = Decimal(9, 99);
1073 assert(!dec.overflow);
1074 writeln("passed");
1075 }
1076
1077 } // end struct Decimal
1078
1079
1080 //--------------------------------
1081 // context functions
1082 //--------------------------------
1083
1084 // TODO: this is actually a property of the context.
1085
1086 /**
1087 * Returns radix of this representation (10).
1088 */
1089 public int radix() {
1090 return 10;
1091 }
1092
1093 unittest {
1094 write("radix........");
1095 assert(radix() == 10);
1096 writeln("passed");
1097 }
1098
1099 //--------------------------------
1100 // classification functions
1101 //--------------------------------
1102
1103 public string classify(const Decimal dcm) {
1104 if (dcm.isSignaling()) {
1105 return "sNaN";
1106 }
1107 if (dcm.isQuiet) {
1108 return "NaN";
1109 }
1110 if (dcm.isInfinite) {
1111 return dcm.sign ? "-Infinity" : "+Infinity";
1112 }
1113 if (dcm.isSubnormal) {
1114 return dcm.sign ? "-Subnormal" : "+Subnormal";
1115 }
1116 if (dcm.isZero) {
1117 return dcm.sign ? "-Zero" : "+Zero";
1118 }
1119 return dcm.sign ? "-Normal" : "+Normal";
1120 }
1121
1122 /**
1123 * Returns true if this number is canonical representation (always true).
1124 */
1125 public bool isCanonical(const Decimal dcm) {
1126 return dcm.isCanonical;
1127 }
1128
1129 /**
1130 * Returns true if this Decimal is a signaling NaN.
1131 */
1132 public bool isSignaling(const Decimal dcm) {
1133 return dcm.isSignaling;
1134 }
1135
1136 /**
1137 * Returns true if the specified Decimal is a quiet NaN.
1138 */
1139 public bool isQuiet(const Decimal dcm) {
1140 return dcm.isQuiet;
1141 }
1142
1143 public bool isFinite(const Decimal dcm) {
1144 return dcm.isFinite;
1145 }
1146
1147 public bool isInfinite(const Decimal dcm) {
1148 return dcm.isInfinite;
1149 }
1150
1151 public bool isNaN(const Decimal dcm) {
1152 return dcm.isNaN;
1153 }
1154
1155 public bool isNormal(const Decimal dcm) {
1156 return dcm.isNormal;
1157 }
1158
1159 public bool isSubnormal(const Decimal dcm) {
1160 return dcm.isSubnormal;
1161 }
1162
1163 public bool isZero(const Decimal dcm) {
1164 return dcm.isZero;
1165 }
1166
1167 public bool isSigned(const Decimal dcm) {
1168 return dcm.isSigned;
1169 }
1170
1171 unittest {
1172 write("classify.....");
1173 Decimal dcm;
1174 dcm = "Infinity";
1175 assert(classify(dcm) == "+Infinity");
1176 dcm = "1E-10";
1177 assert(classify(dcm) == "+Normal");
1178 dcm = "2.50";
1179 assert(classify(dcm) == "+Normal");
1180 dcm = "0.1E-99";
1181 assert(classify(dcm) == "+Subnormal");
1182 dcm = "0";
1183 assert(classify(dcm) == "+Zero");
1184 dcm = "-0";
1185 assert(classify(dcm) == "-Zero");
1186 dcm = "-0.1E-99";
1187 assert(classify(dcm) == "-Subnormal");
1188 dcm = "-1E-10";
1189 assert(classify(dcm) == "-Normal");
1190 dcm = "-2.50";
1191 assert(classify(dcm) == "-Normal");
1192 dcm = "-Infinity";
1193 assert(classify(dcm) == "-Infinity");
1194 dcm = "NaN";
1195 assert(classify(dcm) == "NaN");
1196 dcm = "-NaN";
1197 assert(classify(dcm) == "NaN");
1198 dcm = "sNaN";
1199 assert(classify(dcm) == "sNaN");
1200
1201 dcm = Decimal("2.50");
1202 assert(isCanonical(dcm));
1203
1204 dcm = Decimal("2.50");
1205 assert(isFinite(dcm));
1206 dcm = Decimal("-0.3");
1207 assert(isFinite(dcm));
1208 dcm = 0;
1209 assert(isFinite(dcm));
1210 dcm = Decimal("Inf");
1211 assert(!isFinite(dcm));
1212 dcm = Decimal("-Inf");
1213 assert(!isFinite(dcm));
1214 dcm = Decimal("NaN");
1215 assert(!isFinite(dcm));
1216
1217 dcm = Decimal("2.50");
1218 assert(!isInfinite(dcm));
1219 dcm = Decimal("-Inf");
1220 assert(isInfinite(dcm));
1221 dcm = Decimal("NaN");
1222 assert(!isInfinite(dcm));
1223
1224 dcm = Decimal("2.50");
1225 assert(!isNaN(dcm));
1226 dcm = Decimal("NaN");
1227 assert(isNaN(dcm));
1228 dcm = Decimal("-sNaN");
1229 assert(isNaN(dcm));
1230
1231 dcm = Decimal("2.50");
1232 assert(isNormal(dcm));
1233 dcm = Decimal("0.1E-99");
1234 assert(!isNormal(dcm));
1235 dcm = Decimal("0.00");
1236 assert(!isNormal(dcm));
1237 dcm = Decimal("-Inf");
1238 assert(!isNormal(dcm));
1239 dcm = Decimal("NaN");
1240 assert(!isNormal(dcm));
1241 writeln("passed");
1242
1243 dcm = Decimal("2.50");
1244 assert(!isQuiet(dcm));
1245 dcm = Decimal("NaN");
1246 assert(isQuiet(dcm));
1247 dcm = Decimal("sNaN");
1248 assert(!isQuiet(dcm));
1249
1250 dcm = Decimal("2.50");
1251 assert(!isSignaling(dcm));
1252 dcm = Decimal("NaN");
1253 assert(!isSignaling(dcm));
1254 dcm = Decimal("sNaN");
1255 assert(isSignaling(dcm));
1256
1257 dcm = Decimal("2.50");
1258 assert(!isSigned(dcm));
1259 dcm = Decimal("-12");
1260 assert(isSigned(dcm));
1261 dcm = Decimal("-0");
1262 assert(isSigned(dcm));
1263
1264 dcm = Decimal("2.50");
1265 assert(!isSubnormal(dcm));
1266 dcm = Decimal("0.1E-99");
1267 assert(isSubnormal(dcm));
1268 dcm = Decimal("0.00");
1269 assert(!isSubnormal(dcm));
1270 dcm = Decimal("-Inf");
1271 assert(!isSubnormal(dcm));
1272 dcm = Decimal("NaN");
1273 assert(!isSubnormal(dcm));
1274
1275 dcm = Decimal("0");
1276 assert(isZero(dcm));
1277 dcm = Decimal("2.50");
1278 assert(!isZero(dcm));
1279 dcm = Decimal("-0E+2");
1280 assert(isZero(dcm));
1281
1282 }
1283
1284 //--------------------------------
1285 // copy functions
1286 //--------------------------------
1287
1288 /**
1289 * Returns a copy of the operand.
1290 * The copy is unaffected by context; no flags are changed.
1291 */
1292 Decimal copy(const Decimal dcm) {
1293 Decimal cpy = dcm;
1294 return cpy;
1295 }
1296
1297 /**
1298 * Returns a copy of the operand with a positive sign.
1299 * The copy is unaffected by context; no flags are changed.
1300 */
1301 Decimal copyAbs(const Decimal dcm) {
1302 Decimal cpy = dcm;
1303 cpy.sign = false;
1304 return cpy;
1305 }
1306
1307 /**
1308 * Returns a copy of the operand with the sign inverted.
1309 * The copy is unaffected by context; no flags are changed.
1310 */
1311 Decimal copyNegate(const Decimal dcm) {
1312 Decimal cpy = dcm;
1313 cpy.sign = !dcm.sign;
1314 return cpy;
1315 }
1316
1317 /**
1318 * Returns a copy of the first operand with the sign of the second operand.
1319 * The copy is unaffected by context; no flags are changed.
1320 */
1321 Decimal copySign(const Decimal dcm1, const Decimal dcm2) {
1322 Decimal cpy = dcm1;
1323 cpy.sign = dcm2.sign;
1324 return cpy;
1325 }
1326
1327 // TODO: these should actually be compare-total assertions
1328 // This is probably true of other unit tests as well
1329 unittest {
1330 write("copy.........");
1331 Decimal dcm;
1332 Decimal expd;
1333 dcm = "2.1";
1334 expd = "2.1";
1335 assert(copy(dcm) == expd);
1336 dcm = "-1.00";
1337 expd = "-1.00";
1338 assert(copy(dcm) == expd);
1339 dcm = "2.1";
1340 expd = "2.1";
1341
1342 assert(copyAbs(dcm) == expd);
1343 dcm = "-1.00";
1344 expd = "1.00";
1345 assert(copyAbs(dcm) == expd);
1346 dcm = "101.5";
1347 expd = "-101.5";
1348
1349 assert(copyNegate(dcm) == expd);
1350 Decimal dcm1;
1351 Decimal dcm2;
1352 dcm1 = "1.50";
1353 dcm2 = "7.33";
1354 expd = "1.50";
1355
1356 assert(copySign(dcm1, dcm2) == expd);
1357 dcm1 = "-1.50";
1358 dcm2 = "7.33";
1359 expd = "1.50";
1360 assert(copySign(dcm1, dcm2) == expd);
1361 dcm1 = "1.50";
1362 dcm2 = "-7.33";
1363 expd = "-1.50";
1364 assert(copySign(dcm1, dcm2) == expd);
1365 dcm1 = "-1.50";
1366 dcm2 = "-7.33";
1367 expd = "-1.50";
1368 assert(copySign(dcm1, dcm2) == expd);
1369 writeln("passed");
1370 }
1371
1372 //--------------------------------
1373 // plus, minus and abs functions
1374 //--------------------------------
1375
1376 /**
1377 * unary minus -- returns a copy with the opposite sign.
1378 * This operation may set flags -- equivalent to
1379 * subtract('0', b);
1380 */
1381 Decimal minus(const Decimal dcm) {
1382 Decimal result;
1383 if(isInvalidOperation(dcm, result)) {
1384 return result;
1385 }
1386 result = copyNegate(dcm);
1387 round(result);
1388 return result;
1389 }
1390
1391 /**
1392 * unary plus -- returns a copy.
1393 * This operation may set flags -- equivalent to
1394 * add('0', a);
1395 */
1396 Decimal plus(const Decimal dcm) {
1397 Decimal result;
1398 if(isInvalidOperation(dcm, result)) {
1399 return result;
1400 }
1401 result = dcm;
1402 round(result);
1403 return result;
1404 }
1405
1406 unittest {
1407 write("minus/plus...");
1408 // NOTE: result should equal 0+this or 0-this
1409 Decimal zero = Decimal(0);
1410 Decimal dcm;
1411 Decimal expd;
1412 dcm = "1.3";
1413 expd = zero + dcm;
1414 assert(+dcm == expd);
1415 dcm = "-1.3";
1416 expd = zero + dcm;
1417 assert(+dcm == expd);
1418 dcm = "1.3";
1419 expd = zero - dcm;
1420 assert(-dcm == expd);
1421 dcm = "-1.3";
1422 expd = zero - dcm;
1423 assert(-dcm == expd);
1424 // TODO: add tests that check flags.
1425 writeln("passed");
1426 }
1427
1428 /// Returns a new Decimal equal to the absolute value of this Decimal.
1429 public Decimal abs(const Decimal dcm) {
1430 Decimal result;
1431 if(isInvalidOperation(dcm, result)) {
1432 return result;
1433 }
1434 result = copyAbs(dcm);
1435 round(result);
1436 return result;
1437 }
1438
1439 unittest {
1440 // TODO: add rounding tests
1441 write("abs..........");
1442 Decimal dcm;
1443 Decimal expd;
1444 dcm = "sNaN";
1445 assert(abs(dcm).isQuiet);
1446 assert(context.flags && INVALID_OPERATION);
1447 dcm = "NaN";
1448 assert(abs(dcm).isQuiet);
1449 assert(context.flags && INVALID_OPERATION);
1450 dcm = "Inf";
1451 expd = "Inf";
1452 assert(abs(dcm) == expd);
1453 dcm = "-Inf";
1454 expd = "Inf";
1455 assert(abs(dcm) == expd);
1456 dcm = "0";
1457 expd = "0";
1458 assert(abs(dcm) == expd);
1459 dcm = "-0";
1460 expd = "0";
1461 assert(abs(dcm) == expd);
1462 dcm = "2.1";
1463 expd = "2.1";
1464 assert(abs(dcm) == expd);
1465 dcm = -100;
1466 expd = 100;
1467 assert(abs(dcm) == expd);
1468 dcm = 101.5;
1469 expd = 101.5;
1470 assert(abs(dcm) == expd);
1471 dcm = -101.5;
1472 assert(abs(dcm) == expd);
1473 writeln("passed");
1474 }
1475
1476 public Decimal nextPlus(const Decimal dcm) {
1477 Decimal result;
1478 if (isInvalidOperation(dcm, result)) {
1479 return result;
1480 }
1481 if (dcm.isInfinite && dcm.sign) return -context.max();
1482 int adjx = dcm.expo + dcm.digits - context.precision;
1483 if (adjx < context.eTiny) {
1484 return Decimal(true, 0, context.eTiny);
1485 }
1486 Decimal addend = Decimal(1, adjx);
1487 result = dcm + addend;
1488 if (result > context.max) {
1489 result = POS_INF;
1490 }
1491 return result;
1492 }
1493
1494 unittest {
1495 write("next-plus....");
1496 pushContext();
1497 context.eMax = 999;
1498 context.eMin = -999;
1499 Decimal dcm;
1500 Decimal expd;
1501 dcm = 1;
1502 expd = "1.00000001";
1503 assert(nextPlus(dcm) == expd);
1504 dcm = 10;
1505 expd = "10.0000001";
1506 assert(nextPlus(dcm) == expd);
1507 dcm = 1E5;
1508 expd = "100000.001";
1509 assert(nextPlus(dcm) == expd);
1510 dcm = 1E8;
1511 expd = "100000001";
1512 assert(nextPlus(dcm) == expd);
1513 // num digits exceeds precision...
1514 dcm = "1234567891";
1515 expd = "1.23456790E9";
1516 assert(nextPlus(dcm) == expd);
1517 // result < tiny
1518 dcm = "-1E-1007";
1519 expd = "-0E-1007";
1520 assert(nextPlus(dcm) == expd);
1521 dcm = "-1.00000003";
1522 expd = "-1.00000002";
1523 assert(nextPlus(dcm) == expd);
1524 dcm = "-Infinity";
1525 expd = "-9.99999999E+999";
1526 assert(nextPlus(dcm) == expd);
1527 popContext();
1528 writeln("passed");
1529 }
1530
1531 public Decimal nextMinus(const Decimal dcm) {
1532 Decimal result;
1533 if (isInvalidOperation(dcm, result)) {
1534 return result;
1535 }
1536 if (dcm.isInfinite && !dcm.sign) return context.max();
1537 // This is necessary to catch the special case where ceff == 1
1538 Decimal red = reduce(dcm);
1539 int adjx = red.expo + red.digits - context.precision;
1540 if (dcm.ceff == 1) adjx--;
1541 if (adjx < context.eTiny) {
1542 return Decimal(false, 0, context.eTiny);
1543 }
1544 Decimal addend = Decimal(1, adjx);
1545 result = dcm - addend;
1546 if (result < -context.max) {
1547 result = NEG_INF;
1548 }
1549 return result;
1550 }
1551
1552 unittest {
1553 write("next-minus...");
1554 pushContext();
1555 context.eMax = 999;
1556 context.eMin = -999;
1557 Decimal dcm;
1558 Decimal expd;
1559 dcm = 1;
1560 expd = "0.999999999";
1561 assert(nextMinus(dcm) == expd);
1562 dcm = "1E-1007";
1563 expd = "0E-1007";
1564 assert(nextMinus(dcm) == expd);
1565 dcm = "-1.00000003";
1566 expd = "-1.00000004";
1567 assert(nextMinus(dcm) == expd);
1568 dcm = "Infinity";
1569 expd = "9.99999999E+999";
1570 assert(nextMinus(dcm) == expd);
1571 popContext();
1572 writeln("passed");
1573 }
1574
1575 public Decimal nextToward(const Decimal dcm1, const Decimal dcm2) {
1576 Decimal result;
1577 if (isInvalidOperation(dcm1, dcm2, result)) {
1578 return result;
1579 }
1580 int comp = icompare(dcm1, dcm2);
1581 if (comp < 0) return nextPlus(dcm1);
1582 if (comp > 0) return nextMinus(dcm1);
1583 result = copySign(dcm1, dcm2);
1584 round(result);
1585 return result;
1586 }
1587
1588 unittest {
1589 write("next-toward..");
1590 DecimalContext save = context;
1591 Decimal dcm1, dcm2;
1592 Decimal expd;
1593 dcm1 = 1;
1594 dcm2 = 2;
1595 expd = "1.00000001";
1596 assert(nextToward(dcm1,dcm2) == expd);
1597 dcm1 = "-1E-1007";
1598 dcm2 = 1;
1599 expd = "-0E-1007";
1600 assert(nextToward(dcm1,dcm2) == expd);
1601 dcm1 = "-1.00000003";
1602 dcm2 = 0;
1603 expd = "-1.00000002";
1604 assert(nextToward(dcm1,dcm2) == expd);
1605 dcm1 = 1;
1606 dcm2 = 0;
1607 expd = "0.999999999";
1608 assert(nextToward(dcm1,dcm2) == expd);
1609 dcm1 = "1E-1007";
1610 dcm2 = -100;
1611 expd = "0E-1007";
1612 assert(nextToward(dcm1,dcm2) == expd);
1613 dcm1 = "-1.00000003";
1614 dcm2 = -10;
1615 expd = "-1.00000004";
1616 assert(nextToward(dcm1,dcm2) == expd);
1617 dcm1 = "0.00";
1618 dcm2 = "-0.0000";
1619 expd = "-0.00";
1620 assert(nextToward(dcm1,dcm2) == expd);
1621 context = save;
1622 writeln("passed");
1623 }
1624
1625 //--------------------------------
1626 // comparison functions
1627 //--------------------------------
1628
1629 /// returns true if the numbers have the same exponent.
1630 public bool sameQuantum(const Decimal x, const Decimal y) {
1631 if (x.isNaN || y.isNaN) {
1632 return x.isNaN && y.isNaN;
1633 }
1634 if (x.isInfinite || y.isInfinite) {
1635 return x.isInfinite && y.isInfinite;
1636 }
1637 return x.expo == y.expo;
1638 }
1639
1640 unittest {
1641 write("same-quantum.");
1642 Decimal op1;
1643 Decimal op2;
1644 op1 = "2.17";
1645 op2 = "0.001";
1646 assert(!sameQuantum(op1, op2));
1647 op2 = "0.01";
1648 assert(sameQuantum(op1, op2));
1649 op2 = "0.1";
1650 assert(!sameQuantum(op1, op2));
1651 op2 = "1";
1652 assert(!sameQuantum(op1, op2));
1653 op1 = "Inf";
1654 op2 = "Inf";
1655 assert(sameQuantum(op1, op2));
1656 op1 = "NaN";
1657 op2 = "NaN";
1658 assert(sameQuantum(op1, op2));
1659 writeln("passed");
1660 }
1661
1662 public Decimal compare(const Decimal dcm1, const Decimal dcm2,
1663 const bool signal = false) {
1664 // sNaN is an invalid operand
1665 if (dcm1.isSignaling && dcm2.isSignaling) {
1666 return invalidOp();
1667 }
1668 // qNaN is invalid if signal flag is set.
1669 if (signal && (dcm1.isNaN || dcm2.isNaN)) {
1670 return invalidOp();
1671 }
1672 // NaN returns > any number, including NaN
1673 if (dcm1.isNaN) return ONE;
1674 if (dcm2.isNaN) return -ONE;
1675
1676 if (dcm1.sign != dcm2.sign) {
1677 Decimal op1 = dcm1.sign ? -ONE : ONE;
1678 Decimal op2 = -op1;
1679 op1 = dcm1.isZero ? ZERO : op1;
1680 op2 = dcm2.isZero ? ZERO : op2;
1681 return op1 != op2 ? op1 : ZERO;
1682 }
1683 int diff = (dcm1.expo + dcm1.digits) - (dcm2.expo + dcm2.digits);
1684 if (!dcm1.sign) {
1685 if (diff > 0) return ONE;
1686 if (diff < 0) return -ONE;
1687 }
1688 else {
1689 if (diff > 0) return -ONE;
1690 if (diff < 0) return ONE;
1691 }
1692 Decimal result = dcm1 - dcm2;
1693 if (result.isZero) return ZERO;
1694 return result.sign ? -ONE : ONE;
1695 }
1696
1697 public int icompare(const Decimal dcm1, const Decimal dcm2) {
1698 // sNaN is invalid operand
1699 // NaN returns > any number, including NaN
1700 if (dcm1.isSignaling) {
1701 invalidOp();
1702 return 1;
1703 }
1704 if (dcm2.isSignaling) {
1705 invalidOp();
1706 return -1;
1707 }
1708 // NaN returns > any number, including NaN
1709 if (dcm1.isNaN) return 1;
1710 if (dcm2.isNaN) return -1;
1711
1712 if (dcm1.sign != dcm2.sign) {
1713 int op1 = dcm1.sign ? -1 : 1;
1714 int op2 = -op1;
1715 op1 = dcm1.isZero ? 0 : op1;
1716 op2 = dcm2.isZero ? 0 : op2;
1717 return op1 != op2 ? op1 : 0;
1718 }
1719 int diff = (dcm1.expo + dcm1.digits) - (dcm2.expo + dcm2.digits);
1720 if (!dcm1.sign) {
1721 if (diff > 0) return 1;
1722 if (diff < 0) return -1;
1723 }
1724 else {
1725 if (diff > 0) return -1;
1726 if (diff < 0) return 1;
1727 }
1728 Decimal result = dcm1 - dcm2;
1729 if (result.isZero) return 0;
1730 return result.sign ? -1 : 1;
1731 }
1732
1733 unittest {
1734 write("compare......");
1735 Decimal op1;
1736 Decimal op2;
1737 int result;
1738 op1 = "2.1";
1739 op2 = "3";
1740 result = icompare(op1, op2);
1741 assert(result == -1);
1742 op1 = "2.1";
1743 op2 = "2.1";
1744 result = icompare(op1, op2);
1745 assert(result == 0);
1746 op1 = "2.1";
1747 op2 = "2.10";
1748 result = icompare(op1, op2);
1749 assert(result == 0);
1750 op1 = "3";
1751 op2 = "2.1";
1752 result = icompare(op1, op2);
1753 assert(result == 1);
1754 op1 = "2.1";
1755 op2 = "-3";
1756 result = icompare(op1, op2);
1757 assert(result == 1);
1758 op1 = "-3";
1759 op2 = "2.1";
1760 result = icompare(op1, op2);
1761 assert(result == -1);
1762 op1 = -3;
1763 op2 = -4;
1764 result = icompare(op1, op2);
1765 assert(result == 1);
1766 op1 = -300;
1767 op2 = -4;
1768 result = icompare(op1, op2);
1769 assert(result == -1);
1770 op1 = 3;
1771 op2 = context.max;
1772 result = icompare(op1, op2);
1773 assert(result == -1);
1774 op1 = -3;
1775 op2 = -context.max;
1776 result = icompare(op1, op2);
1777 assert(result == 1);
1778
1779 writeln("passed");
1780 }
1781
1782 /// Returns 0 if the numbers are equal and have the same representation
1783 public int compareTotal(const Decimal x, const Decimal y) {
1784 if (x.sign != y.sign) {
1785 return x.sign ? -1 : 1;
1786 }
1787 if (x.isQuiet || y.isQuiet) {
1788 if (x.isQuiet && y.isQuiet) {
1789 return 0;
1790 }
1791 return x.isQuiet ? 1 : -1;
1792 }
1793 if (x.isSignaling || y.isSignaling) {
1794 return 0;
1795 }
1796 if (x.isInfinite || y.isInfinite) {
1797 return 0;
1798 }
1799 int diff = (x.expo + x.digits) - (y.expo + y.digits);
1800 if (diff > 0) return 1;
1801 if (diff < 0) return -1;
1802 Decimal result = x - y;
1803 if (result.isZero) {
1804 if (x.expo > y.expo) return 1;
1805 if (x.expo < y.expo) return -1;
1806 return 0;
1807 }
1808 return result.sign ? -1 : 1;
1809 }
1810
1811 unittest {
1812 write("comp-total...");
1813 Decimal op1;
1814 Decimal op2;
1815 int result;
1816 op1 = "12.73";
1817 op2 = "127.9";
1818 result = compareTotal(op1, op2);
1819 assert(result == -1);
1820 op1 = "-127";
1821 op2 = "12";
1822 result = compareTotal(op1, op2);
1823 assert(result == -1);
1824 op1 = "12.30";
1825 op2 = "12.3";
1826 result = compareTotal(op1, op2);
1827 assert(result == -1);
1828 op1 = "12.30";
1829 op2 = "12.30";
1830 result = compareTotal(op1, op2);
1831 assert(result == 0);
1832 op1 = "12.3";
1833 op2 = "12.300";
1834 result = compareTotal(op1, op2);
1835 assert(result == 1);
1836 op1 = "12.3";
1837 op2 = "NaN";
1838 result = compareTotal(op1, op2);
1839 assert(result == -1);
1840 writeln("passed");
1841 }
1842
1843 int compareTotalMagnitude(const Decimal x, const Decimal y) {
1844 return compareTotal(copyAbs(x), copyAbs(y));
1845 }
1846
1847 // TODO: this is where the need for flags comes in.
1848 /**
1849 * Returns the maximum of the two operands (or NaN).
1850 * If either is an sNaN, or both are quiet NaNs, a NaN is returned.
1851 * Otherwise, Any (finite or infinite) number is larger than a NaN.
1852 * If they are not numerically equal, the larger is returned.
1853 * If they are numerically equal:
1854 * 1) If the signs differ, the one with the positive sign is returned.
1855 * 2) If they are positive, the one with the larger exponent is returned.
1856 * 3) If they are negative, the one with the smaller exponent is returned.
1857 * 4) Otherwise, they are indistinguishable; the first is returned.
1858 */
1859 Decimal max(const Decimal op1, const Decimal op2) {
1860 // if both are NaNs or either is an sNan, return NaN.
1861 if (op1.isNaN && op2.isNaN || op1.isSignaling || op2.isSignaling) {
1862 return NaN;
1863 }
1864 // if one op is a quiet NaN return the other
1865 if (op1.isQuiet || op2.isQuiet) {
1866 return (op1.isQuiet) ? op2 : op1;
1867 }
1868 // if the signs differ, return the unsigned operand
1869 if (op1.sign != op2.sign) {
1870 return op1.sign ? op2 : op1;
1871 }
1872 // if not numerically equal, return the larger
1873 int comp = icompare(op1, op2);
1874 if (comp != 0) {
1875 return comp > 0 ? op1 : op2;
1876 }
1877 // if they have the same exponent they are identical, return either
1878 if (op1.expo == op2.expo) {
1879 return op1;
1880 }
1881 // if they are non-negative, return the one with larger exponent.
1882 if (op1.sign == 0) {
1883 return op1.expo > op2.expo ? op1 : op2;
1884 }
1885 // else they are negative; return the one with smaller exponent.
1886 return op1.expo > op2.expo ? op2 : op1;
1887 }
1888
1889 unittest {
1890 write("max..........");
1891 Decimal op1;
1892 Decimal op2;
1893 op1 = 3;
1894 op2 = 2;
1895 assert(max(op1, op2) == op1);
1896 op1 = -10;
1897 op2 = 3;
1898 assert(max(op1, op2) == op2);
1899 op1 = "1.0";
1900 op2 = "1";
1901 assert(max(op1, op2) == op2);
1902 op1 = "7";
1903 op2 = "NaN";
1904 assert(max(op1, op2) == op1);
1905 writeln("passed");
1906 }
1907
1908 /**
1909 * Returns the minimum of the two operands (or NaN).
1910 * If either is an sNaN, or both are quiet NaNs, a NaN is returned.
1911 * Otherwise, Any (finite or infinite) number is smaller than a NaN.
1912 * If they are not numerically equal, the smaller is returned.
1913 * If they are numerically equal:
1914 * 1) If the signs differ, the one with the negative sign is returned.
1915 * 2) If they are negative, the one with the larger exponent is returned.
1916 * 3) If they are positive, the one with the smaller exponent is returned.
1917 * 4) Otherwise, they are indistinguishable; the first is returned.
1918 */
1919 Decimal min(const Decimal op1, const Decimal op2) {
1920 // if both are NaNs or either is an sNan, return NaN.
1921 if (op1.isNaN && op2.isNaN || op1.isSignaling || op2.isSignaling) {
1922 /+ Decimal result;
1923 result.flags = INVALID_OPERATION;+/
1924 return NaN;
1925 }
1926 // if one op is a quiet NaN return the other
1927 if (op1.isQuiet || op2.isQuiet) {
1928 return (op1.isQuiet) ? op2 : op1;
1929 }
1930 // if the signs differ, return the unsigned operand
1931 if (op1.sign != op2.sign) {
1932 return op1.sign ? op1 : op2;
1933 }
1934 // if not numerically equal, return the smaller
1935 int comp = icompare(op1, op2);
1936 if (comp != 0) {
1937 return comp < 0 ? op1 : op2;
1938 }
1939 // if they have the same exponent they are identical, return either
1940 if (op1.expo == op2.expo) {
1941 return op1;
1942 }
1943 // if they are non-negative, return the one with smaller exponent.
1944 if (op1.sign == 0) {
1945 return op1.expo < op2.expo ? op1 : op2;
1946 }
1947 // else they are negative; return the one with larger exponent.
1948 return op1.expo < op2.expo ? op2 : op1;
1949 }
1950
1951 unittest {
1952 write("min..........");
1953 Decimal op1;
1954 Decimal op2;
1955 op1 = 3;
1956 op2 = 2;
1957 assert(min(op1, op2) == op2);
1958 op1 = -10;
1959 op2 = 3;
1960 assert(min(op1, op2) == op1);
1961 op1 = "1.0";
1962 op2 = "1";
1963 assert(min(op1, op2) == op1);
1964 op1 = "7";
1965 op2 = "NaN";
1966 assert(min(op1, op2) == op1);
1967 writeln("passed");
1968 }
1969
1970 //------------------------------------------
1971 //
1972 // Binary Arithmetic Operations
1973 //
1974 //------------------------------------------
1975
1976 /**
1977 * Adds two Decimal numbers.
1978 *
1979 * This function corresponds to the "add and subtract" function
1980 * in the General Decimal Arithmetic Specification and is the basis
1981 * for the opAdd and opSub functions for the Decimal struct.
1982 */
1983 Decimal add(const Decimal augend, const Decimal addend) {
1984
1985 Decimal sum;
1986 // check for NaN operand(s)
1987 if (isInvalidOperation(augend, addend, sum)) {
1988 return sum;
1989 }
1990 // if both operands are infinite
1991 if (augend.isInfinite && addend.isInfinite) {
1992 // (+inf) + (-inf) => invalid operation
1993 if (augend.sign != addend.sign) {
1994 return invalidOp();
1995 }
1996 // both infinite with same sign
1997 return augend;
1998 }
1999
2000 /+ if (isInvalidAddition(augend, addend, sum)) {
2001 return sum;
2002 }+/
2003 // TODO: is it okay to return the operand? is a copy implied?
2004 // only augend is infinite,
2005 if (augend.isInfinite) {
2006 return augend;
2007 }
2008 // only addend is infinite
2009 if (addend.isInfinite) {
2010 return addend;
2011 }
2012
2013 // align the operands
2014 alignOps(augend, addend);
2015
2016 // add(0, 0)
2017 if (augend.isZero && addend.isZero) {
2018 sum = augend;
2019 sum.sign = augend.sign && addend.sign;
2020 return sum;
2021 }
2022
2023 // at this point, the result will be finite and not zero
2024 // (before rounding)
2025 sum.clear();
2026
2027 // if operands have the same sign...
2028 if (augend.sign == addend.sign) {
2029 sum.ceff = augend.ceff + addend.ceff;
2030 sum.sign = augend.sign;
2031 }
2032 // ...else operands have different signs
2033 else {
2034 sum.ceff = augend.ceff - addend.ceff;
2035 sum.sign = augend.sign;
2036 if (sum.ceff < BIG_ZERO) {
2037 sum.ceff = -sum.ceff;
2038 sum.sign = !sum.sign;
2039 }
2040 }
2041 // set the number of digits and the exponent
2042 sum.digits = numDigits(sum.ceff, augend.digits);
2043 sum.expo = augend.expo;
2044
2045 // round the result
2046 round(sum);
2047 return sum;
2048 } // end add(augend, addend)
2049
2050 /**
2051 * Subtracts two Decimal numbers.
2052 *
2053 * This function corresponds to the "add and subtract" function
2054 * in the General Decimal Arithmetic Specification and is the basis
2055 * for the opAdd and opSub functions for the Decimal struct.
2056 */
2057 Decimal subtract(const Decimal minuend, const Decimal subtrahend) {
2058 return add(minuend, copyNegate(subtrahend));
2059 } // end subtract(minuend, subtrahend)
2060
2061 // TODO: these tests need to be cleaned up to rely less on strings
2062 // and to check the NaN, Inf combinations better.
2063 unittest {
2064 write("add..........");
2065 Decimal dcm1 = Decimal("12");
2066 Decimal dcm2 = Decimal("7.00");
2067 Decimal sum = add(dcm1, dcm2);
2068 assert(sum.toString() == "19.00");
2069 dcm1 = Decimal("1E+2");
2070 dcm2 = Decimal("1E+4");
2071 sum = add(dcm1, dcm2);
2072 assert(sum.toString() == "1.01E+4");
2073 dcm1 = Decimal("1.3");
2074 dcm2 = Decimal("1.07");
2075 sum = subtract(dcm1, dcm2);
2076 assert(sum.toString() == "0.23");
2077 dcm2 = Decimal("1.30");
2078 sum = subtract(dcm1, dcm2);
2079 assert(sum.toString() == "0.00");
2080 dcm2 = Decimal("2.07");
2081 sum = subtract(dcm1, dcm2);
2082 assert(sum.toString() == "-0.77");
2083 dcm1 = "Inf";
2084 dcm2 = 1;
2085 sum = add(dcm1, dcm2);
2086 assert(sum.toString() == "Infinity");
2087 dcm1 = "NaN";
2088 dcm2 = 1;
2089 sum = add(dcm1, dcm2);
2090 assert(sum.isQuiet);
2091 dcm2 = "Infinity";
2092 sum = add(dcm1, dcm2);
2093 assert(sum.isQuiet);
2094 dcm1 = 1;
2095 sum = subtract(dcm1, dcm2);
2096 assert(sum.toString() == "-Infinity");
2097 dcm1 = "-0";
2098 dcm2 = 0;
2099 sum = subtract(dcm1, dcm2);
2100 assert(sum.toString() == "-0");
2101 writeln("passed");
2102 }
2103
2104 Decimal multiply(const Decimal multiplier, const Decimal multiplicand) {
2105
2106 Decimal product;
2107 if (isInvalidMultiplication(multiplier, multiplicand, product)) {
2108 return product;
2109 }
2110 if (multiplier.isInfinite || multiplicand.isInfinite) {
2111 product = Decimal.infinity;
2112 product.sign = multiplier.sign ^ multiplicand.sign;
2113 return product;
2114 }
2115 product.clear();
2116 product.ceff = multiplier.ceff * multiplicand.ceff;
2117 product.expo = multiplier.expo + multiplicand.expo;
2118 product.sign = multiplier.sign ^ multiplicand.sign;
2119 product.digits = numDigits(product.ceff, multiplier.digits + multiplicand.digits);
2120 round(product);
2121 return product;
2122 }
2123
2124 unittest {
2125 write("multiply.....");
2126 Decimal op1, op2, result;
2127 op1 = Decimal("1.20");
2128 op2 = 3;
2129 result = op1 * op2;
2130 assert(result.toString() == "3.60");
2131 op1 = 7;
2132 result = op1 * op2;
2133 assert(result.toString() == "21");
2134 op1 = Decimal("0.9");
2135 op2 = Decimal("0.8");
2136 result = op1 * op2;
2137 assert(result.toString() == "0.72");
2138 op1 = Decimal("0.9");
2139 op2 = Decimal("-0.0");
2140 result = op1 * op2;
2141 assert(result.toString() == "-0.00");
2142 op1 = Decimal(654321);
2143 op2 = Decimal(654321);
2144 result = op1 * op2;
2145 assert(result.toString() == "4.28135971E+11");
2146 op1 = -1;
2147 op2 = "Infinity";
2148 result = op1 * op2;
2149 assert(result.toString() == "-Infinity");
2150 op1 = -1;
2151 op2 = 0;
2152 result = op1 * op2;
2153 assert(result.toString() == "-0");
2154 writeln("passed");
2155 }
2156
2157 Decimal fma(const Decimal multiplier, const Decimal multiplicand,
2158 const Decimal addend) {
2159 Decimal product;
2160 if (isInvalidMultiplication(multiplier, multiplicand, product)) {
2161 return product;
2162 }
2163 product.clear();
2164 product.ceff = multiplier.ceff * multiplicand.ceff;
2165 product.expo = multiplier.expo + multiplicand.expo;
2166 product.sign = multiplier.sign ^ multiplicand.sign;
2167 product.digits = numDigits(product.ceff, multiplier.digits + multiplicand.digits);
2168 return add(product, addend);
2169 }
2170
2171 unittest {
2172 write("fma..........");
2173 Decimal op1;
2174 Decimal op2;
2175 Decimal op3;
2176 Decimal result;
2177 op1 = 3;
2178 op2 = 5;
2179 op3 = 7;
2180 result = (fma(op1, op2, op3));
2181 assert(result == Decimal(22));
2182 op1 = 3;
2183 op2 = -5;
2184 op3 = 7;
2185 result = (fma(op1, op2, op3));
2186 assert(result == Decimal(-8));
2187 op1 = "888565290";
2188 op2 = "1557.96930";
2189 op3 = "-86087.7578";
2190 result = (fma(op1, op2, op3));
2191 assert(result == Decimal("1.38435736E+12"));
2192 writeln("passed");
2193 }
2194
2195 bool isZeroDividend(const Decimal dividend, const Decimal divisor,
2196 Decimal quotient) {
2197 if (dividend.isZero()) {
2198 quotient.spval = SpVal.ZERO;
2199 quotient.ceff = BIG_ZERO;
2200 quotient.expo = 0;
2201 quotient.digits = dividend.digits;
2202 quotient.sign = dividend.sign;
2203 return true;
2204 }
2205 return false;
2206 }
2207
2208 Decimal divide(const Decimal dividend, const Decimal divisor) {
2209
2210 Decimal quotient;
2211 if (isInvalidDivision(dividend, divisor, quotient)) {
2212 return quotient;
2213 }
2214 if (isZeroDividend(dividend, divisor, quotient)) {
2215 return quotient;
2216 }
2217 quotient.clear();
2218
2219 Decimal temp = dividend;
2220 int adjust = 0;
2221 while (temp.ceff < divisor.ceff) {
2222 temp.ceff *= 10;
2223 adjust++;
2224 }
2225 bool complete = false;
2226 while (!complete) {
2227 // repeated subtraction
2228 while (divisor.ceff <= temp.ceff) {
2229 temp.ceff -= divisor.ceff;
2230 quotient.ceff++;
2231 }
2232 // check for done
2233 if (temp.ceff == 0 && adjust >= 0
2234 || numDigits(quotient.ceff, 1) == context.precision + 2) {
2235 complete = true;
2236 }
2237 else {
2238 // bump the quotient and temp by 10
2239 quotient.ceff *= 10;
2240 temp.ceff *= 10;
2241 adjust++;
2242 }
2243 quotient.digits = numDigits(quotient.ceff, context.precision);
2244 }
2245 quotient.expo = temp.expo - divisor.expo - adjust;
2246 quotient.sign = temp.sign ^ divisor.sign;
2247 round(quotient);
2248 return quotient;
2249 }
2250
2251 Decimal edivide(const Decimal dividend, const Decimal divisor) {
2252 Decimal quotient;
2253 if (isInvalidDivision(dividend, divisor, quotient)) {
2254 return quotient;
2255 }
2256 if (isZeroDividend(dividend, divisor, quotient)) {
2257 return quotient;
2258 }
2259 quotient.clear();
2260 Decimal denom = dividend;
2261 Decimal numer = divisor;
2262 // align operands
2263 int diff = denom.expo - numer.expo;
2264 if (diff < 0) {
2265 numer.ceff *= pow10(-diff);
2266 }
2267 if (diff > 0) {
2268 numer.ceff *= pow10(diff);
2269 }
2270 numer.digits = numDigits(numer.ceff, 1);
2271 denom.digits = numDigits(denom.ceff, 1);
2272 int shift = 2 + context.precision - denom.digits + numer.digits;
2273 if (shift > 0) {
2274 denom.ceff *= pow10(shift);
2275 denom.expo -= shift;
2276 }
2277 quotient.ceff = denom.ceff / numer.ceff;
2278 quotient.expo = denom.expo - numer.expo;
2279 quotient.sign = denom.sign ^ numer.sign;
2280 quotient.digits = numDigits(quotient.ceff, context.precision);
2281 round(quotient);
2282 return quotient;
2283 }
2284
2285 unittest {
2286 write("divide.......");
2287 Decimal dcm1, dcm2;
2288 Decimal expd;
2289 dcm1 = 1;
2290 dcm2 = 3;
2291 Decimal quotient = edivide(dcm1, dcm2);
2292 expd = "0.333333333";
2293 assert(quotient == expd);
2294 assert(quotient.toString() == expd.toString());
2295 dcm1 = 2;
2296 dcm2 = 3;
2297 quotient = edivide(dcm1, dcm2);
2298 expd = "0.666666667";
2299 assert(quotient == expd);
2300 dcm1 = 5;
2301 dcm2 = 2;
2302 quotient = divide(dcm1, dcm2);
2303 expd = "2.5";
2304 assert(quotient == expd);
2305 assert(quotient.toString() == expd.toString());
2306 dcm1 = 1;
2307 dcm2 = 10;
2308 expd = 0.1;
2309 quotient = divide(dcm1, dcm2);
2310 assert(quotient == expd);
2311 assert(quotient.toString() == expd.toString());
2312 dcm1 = "8.00";
2313 dcm2 = 2;
2314 expd = "4.00";
2315 quotient = divide(dcm1, dcm2);
2316 assert(quotient == expd);
2317 assert(quotient.toString() == expd.toString());
2318 dcm1 = "2.400";
2319 dcm2 = "2.0";
2320 expd = "1.20";
2321 quotient = divide(dcm1, dcm2);
2322 assert(quotient == expd);
2323 assert(quotient.toString() == expd.toString());
2324 dcm1 = 1000;
2325 dcm2 = 100;
2326 expd = 10;
2327 quotient = divide(dcm1, dcm2);
2328 assert(quotient == expd);
2329 assert(quotient.toString() == expd.toString());
2330 dcm2 = 1;
2331 quotient = divide(dcm1, dcm2);
2332 expd = 1000;
2333 assert(quotient == expd);
2334 assert(quotient.toString() == expd.toString());
2335 dcm1 = "2.40E+6";
2336 dcm2 = 2;
2337 expd = "1.20E+6";
2338 quotient = divide(dcm1, dcm2);
2339 assert(quotient == expd);
2340 assert(quotient.toString() == expd.toString());
2341 writeln("passed");
2342 }
2343
2344 Decimal divideInteger(const Decimal dividend, const Decimal divisor) {
2345 Decimal quotient;
2346 if (isInvalidDivision(dividend, divisor, quotient)) {
2347 return quotient;
2348 }
2349 if (isZeroDividend(dividend, divisor, quotient)) {
2350 return quotient;
2351 }
2352 quotient.clear();
2353 Decimal denom = dividend;
2354 Decimal numer = divisor;
2355 // align operands
2356 int diff = denom.expo - numer.expo;
2357 if (diff < 0) {
2358 numer.ceff *= pow10(-diff);
2359 }
2360 if (diff > 0) {
2361 denom.ceff *= pow10(diff);
2362 }
2363 quotient.ceff = denom.ceff / numer.ceff;
2364 quotient.expo = 0;
2365 quotient.sign = denom.sign ^ numer.sign;
2366 quotient.digits = numDigits(quotient.ceff, context.precision);
2367 if (quotient.ceff == 0) quotient.spval = SpVal.ZERO;
2368 return quotient;
2369 }
2370
2371 unittest {
2372 write("div-int......");
2373 Decimal dividend;
2374 Decimal divisor;
2375 Decimal quotient;
2376 Decimal expd;
2377 dividend = 2;
2378 divisor = 3;
2379 quotient = divideInteger(dividend, divisor);
2380 expd = 0;
2381 assert(quotient == expd);
2382 dividend = 10;
2383 quotient = divideInteger(dividend, divisor);
2384 expd = 3;
2385 assert(quotient == expd);
2386 dividend = 1;
2387 divisor = "0.3";
2388 quotient = divideInteger(dividend, divisor);
2389 assert(quotient == expd);
2390 writeln("passed");
2391 }
2392
2393 Decimal remainder(const Decimal dividend, const Decimal divisor) {
2394 Decimal quotient;
2395 if (isInvalidDivision(dividend, divisor, quotient)) {
2396 return quotient;
2397 }
2398 if (isZeroDividend(dividend, divisor, quotient)) {
2399 return quotient;
2400 }
2401 quotient = dividend - divisor * divideInteger(dividend, divisor);
2402 return quotient;
2403 }
2404
2405 unittest {
2406 write("remainder....");
2407 Decimal dividend;
2408 Decimal divisor;
2409 Decimal quotient;
2410 Decimal expected;
2411 dividend = "2.1";
2412 divisor = 3;
2413 quotient = remainder(dividend, divisor);
2414 expected = "2.1";
2415 assert(quotient == expected);
2416 dividend = 10;
2417 quotient = remainder(dividend, divisor);
2418 expected = 1;
2419 assert(quotient == expected);
2420 dividend = -10;
2421 quotient = remainder(dividend, divisor);
2422 expected = -1;
2423 assert(quotient == expected);
2424 dividend = 10.2;
2425 divisor = 1;
2426 quotient = remainder(dividend, divisor);
2427 expected = "0.2";
2428 assert(quotient == expected);
2429 dividend = 10;
2430 divisor = 0.3;
2431 quotient = remainder(dividend, divisor);
2432 expected = "0.1";
2433 assert(quotient == expected);
2434 dividend = 3.6;
2435 divisor = 1.3;
2436 quotient = remainder(dividend, divisor);
2437 expected = "1.0";
2438 assert(quotient == expected);
2439 writeln("passed");
2440 }
2441
2442 //--------------------------------
2443 // rounding
2444 //--------------------------------
2445
2446 public Decimal rint(const Decimal dec){
2447 if (dec.isSignaling) return invalidOp();
2448 if (dec.isSpecial) return dec;
2449 if (dec.expo >= 0) return dec;
2450 pushContext();
2451 context.precision = dec.digits;
2452 Decimal result = quantize(dec, ONE);
2453 popContext();
2454 return result;
2455 }
2456
2457 public Decimal nearbyint(const Decimal dec){
2458 // this operation shouldn't affect the inexact or rounded flags
2459 // so we'll save them in case they were already set.
2460 bool inexact = context.getFlag(INEXACT);
2461 bool rounded = context.getFlag(ROUNDED);
2462 Decimal result = rint(dec);
2463 context.setFlag(INEXACT, inexact);
2464 context.setFlag(ROUNDED, rounded);
2465 return result;
2466 }
2467
2468 unittest {
2469 write("rnd-int-ex...");
2470 Decimal dec;
2471 Decimal expd;
2472 Decimal actual;
2473 dec = 2.1;
2474 expd = 2;
2475 actual = rint(dec);
2476 assert(actual == expd);
2477 dec = 100;
2478 expd = 100;
2479 assert(rint(dec) == expd);
2480 assert(rint(dec).toString() == expd.toString());
2481 dec = "100.0";
2482 assert(rint(dec) == expd);
2483 assert(rint(dec).toString() == expd.toString());
2484 dec = "101.5";
2485 expd = 102;
2486 assert(rint(dec) == expd);
2487 assert(rint(dec).toString() == expd.toString());
2488 dec = "-101.5";
2489 expd = -102;
2490 assert(rint(dec) == expd);
2491 assert(rint(dec).toString() == expd.toString());
2492 dec = "10E+5";
2493 expd = "1.0E+6";
2494 assert(rint(dec) == expd);
2495 assert(rint(dec).toString() == expd.toString());
2496 dec = "7.89E+77";
2497 expd = "7.89E+77";
2498 assert(rint(dec) == expd);
2499 assert(rint(dec).toString() == expd.toString());
2500 dec = "-Inf";
2501 expd = "-Infinity";
2502 assert(rint(dec) == expd);
2503 assert(rint(dec).toString() == expd.toString());
2504 writeln("passed");
2505 }
2506
2507 /**
2508 * Clips the coefficient of the number to the specified precision.
2509 * Returns the remainder for adjustments based on rounding mode.
2510 * Sets the ROUNDED and INEXACT flags.
2511 */
2512 private BigInt shorten(ref Decimal number) {
2513 BigInt remainder = BIG_ZERO;
2514 int diff = number.digits - context.precision;
2515 if (diff <= 0) {
2516 return remainder;
2517 }
2518 context.setFlag(ROUNDED);
2519 if (context.precision == 0) {
2520 remainder = number.ceff;
2521 number.ceff = 0;
2522 number.digits = 1;
2523 }
2524 else {
2525 BigInt divisor = pow10(diff);
2526 remainder = number.ceff % divisor;
2527 number.ceff /= divisor;
2528 number.digits = context.precision;
2529 number.expo += diff;
2530 }
2531 if (remainder != BIG_ZERO) {
2532 context.setFlag(INEXACT);
2533 }
2534 return remainder;
2535 }
2536
2537 /**
2538 * Increments the coefficient by 1. If this causes an overflow, divides by 10.
2539 */
2540 private void increment(ref BigInt number) {
2541 number++;
2542 if (lastDigit(number) == 0) {
2543 number /= 10;
2544 }
2545 }
2546
2547 // TODO: need to signal inexact and rounded.
2548 private void roundByMode(ref Decimal number) {
2549 BigInt remainder = shorten(number);
2550
2551 // if the rounded flag is not set by the shorten operation, return
2552 if (!context.getFlag(ROUNDED)) {
2553 return;
2554 }
2555 // if the remainder is zero, return
2556 if (remainder == BIG_ZERO) {
2557 return;
2558 }
2559
2560 switch (context.mode) {
2561 case Rounding.DOWN:
2562 return;
2563 case Rounding.HALF_UP:
2564 if (firstDigit(remainder) >= 5) {
2565 increment(number.ceff);
2566 }
2567 return;
2568 case Rounding.HALF_EVEN:
2569 BigInt test = 5 * pow10(numDigits(remainder,1)-1);
2570 int result = remainder.opCmp(test);
2571 if (result > 0) {
2572 increment(number.ceff);
2573 return;
2574 }
2575 if (result < 0) {
2576 return;
2577 }
2578 // if last digit is odd...
2579 if (lastDigit(number.ceff) & 1 == 1) {
2580 increment(number.ceff);
2581 }
2582 return;
2583 case Rounding.CEILING:
2584 if (!number.sign && remainder != BIG_ZERO) {
2585 increment(number.ceff);
2586 }
2587 return;
2588 case Rounding.FLOOR:
2589 if (number.sign && remainder != BIG_ZERO) {
2590 increment(number.ceff);
2591 }
2592 return;
2593 case Rounding.HALF_DOWN:
2594 if (firstDigit(remainder) > 5) {
2595 increment(number.ceff);
2596 }
2597 return;
2598 case Rounding.UP:
2599 if (remainder != BIG_ZERO) {
2600 increment(number.ceff);
2601 }
2602 return;
2603 } // end switch(mode)
2604 } // end roundByMode()
2605
2606 public void round(ref Decimal number) {
2607 if (!number.isFinite) return;
2608
2609 context.clearFlags();
2610 // check for subnormal
2611 bool subnormal = false;
2612 if (number.isSubnormal()) {
2613 context.setFlag(SUBNORMAL);
2614 subnormal = true;
2615 }
2616
2617 // check for overflow
2618 if (number.overflow()) {
2619 context.setFlag(OVERFLOW);
2620 switch (context.mode) {
2621 case Rounding.HALF_UP:
2622 case Rounding.HALF_EVEN:
2623 case Rounding.HALF_DOWN:
2624 case Rounding.UP:
2625 bool sign = number.sign;
2626 number = POS_INF;
2627 number.sign = sign;
2628 break;
2629 case Rounding.DOWN:
2630 bool sign = number.sign;
2631 number = context.max;
2632 number.sign = sign;
2633 break;
2634 case Rounding.CEILING:
2635 if (number.sign) {
2636 number = context.max;
2637 number.sign = true;
2638 }
2639 else {
2640 number = POS_INF;
2641 }
2642 break;
2643 case Rounding.FLOOR:
2644 if (number.sign) {
2645 number = NEG_INF;
2646 } else {
2647 number = context.max;
2648 }
2649 break;
2650 }
2651 context.setFlag(INEXACT);
2652 context.setFlag(ROUNDED);
2653 return;
2654 }
2655 roundByMode(number);
2656 // check for underflow
2657 if (number.isSubnormal /+&& number.isInexact+/) {
2658 context.setFlag(SUBNORMAL);
2659 int diff = context.eTiny - number.adjustedExponent();
2660 if (diff > number.digits) {
2661 number.ceff = 0;
2662 number.expo = context.eTiny;
2663 } else if (diff > 0) {
2664 writeln("We got a tiny one!");
2665 }
2666 }
2667 // check for zero
2668 if (number.spval == SpVal.CLEAR && number.ceff == BIG_ZERO) {
2669 number.spval = SpVal.ZERO;
2670 // subnormal rounding to zero == clamped
2671 // Spec. p. 51
2672 if (subnormal) {
2673 context.setFlag(CLAMPED);
2674 }
2675 return;
2676 }
2677 } // end round()
2678
2679 unittest {
2680 write("round........");
2681 Decimal before = Decimal(1234567890);
2682 Decimal after = before;
2683 pushContext();
2684 context.precision = 3;
2685 round(after);
2686 assert(after.toString() == "1.23E+9");
2687 after = before;
2688 context.precision = 4;
2689 round(after);
2690 assert(after.toString() == "1.235E+9");
2691 after = before;
2692 context.precision = 5;
2693 round(after);
2694 assert(after.toString() == "1.2346E+9");
2695 after = before;
2696 context.precision = 6;
2697 round(after);
2698 assert(after.toString() == "1.23457E+9");
2699 after = before;
2700 context.precision = 7;
2701 round(after);
2702 assert(after.toString() == "1.234568E+9");
2703 after = before;
2704 context.precision = 8;
2705 round(after);
2706 assert(after.toString() == "1.2345679E+9");
2707 before = "1235";
2708 after = before;
2709 context.precision = 3;
2710 round(after);
2711 assert(after.toAbstract() == "[0,124,1]");
2712 before = "12359";
2713 after = before;
2714 context.precision = 3;
2715 round(after);
2716 assert(after.toAbstract() == "[0,124,2]");
2717 before = "1245";
2718 after = before;
2719 context.precision = 3;
2720 round(after);
2721 assert(after.toAbstract() == "[0,124,1]");
2722 before = "12459";
2723 after = before;
2724 context.precision = 3;
2725 round(after);
2726 assert(after.toAbstract() == "[0,125,2]");
2727 popContext();
2728 writeln("passed");
2729 }
2730
2731 public void setDigits(ref Decimal number) {
2732 int diff = number.digits - context.precision;
2733 if (diff > 0) {
2734 round(number);
2735 }
2736 else if (diff < 0) {
2737 number.ceff *= pow10(-diff);
2738 number.expo += diff;
2739 }
2740 number.digits = context.precision;
2741 }
2742
2743 /**
2744 * Returns the number which is equal in value and sign
2745 * to the first operand and which has its exponent set
2746 * to be equal to the exponent of the second operand.
2747 */
2748 // TODO: this has unusual flag rules
2749 Decimal quantize(const Decimal dcm1, const Decimal dcm2) {
2750 Decimal result;
2751 if (isInvalidOperation(dcm1, dcm2, result)) {
2752 return result;
2753 }
2754 if (dcm1.isInfinite != dcm2.isInfinite() ||
2755 dcm2.isInfinite != dcm1.isInfinite()) {
2756 return invalidOp();
2757 }
2758 if (dcm1.isInfinite() && dcm2.isInfinite()) {
2759 return dcm1.dup;
2760 }
2761 result = dcm1;
2762 int diff = dcm1.expo - dcm2.expo;
2763 if (diff == 0) {
2764 return result;
2765 }
2766 if (diff > 0) {
2767 result.ceff *= pow10(diff);
2768 result.digits += diff;
2769 result.expo = dcm2.expo;
2770 if (result.digits > context.precision) {
2771 result = NaN;
2772 }
2773 return result;
2774 }
2775 else {
2776 pushContext();
2777 context.precision =
2778 -diff > dcm1.digits ? 0 : dcm1.digits + diff;
2779 round(result);
2780 result.expo = dcm2.expo;
2781 popContext();
2782 return result;
2783 }
2784 }
2785
2786 unittest {
2787 write("quantize.....");
2788 Decimal op1;
2789 Decimal op2;
2790 Decimal result;
2791 Decimal expd;
2792 string str;
2793 op1 = "2.17";
2794 op2 = "0.001";
2795 expd = "2.170";
2796 result = quantize(op1, op2);
2797 assert(result == expd);
2798 op1 = "2.17";
2799 op2 = "0.01";
2800 expd = "2.17";
2801 result = quantize(op1, op2);
2802 assert(result == expd);
2803 op1 = "2.17";
2804 op2 = "0.1";
2805 expd = "2.2";
2806 result = quantize(op1, op2);
2807 assert(result == expd);
2808 op1 = "2.17";
2809 op2 = "1e+0";
2810 expd = "2";
2811 result = quantize(op1, op2);
2812 assert(result == expd);
2813 op1 = "2.17";
2814 op2 = "1e+1";
2815 expd = "0E+1";
2816 result = quantize(op1, op2);
2817 assert(result.toString() == expd.toString());
2818 op1 = "-Inf";
2819 op2 = "Infinity";
2820 expd = "-Infinity";
2821 result = quantize(op1, op2);
2822 assert(result == expd);
2823 op1 = "2";
2824 op2 = "Infinity";
2825 expd = "NaN";
2826 result = quantize(op1, op2);
2827 assert(result.toString() == expd.toString());
2828 op1 = "-0.1";
2829 op2 = "1";
2830 expd = "-0";
2831 result = quantize(op1, op2);
2832 assert(result.toString() == expd.toString());
2833 op1 = "-0";
2834 op2 = "1e+5";
2835 expd = "-0E+5";
2836 result = quantize(op1, op2);
2837 assert(result.toString() == expd.toString());
2838 op1 = "+35236450.6";
2839 op2 = "1e-2";
2840 expd = "NaN";
2841 result = quantize(op1, op2);
2842 assert(result.toString() == expd.toString());
2843 op1 = "-35236450.6";
2844 op2 = "1e-2";
2845 expd = "NaN";
2846 result = quantize(op1, op2);
2847 assert(result.toString() == expd.toString());
2848 op1 = "217";
2849 op2 = "1e-1";
2850 expd = "217.0";
2851 result = quantize(op1, op2);
2852 assert(result.toString() == expd.toString());
2853 op1 = "217";
2854 op2 = "1e+0";
2855 expd = "217";
2856 result = quantize(op1, op2);
2857 assert(result.toString() == expd.toString());
2858 op1 = "217";
2859 op2 = "1e+1";
2860 expd = "2.2E+2";
2861 result = quantize(op1, op2);
2862 assert(result.toString() == expd.toString());
2863 op1 = "217";
2864 op2 = "1e+2";
2865 expd = "2E+2";
2866 result = quantize(op1, op2);
2867 assert(result.toString() == expd.toString());
2868 assert(result == expd);
2869 writeln("passed");
2870 }
2871
2872 /**
2873 * Reduces operand to simplest form. All trailing zeros are removed.
2874 */
2875 // TODO: has non-standard flag setting
2876 Decimal reduce(const Decimal dcm) {
2877 Decimal result;
2878 if (isInvalidOperation(dcm, result)) {
2879 return result;
2880 }
2881 result = dcm;
2882 if (!result.isFinite()) {
2883 return result;
2884 }
2885 BigInt temp = result.ceff % 10;
2886 while (result.ceff != 0 && temp == 0) {
2887 result.expo++;
2888 result.ceff = result.ceff / 10;
2889 temp = result.ceff % 10;
2890 }
2891 if (result.ceff == 0) {
2892 result.spval = SpVal.ZERO;
2893 result.expo = 0;
2894 }
2895 result.digits = numDigits(result.ceff);
2896 return result;
2897 }
2898
2899 unittest {
2900 write("reduce.......");
2901 Decimal dec;
2902 Decimal red;
2903 string str;
2904 dec = "2.1";
2905 str = "2.1";
2906 red = reduce(dec);
2907 assert(red.toString() == str);
2908 dec = "-2.0";
2909 str = "-2";
2910 red = reduce(dec);
2911 assert(red.toString() == str);
2912 dec = "1.200";
2913 str = "1.2";
2914 red = reduce(dec);
2915 assert(red.toString() == str);
2916 dec = "-120";
2917 str = "-1.2E+2";
2918 red = reduce(dec);
2919 assert(red.toString() == str);
2920 dec = "120.00";
2921 str = "1.2E+2";
2922 red = reduce(dec);
2923 assert(red.toString() == str);
2924 writeln("passed");
2925 }
2926
2927 private:
2928
2929 /**
2930 * Sets the invalid-operation flag and
2931 * returns a quiet NaN.
2932 */
2933 Decimal invalidOp() {
2934 context.flags |= INVALID_OPERATION;
2935 return NaN;
2936 }
2937
2938 /**
2939 * aligns the two operands by raising the smaller exponent
2940 * to the value of the larger exponent, and adjusting the
2941 * coefficient so the value remains the same.
2942 */
2943 void alignOps(ref Decimal op1, ref Decimal op2) {
2944 int diff = op1.expo - op2.expo;
2945 if (diff > 0) {
2946 op1.ceff *= pow10(diff);
2947 op1.expo = op2.expo;
2948 }
2949 else if (diff < 0) {
2950 op2.ceff *= pow10(-diff);
2951 op2.expo = op1.expo;
2952 }
2953 }
2954
2955 /*
2956 * "The result of any arithmetic operation which has an operand
2957 * which is a NaN (a quiet NaN or a signaling NaN) is [s,qNaN]
2958 * or [s,qNaN,d]. The sign and any diagnostic information is copied
2959 * from the first operand which is a signaling NaN, or if neither is
2960 * signaling then from the first operand which is a NaN."
2961 * -- General Decimal Arithmetic Specification, p. 24
2962 */
2963 bool isInvalidOperation(const Decimal dcm1, const Decimal dcm2,
2964 ref Decimal result) {
2965 // if either operand is an sNaN...
2966 if (dcm1.isSignaling || dcm2.isSignaling) {
2967 // set the result to the first sNaN operand
2968 result = dcm1.isSignaling ? dcm1 : dcm2;
2969 // retain sign and payload; convert to qNaN
2970 result.spval = SpVal.QNAN;
2971 // flag the invalid operation
2972 context.flags |= INVALID_OPERATION;
2973 return true;
2974 }
2975 // ...else if either operand is a qNaN...
2976 if (dcm1.isQuiet || dcm2.isQuiet) {
2977 // set the result to the first qNaN operand
2978 result = dcm1.isQuiet ? dcm1 : dcm2;
2979 // flag the invalid operation
2980 context.flags |= INVALID_OPERATION;
2981 return true;
2982 }
2983 // ...otherwise, no flags are set and result is unchanged
2984 return false;
2985 }
2986
2987 unittest {
2988 write("invalid......");
2989 Decimal dcm;
2990 Decimal expd;
2991 Decimal actual;
2992
2993 dcm = "sNaN123";
2994 expd = "NaN123";
2995 actual = abs(dcm);
2996 assert(actual.isQuiet);
2997 assert(context.flags && INVALID_OPERATION);
2998 assert(actual.toAbstract == expd.toAbstract);
2999 dcm = "NaN123";
3000 actual = abs(dcm);
3001 assert(actual.isQuiet);
3002 assert(context.flags && INVALID_OPERATION);
3003 assert(actual.toAbstract == expd.toAbstract);
3004
3005 dcm = "sNaN123";
3006 expd = "NaN123";
3007 actual = -dcm;
3008 assert(actual.isQuiet);
3009 assert(context.flags && INVALID_OPERATION);
3010 assert(actual.toAbstract == expd.toAbstract);
3011 dcm = "NaN123";
3012 actual = -dcm;
3013 assert(actual.isQuiet);
3014 assert(context.flags && INVALID_OPERATION);
3015 assert(actual.toAbstract == expd.toAbstract);
3016 writeln("passed");
3017 }
3018
3019 /*
3020 * "The result of any arithmetic operation which has an operand
3021 * which is a NaN (a quiet NaN or a signaling NaN) is [s,qNaN]
3022 * or [s,qNaN,d]. The sign and any diagnostic information is copied
3023 * from the first operand which is a signaling NaN, or if neither is
3024 * signaling then from the first operand which is a NaN."
3025 * -- General Decimal Arithmetic Specification, p. 24
3026 */
3027 bool isInvalidOperation(const Decimal dcm, ref Decimal result) {
3028 // if the operand is an sNaN...
3029 if (dcm.isSignaling) {
3030 // set the result to the sNaN operand
3031 result = dcm;
3032 // retain sign and payload; convert to qNaN
3033 result.spval = SpVal.QNAN;
3034 // flag the invalid operation
3035 context.flags |= INVALID_OPERATION;
3036 return true;
3037 }
3038 // ...else if the operand is a qNaN...
3039 if (dcm.isQuiet) {
3040 // set the result to the qNaN operand
3041 result = dcm;
3042 // flag the invalid operation
3043 context.flags |= INVALID_OPERATION;
3044 return true;
3045 }
3046 // ...otherwise, no flags are set and result is unchanged
3047 return false;
3048 }
3049
3050 // TODO: add unit tests here for operations that apply
3051 unittest {
3052
3053 }
3054
3055 /+/*
3056 * -- General Decimal Arithmetic Specification, p. 52, "Invalid operation"
3057 */
3058 bool isInvalidAddition(Decimal op1, Decimal op2, ref Decimal result) {
3059 if (isInvalidOperation(op1, op2, result)) {
3060 return true;
3061 }
3062 // if both operands are infinite
3063 if (op1.isInfinite && op2.isInfinite) {
3064 // (+inf) + (-inf) => invalid operation
3065 if (op1.sign != op2.sign) {
3066 result = invalidOp();
3067 return true;
3068 }
3069 }
3070 return false;
3071 }+/
3072
3073 /*
3074 * -- General Decimal Arithmetic Specification, p. 52, "Invalid operation"
3075 */
3076 bool isInvalidMultiplication(Decimal op1, Decimal op2, ref Decimal result) {
3077 if (isInvalidOperation(op1, op2, result)) {
3078 return true;
3079 }
3080 if (op1.isZero && op2.isInfinite || op1.isInfinite && op2.isZero) {
3081 result = NaN;
3082 return true;
3083 }
3084 return false;
3085 }
3086
3087 /*
3088 * -- General Decimal Arithmetic Specification, p. 52, "Invalid operation"
3089 */
3090 bool isInvalidDivision(Decimal dividend, Decimal divisor, ref Decimal quotient) {
3091 if (isInvalidOperation(dividend, divisor, quotient)) {
3092 return true;
3093 }
3094 if (divisor.isZero()) {
3095 if (dividend.isZero()) {
3096 quotient = invalidOp();
3097 }
3098 else {
3099 quotient.spval = SpVal.INF;
3100 context.flags |= DIVISION_BY_ZERO;
3101 quotient.ceff = BIG_ZERO;
3102 quotient.sign = dividend.sign ^ divisor.sign;
3103 }
3104 return true;
3105 }
3106 return false;
3107 }
3108
3109 //--------------------------------
3110 // unit tests
3111 //--------------------------------
3112
3113 //--------------------------------
3114 // additions to BigInt
3115 //--------------------------------
3116
3117 private:
3118 static immutable BigInt BIG_ZERO = { [0] };
3119 static immutable BigInt BIG_ONE = { [1] };
3120 static immutable BigInt BIG_FIVE = { [5] };
3121 static immutable BigInt BIG_TEN = { [10] };
3122
3123 /**
3124 * Returns the number of decimal digits in BigInt value.
3125 * There are probably significant efficiency gains available.
3126 **/
3127 uint numDigits(const BigInt big, int n = 1) {
3128 if (big == 0) return 1;
3129 if (n <= 0) n = 1;
3130 int m = n;
3131 while (big < pow10(m-1)) m--;
3132 if (m != n) return m;
3133 while (big >= pow10(m)) m++;
3134 return m;
3135 }
3136
3137 /**
3138 * Returns a BigInt with the value of 10 raised to the specified power.
3139 * There are probably significant efficiency gains available.
3140 **/
3141 public BigInt pow10(uint power) {
3142 static immutable int BILLION = 1000000000;
3143 static immutable int array[10] =
3144 [ 1, 10, 100, 1000, 10000, 100000, 1000000,
3145 10000000, 100000000, BILLION ];
3146
3147 if (power < 10) {
3148 return BigInt(array[power]);
3149 }
3150 BigInt big = BigInt(BILLION);
3151 power -= 9;
3152 int quo = power / 9;
3153 int rem = power % 9;
3154 for (int i = 0; i < quo; i++) {
3155 big *= BILLION;
3156 }
3157 return big * array[rem];
3158 }
3159
3160 /**
3161 * Returns the first decimal digit of the specified BigInt.
3162 */
3163 uint firstDigit(BigInt big) {
3164 uint digits = numDigits(big, 1);
3165 if (digits == 0) {
3166 return 0;
3167 }
3168 BigInt bfd = big / pow10(digits - 1);
3169 uint ifd;
3170 bfd.castTo(ifd);
3171 return ifd;
3172 }
3173
3174 /**
3175 * Returns the last decimal digit of the specified BigInt.
3176 */
3177 uint lastDigit(BigInt big) {
3178 return big % 10;
3179 }
3180
3181 unittest {
3182 write("bigint.......");
3183 string str = "1";
3184 BigInt big = pow10(0);
3185 assert(str == big.toString);
3186 for (int i = 1; i < 35; i++) {
3187 str ~= "0";
3188 big = pow10(i);
3189 assert(str == big.toString);
3190 assert(numDigits(big) == str.length);
3191 }
3192 writeln("passed");
3193 }
3194
3195 public void main() {
3196 writeln("Hello, world!");
3197 /+ writeln("eTiny = ", context.eTiny);
3198 writeln("tiny min = ", Decimal(1, context.eTiny));
3199 writeln("tiny min = ", Decimal(1, context.eTiny - 1));
3200 writeln("max = ", context.max());
3201 writeln("max1 = ", Decimal(999999999, 99));
3202 writeln("dig = ", context.dig());
3203 writeln("eps = ", context.epsilon());
3204 writeln("smallest = ", context.min_normal()*context.epsilon());
3205 writeln("1/epsilon = ", Decimal(1)/context.epsilon());
3206 writeln("max * min = ", context.max * context.min_normal);
3207 writeln("mant_dig = ", context.mant_dig);
3208 writeln("min_exp = ", context.min_exp);
3209 writeln("max_exp = ", context.max_exp);+/
3210
3211
3212 // TODO: this next one goes crazy -- shows need for checks on construction
3213 // TODO: turns out this is being converted to a double (or real) and
3214 // then it's really weird.
3215 // writeln("bigger = ", Decimal(999999999999));
3216 // float f = float.max;
3217 // TODO: convert these to assserts
3218 /+ writeln("f.max = ", f);
3219 writeln("f.min = ", float.min);
3220 writeln("f = ", 2 * float.min);
3221 writeln("d.max = ", Decimal.max());
3222 writeln("d.min = ", Decimal.min_normal());
3223 writeln("2 * d.min = ", 2 * Decimal.min_normal());
3224 writeln("0.1 * d.min = ", 0.1 * Decimal.min_normal());+/
3225 // TODO: move this to unittesting
3226 /+ Decimal dec = Decimal(PI);
3227 writeln("pi = ", dec );
3228 dec = Decimal(PI, 19);
3229 writeln("pi = ", dec );
3230 dec = Decimal(1.3, 25);
3231 writeln("pi = ", dec );
3232 dec = Decimal(0.1, 25);
3233 writeln("pi = ", dec );
3234 dec = Decimal(2.0, 25);
3235 writeln("pi = ", dec );
3236 dec = Decimal(200.5, 25);
3237 writeln("pi = ", dec );
3238 writeln(double.dig);
3239 writeln(real.dig);+/
3240 }
3241