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