0
|
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
|