001/* 002 * $Id$ 003 */ 004 005package edu.jas.arith; 006 007 008import java.io.Reader; 009import java.math.MathContext; 010import java.util.ArrayList; 011import java.util.List; 012import java.util.Random; 013 014import edu.jas.kern.StringUtil; 015import edu.jas.structure.GcdRingElem; 016import edu.jas.structure.RingFactory; 017 018 019/** 020 * BigDecimal class to make java.math.BigDecimal available with RingElem 021 * interface. Objects of this class are immutable. Experimental, use with care, 022 * compareTo is some times hacked. 023 * @author Heinz Kredel 024 * @see java.math.BigDecimal 025 */ 026 027public final class BigDecimal implements GcdRingElem<BigDecimal>, RingFactory<BigDecimal>, 028 Rational { 029 030 031 /** 032 * The data structure. 033 */ 034 public final java.math.BigDecimal val; 035 036 037 public final MathContext context; // should be in factory 038 039 040 public static final MathContext DEFAULT_CONTEXT = MathContext.DECIMAL64; //32; //64; //128; 041 042 043 public static final int DEFAULT_PRECISION = DEFAULT_CONTEXT.getPrecision(); 044 045 046 private final static Random random = new Random(); 047 048 049 /** 050 * If true, then use equals from java.math.BigDecimal, else use hacked 051 * approximate compareTo(). 052 */ 053 public final static boolean EXACT_EQUAL = true; 054 055 056 /** 057 * The constant 0. 058 */ // depends on math context, should be in factory 059 public final static BigDecimal ZERO = new BigDecimal(java.math.BigDecimal.ZERO); 060 061 062 /** 063 * The constant 1. 064 */ // depends on math context, should be in factory 065 public final static BigDecimal ONE = new BigDecimal(java.math.BigDecimal.ONE); 066 067 068 /** 069 * Constructor for BigDecimal from math.BigDecimal. 070 * @param a java.math.BigDecimal. 071 */ 072 public BigDecimal(java.math.BigDecimal a) { 073 this(a, DEFAULT_CONTEXT); 074 } 075 076 077 /** 078 * Constructor for BigDecimal from math.BigDecimal. 079 * @param a java.math.BigDecimal. 080 * @param mc MathContext. 081 */ 082 public BigDecimal(java.math.BigDecimal a, MathContext mc) { 083 val = a; 084 context = mc; 085 } 086 087 088 /** 089 * Constructor for BigDecimal from long. 090 * @param a long. 091 */ 092 public BigDecimal(long a) { 093 this(a, DEFAULT_CONTEXT); 094 } 095 096 097 /** 098 * Constructor for BigDecimal from long and a context. 099 * @param a long. 100 * @param mc MathContext. 101 */ 102 public BigDecimal(long a, MathContext mc) { 103 this(new java.math.BigDecimal(String.valueOf(a)), mc); 104 } 105 106 107 /** 108 * Constructor for BigDecimal from double. 109 * @param a double. 110 */ 111 public BigDecimal(double a) { 112 this(a, DEFAULT_CONTEXT); 113 } 114 115 116 /** 117 * Constructor for BigDecimal from double and a context. 118 * @param a double. 119 * @param mc MathContext. 120 */ 121 public BigDecimal(double a, MathContext mc) { 122 this(new java.math.BigDecimal(a, mc), mc); 123 } 124 125 126 /** 127 * Constructor for BigDecimal from java.math.BigInteger. 128 * @param a java.math.BigInteger. 129 */ 130 public BigDecimal(java.math.BigInteger a) { 131 this(a, DEFAULT_CONTEXT); 132 } 133 134 135 /** 136 * Constructor for BigDecimal from java.math.BigInteger. 137 * @param a java.math.BigInteger. 138 * @param mc MathContext. 139 */ 140 public BigDecimal(java.math.BigInteger a, MathContext mc) { 141 this(new java.math.BigDecimal(a), mc); 142 } 143 144 145 /** 146 * Constructor for BigDecimal from BigRational. 147 * @param a edu.jas.arith.BigRational. 148 */ 149 public BigDecimal(BigRational a) { 150 this(a, DEFAULT_CONTEXT); 151 } 152 153 154 /** 155 * Constructor for BigDecimal from BigRational. 156 * @param a edu.jas.arith.BigRational. 157 * @param mc MathContext. 158 */ 159 public BigDecimal(BigRational a, MathContext mc) { 160 this((new java.math.BigDecimal(a.num, mc)).divide(new java.math.BigDecimal(a.den, mc), mc), mc); 161 } 162 163 164 /** 165 * Constructor for BigDecimal from String. 166 * @param s String. 167 */ 168 public BigDecimal(String s) { 169 this(s, DEFAULT_CONTEXT); 170 } 171 172 173 /** 174 * Constructor for BigDecimal from String. 175 * @param s String. 176 * @param mc MathContext. 177 */ 178 public BigDecimal(String s, MathContext mc) { 179 this(new java.math.BigDecimal(s.trim()), mc); 180 } 181 182 183 /** 184 * Constructor for BigDecimal without parameters. 185 */ 186 public BigDecimal() { 187 this(java.math.BigDecimal.ZERO, DEFAULT_CONTEXT); 188 } 189 190 191 /* 192 * Get the value. 193 * @return val java.math.BigDecimal. 194 * public java.math.BigDecimal getVal() { 195 * return val; } 196 */ 197 198 199 /** 200 * Get the corresponding element factory. 201 * @return factory for this Element. 202 * @see edu.jas.structure.Element#factory() 203 */ 204 public BigDecimal factory() { 205 return this; 206 } 207 208 209 /** 210 * Get a list of the generating elements. 211 * @return list of generators for the algebraic structure. 212 * @see edu.jas.structure.ElemFactory#generators() 213 */ 214 public List<BigDecimal> generators() { 215 List<BigDecimal> g = new ArrayList<BigDecimal>(1); 216 g.add(getONE()); 217 return g; 218 } 219 220 221 /** 222 * Is this structure finite or infinite. 223 * @return true if this structure is finite, else false. 224 * @see edu.jas.structure.ElemFactory#isFinite() <b>Note: </b> is actually 225 * finite but returns false. 226 */ 227 public boolean isFinite() { 228 return false; 229 } 230 231 232 /** 233 * Clone this. 234 * @see java.lang.Object#clone() 235 */ 236 @Override 237 public BigDecimal copy() { 238 return new BigDecimal(val, context); 239 } 240 241 242 /** 243 * Copy BigDecimal element c. 244 * @param c BigDecimal. 245 * @return a copy of c. 246 */ 247 public BigDecimal copy(BigDecimal c) { 248 return new BigDecimal(c.val, c.context); 249 } 250 251 252 /** 253 * Get the zero element. 254 * @return 0. 255 */ 256 public BigDecimal getZERO() { 257 return ZERO; 258 } 259 260 261 /** 262 * Get the one element. 263 * @return 1. 264 */ 265 public BigDecimal getONE() { 266 return ONE; 267 } 268 269 270 /** 271 * Get the decimal representation. 272 * @return decimal. 273 */ 274 public BigDecimal getDecimal() { 275 return this; 276 } 277 278 279 /** 280 * Get the rational representation. 281 * @return rational number. 282 */ 283 public BigRational getRational() { 284 return new BigRational(toString()); 285 } 286 287 288 /** 289 * Query if this ring is commutative. 290 * @return true. 291 */ 292 public boolean isCommutative() { 293 return true; 294 } 295 296 297 /** 298 * Query if this ring is associative. Floating point number addition is not 299 * associative, but multiplication is. 300 * @return true. 301 */ 302 public boolean isAssociative() { 303 return true; 304 } 305 306 307 /** 308 * Query if this ring is a field. 309 * @return true. 310 */ 311 public boolean isField() { 312 return true; 313 } 314 315 316 /** 317 * Characteristic of this ring. 318 * @return characteristic of this ring. 319 */ 320 public java.math.BigInteger characteristic() { 321 return java.math.BigInteger.ZERO; 322 } 323 324 325 /** 326 * Get a BigDecimal element from a math.BigDecimal. 327 * @param a math.BigDecimal. 328 * @return a as BigDecimal. 329 */ 330 public BigDecimal fromInteger(java.math.BigInteger a) { 331 return new BigDecimal(new java.math.BigDecimal(a), context); 332 } 333 334 335 /** 336 * Get a BigDecimal element from a math.BigDecimal. 337 * @param a math.BigDecimal. 338 * @return a as BigDecimal. 339 */ 340 public static BigDecimal valueOf(java.math.BigDecimal a) { 341 return new BigDecimal(a, DEFAULT_CONTEXT); 342 } 343 344 345 /** 346 * Get a BigDecimal element from long. 347 * @param a long. 348 * @return a as BigDecimal. 349 */ 350 public BigDecimal fromInteger(long a) { 351 return new BigDecimal(a, context); 352 } 353 354 355 /** 356 * Get a BigDecimal element from long. 357 * @param a long. 358 * @return a as BigDecimal. 359 */ 360 public static BigDecimal valueOf(long a) { 361 return new BigDecimal(a, DEFAULT_CONTEXT); 362 } 363 364 365 /** 366 * Is BigDecimal number zero. 367 * @return If this is 0 then true is returned, else false. 368 * @see edu.jas.structure.RingElem#isZERO() 369 */ 370 public boolean isZERO() { 371 if (EXACT_EQUAL) { 372 return val.compareTo(java.math.BigDecimal.ZERO) == 0; 373 } 374 return compareTo(ZERO) == 0; 375 } 376 377 378 /** 379 * Is BigDecimal number one. 380 * @see edu.jas.structure.RingElem#isONE() 381 */ 382 public boolean isONE() { 383 if (EXACT_EQUAL) { 384 return val.compareTo(java.math.BigDecimal.ONE) == 0; 385 } 386 return compareTo(ONE) == 0; 387 } 388 389 390 /** 391 * Is BigDecimal number unit. 392 * @see edu.jas.structure.RingElem#isUnit() 393 */ 394 public boolean isUnit() { 395 return (!isZERO()); 396 } 397 398 399 /** 400 * Get the String representation. 401 * @see java.lang.Object#toString() 402 */ 403 @Override 404 public String toString() { 405 //return val.toString() + "(ulp=" + val.ulp() + ")"; 406 return val.toString(); 407 } 408 409 410 /** 411 * Get this decimal as a <tt>double</tt>. 412 * @return the decimal as a <tt>double</tt> 413 * @see java.lang.Number#doubleValue() 414 */ 415 public double doubleValue() { 416 return val.doubleValue(); 417 } 418 419 420 /** 421 * Get a scripting compatible string representation. 422 * @return script compatible representation for this Element. 423 * @see edu.jas.structure.Element#toScript() 424 */ 425 @Override 426 public String toScript() { 427 // Python+Ruby case 428 return toString(); 429 } 430 431 432 /** 433 * Get a scripting compatible string representation of the factory. 434 * @return script compatible representation for this ElemFactory. 435 * @see edu.jas.structure.Element#toScriptFactory() 436 */ 437 @Override 438 public String toScriptFactory() { 439 // Python+Ruby case 440 return "DD()"; 441 } 442 443 444 /** 445 * Compare to BigDecimal b. Experimental, is hacked. 446 * @param b BigDecimal. 447 * @return 0 if abs(this-b) < epsilon, 1 if this > b, -1 if this < 448 * b. 449 */ 450 @Override 451 public int compareTo(BigDecimal b) { 452 //return compareToAbsolute(b); 453 //return compareToRelative(b); 454 return val.compareTo(b.val); 455 } 456 457 458 /** 459 * Compare absolute to BigDecimal b. Experimental, is hacked. 460 * @param b BigDecimal. 461 * @return 0 if abs(this-b) < epsilon, 1 if this > b, -1 if this < 462 * b. 463 */ 464 public int compareToAbsolute(BigDecimal b) { 465 //if (EXACT_EQUAL) { 466 // return val.compareTo(b.val); 467 //} 468 java.math.BigDecimal s = val.subtract(b.val, context); 469 java.math.BigDecimal u1 = val.ulp(); 470 java.math.BigDecimal u2 = b.val.ulp(); 471 int u = Math.min(u1.scale(), u2.scale()); 472 //System.out.println("u = " + u + ", s = " + s); 473 java.math.BigDecimal eps; 474 if (u <= 0) { 475 eps = u1.max(u2); 476 } else { 477 eps = u1.min(u2); 478 } 479 //eps = eps.movePointRight(1); 480 //System.out.println("ctx = " + context); 481 //System.out.println("eps = " + eps); 482 int t = s.abs().compareTo(eps); 483 if (t < 1) { 484 return 0; 485 } 486 return s.signum(); 487 } 488 489 490 /** 491 * Compare to relative BigDecimal b. Experimental, is hacked. 492 * @param b BigDecimal. 493 * @return 0 if abs(this-b)/max(this,b) < epsilon, 1 if this > b, -1 494 * if this < b. 495 */ 496 public int compareToRelative(BigDecimal b) { 497 //if (EXACT_EQUAL) { 498 // return val.compareTo(b.val); 499 //} 500 java.math.BigDecimal s = val.subtract(b.val, context); 501 java.math.BigDecimal u1 = val.ulp(); 502 java.math.BigDecimal u2 = b.val.ulp(); 503 int u = Math.min(u1.scale(), u2.scale()); 504 //System.out.println("u = " + u + ", s = " + s); 505 java.math.BigDecimal eps; 506 if (u <= 0) { 507 eps = u1.max(u2); 508 } else { 509 eps = u1.min(u2); 510 } 511 eps = eps.movePointRight(1); 512 //System.out.println("ctx = " + context); 513 //System.out.println("eps = " + eps); 514 java.math.BigDecimal m = val.abs().max(b.val.abs()); 515 int t; 516 if (m.compareTo(java.math.BigDecimal.ONE) <= 1) { 517 t = s.abs().compareTo(eps); 518 } else { 519 t = s.abs().divide(m, context).compareTo(eps); 520 } 521 if (t < 1) { 522 return 0; 523 } 524 return s.signum(); 525 } 526 527 528 /** 529 * Comparison with any other object. 530 * @see java.lang.Object#equals(java.lang.Object) 531 */ 532 @Override 533 public boolean equals(Object b) { 534 if (!(b instanceof BigDecimal)) { 535 return false; 536 } 537 BigDecimal bi = (BigDecimal) b; 538 if (EXACT_EQUAL) { 539 return val.equals(bi.val); 540 } 541 return compareTo(bi) == 0; 542 } 543 544 545 /** 546 * Hash code for this BigDecimal. 547 * @see java.lang.Object#hashCode() 548 */ 549 @Override 550 public int hashCode() { 551 return val.hashCode(); 552 } 553 554 555 /** 556 * Absolute value of this. 557 * @see edu.jas.structure.RingElem#abs() 558 */ 559 public BigDecimal abs() { 560 return new BigDecimal(val.abs(), context); 561 } 562 563 564 /* Negative value of this. 565 * @see edu.jas.structure.RingElem#negate() 566 */ 567 public BigDecimal negate() { 568 return new BigDecimal(val.negate(), context); 569 } 570 571 572 /** 573 * signum. 574 * @see edu.jas.structure.RingElem#signum() 575 */ 576 public int signum() { 577 return val.signum(); 578 } 579 580 581 /** 582 * BigDecimal subtract. 583 * @param S BigDecimal. 584 * @return this-S. 585 */ 586 public BigDecimal subtract(BigDecimal S) { 587 return new BigDecimal(val.subtract(S.val, context), context); 588 } 589 590 591 /** 592 * BigDecimal divide. 593 * @param S BigDecimal. 594 * @return this/S. 595 */ 596 public BigDecimal divide(BigDecimal S) { 597 return new BigDecimal(val.divide(S.val, context), context); 598 } 599 600 601 /** 602 * Integer inverse. R is a non-zero integer. S=1/R if defined else 0. 603 * @see edu.jas.structure.RingElem#inverse() 604 */ 605 public BigDecimal inverse() { 606 return ONE.divide(this); 607 } 608 609 610 /** 611 * BigDecimal remainder. 612 * @param S BigDecimal. 613 * @return this - (this/S)*S. 614 */ 615 public BigDecimal remainder(BigDecimal S) { 616 return new BigDecimal(val.remainder(S.val, context), context); 617 } 618 619 620 /** 621 * BigDecimal compute quotient and remainder. 622 * @param S BigDecimal. 623 * @return BigDecimal[] { q, r } with q = this/S and r = rem(this,S). 624 */ 625 public BigDecimal[] quotientRemainder(BigDecimal S) { 626 BigDecimal[] qr = new BigDecimal[2]; 627 java.math.BigDecimal[] C = val.divideAndRemainder(S.val, context); 628 qr[0] = new BigDecimal(C[0], context); 629 qr[1] = new BigDecimal(C[1], context); 630 return qr; 631 } 632 633 634 /** 635 * BigDecimal greatest common divisor. 636 * @param S BigDecimal. 637 * @return gcd(this,S). 638 */ 639 public BigDecimal gcd(BigDecimal S) { 640 throw new UnsupportedOperationException("BigDecimal.gcd() not implemented"); 641 //return new BigDecimal( val.gcd( S.val ) ); 642 } 643 644 645 /** 646 * BigDecimal extended greatest common divisor. 647 * @param S BigDecimal. 648 * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). 649 */ 650 public BigDecimal[] egcd(BigDecimal S) { 651 throw new UnsupportedOperationException("BigDecimal.egcd() not implemented"); 652 } 653 654 655 /** 656 * BigDecimal random. 657 * @param n such that 0 ≤ val(r) ≤ (2<sup>n</sup>-1). 0 ≤ exp(r) 658 * ≤ (10-1). 659 * @return r, a random BigDecimal. 660 */ 661 public BigDecimal random(int n) { 662 return random(n, random); 663 } 664 665 666 /** 667 * BigDecimal random. 668 * @param n such that 0 ≤ val(r) ≤ (2<sup>n</sup>-1). 0 ≤ exp(r) 669 * ≤ (10-1). 670 * @param rnd is a source for random bits. 671 * @return r, a random BigDecimal. 672 */ 673 public BigDecimal random(int n, Random rnd) { 674 return random(n, 10, rnd); 675 } 676 677 678 /** 679 * BigDecimal random. 680 * @param n such that 0 ≤ val(r) ≤ (2<sup>n</sup>-1). 681 * @param e such that 0 ≤ exp(r) ≤ (e-1). 682 * @return r, a random BigDecimal. 683 */ 684 public BigDecimal random(int n, int e) { 685 return random(n, e, random); 686 } 687 688 689 /** 690 * BigDecimal random. 691 * @param n such that 0 ≤ val(r) ≤ (2<sup>n</sup>-1). 692 * @param e such that 0 ≤ exp(r) ≤ (e-1). 693 * @param rnd is a source for random bits. 694 * @return r, a random BigDecimal. 695 */ 696 public BigDecimal random(int n, int e, Random rnd) { 697 java.math.BigInteger r = new java.math.BigInteger(n, rnd); 698 if (rnd.nextBoolean()) { 699 r = r.negate(); 700 } 701 int scale = rnd.nextInt(e); 702 //if (rnd.nextBoolean()) { // not according to param spec 703 // scale = -scale; 704 //} 705 java.math.BigDecimal d = new java.math.BigDecimal(r, scale, context); 706 return new BigDecimal(d, context); 707 } 708 709 710 /** 711 * BigDecimal multiply. 712 * @param S BigDecimal. 713 * @return this*S. 714 */ 715 public BigDecimal multiply(BigDecimal S) { 716 return new BigDecimal(val.multiply(S.val, context), context); 717 } 718 719 720 /** 721 * BigDecimal summation. 722 * @param S BigDecimal. 723 * @return this+S. 724 */ 725 public BigDecimal sum(BigDecimal S) { 726 return new BigDecimal(val.add(S.val, context), context); 727 } 728 729 730 /** 731 * BigDecimal parse from String. 732 * @param s String. 733 * @return BigDecimal from s. 734 */ 735 public BigDecimal parse(String s) { 736 int i = s.indexOf("/"); 737 if (i < 0) { // i = 0 also error 738 return new BigDecimal(s, context); 739 } 740 String sd = s.substring(0,i); 741 String sn = s.substring(i+1); 742 //System.out.println("s = " + s + ", sd = " + sd + ", sn = " + sn); 743 BigDecimal dd = new BigDecimal(sd, context); 744 BigDecimal dn = new BigDecimal(sn, context); 745 return dd.divide(dn); 746 } 747 748 749 /** 750 * BigDecimal parse from Reader. 751 * @param r Reader. 752 * @return next BigDecimal from r. 753 */ 754 public BigDecimal parse(Reader r) { 755 return parse(StringUtil.nextString(r)); 756 } 757 758 759 /** 760 * Returns the number of bits in the representation of this BigDecimal, 761 * including a sign bit. For positive BigDecimal, this is equivalent to 762 * {@code val.unscaledValue().bitLength()}.) 763 * @return number of bits in the representation of this BigDecimal, 764 * including a sign bit. 765 */ 766 public long bitLength() { 767 long n = val.unscaledValue().bitLength(); 768 if (val.signum() < 0) { 769 n++; 770 } 771 n++; 772 n += BigInteger.bitLength(val.scale()); 773 return n; 774 } 775 776}