Mercurial > projects > decimal
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 |