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 private final static Random random = new Random(); 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 public final MathContext context; 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 */ 059 public final static BigDecimal ZERO = new BigDecimal(java.math.BigDecimal.ZERO); 060 061 062 /** 063 * The constant 1. 064 */ 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. public java.math.BigDecimal getVal() { 194 * return val; } 195 */ 196 197 198 /** 199 * Get the corresponding element factory. 200 * @return factory for this Element. 201 * @see edu.jas.structure.Element#factory() 202 */ 203 public BigDecimal factory() { 204 return this; 205 } 206 207 208 /** 209 * Get a list of the generating elements. 210 * @return list of generators for the algebraic structure. 211 * @see edu.jas.structure.ElemFactory#generators() 212 */ 213 public List<BigDecimal> generators() { 214 List<BigDecimal> g = new ArrayList<BigDecimal>(1); 215 g.add(getONE()); 216 return g; 217 } 218 219 220 /** 221 * Is this structure finite or infinite. 222 * @return true if this structure is finite, else false. 223 * @see edu.jas.structure.ElemFactory#isFinite() <b>Note: </b> is actually 224 * finite but returns false. 225 */ 226 public boolean isFinite() { 227 return false; 228 } 229 230 231 /** 232 * Clone this. 233 * @see java.lang.Object#clone() 234 */ 235 @Override 236 public BigDecimal copy() { 237 return new BigDecimal(val, context); 238 } 239 240 241 /** 242 * Copy BigDecimal element c. 243 * @param c BigDecimal. 244 * @return a copy of c. 245 */ 246 public BigDecimal copy(BigDecimal c) { 247 return new BigDecimal(c.val, c.context); 248 } 249 250 251 /** 252 * Get the zero element. 253 * @return 0. 254 */ 255 public BigDecimal getZERO() { 256 return ZERO; 257 } 258 259 260 /** 261 * Get the one element. 262 * @return 1. 263 */ 264 public BigDecimal getONE() { 265 return ONE; 266 } 267 268 269 /** 270 * Get the decimal representation. 271 * @return decimal. 272 */ 273 public BigDecimal getDecimal() { 274 return this; 275 } 276 277 278 /** 279 * Get the rational representation. 280 * @return rational number. 281 */ 282 public BigRational getRational() { 283 return new BigRational(toString()); 284 } 285 286 287 /** 288 * Query if this ring is commutative. 289 * @return true. 290 */ 291 public boolean isCommutative() { 292 return true; 293 } 294 295 296 /** 297 * Query if this ring is associative. Floating point number addition is not 298 * associative, but multiplication is. 299 * @return true. 300 */ 301 public boolean isAssociative() { 302 return true; 303 } 304 305 306 /** 307 * Query if this ring is a field. 308 * @return true. 309 */ 310 public boolean isField() { 311 return true; 312 } 313 314 315 /** 316 * Characteristic of this ring. 317 * @return characteristic of this ring. 318 */ 319 public java.math.BigInteger characteristic() { 320 return java.math.BigInteger.ZERO; 321 } 322 323 324 /** 325 * Get a BigDecimal element from a math.BigDecimal. 326 * @param a math.BigDecimal. 327 * @return a as BigDecimal. 328 */ 329 public BigDecimal fromInteger(java.math.BigInteger a) { 330 return new BigDecimal(new java.math.BigDecimal(a), context); 331 } 332 333 334 /** 335 * Get a BigDecimal element from a math.BigDecimal. 336 * @param a math.BigDecimal. 337 * @return a as BigDecimal. 338 */ 339 public static BigDecimal valueOf(java.math.BigDecimal a) { 340 return new BigDecimal(a, DEFAULT_CONTEXT); 341 } 342 343 344 /** 345 * Get a BigDecimal element from long. 346 * @param a long. 347 * @return a as BigDecimal. 348 */ 349 public BigDecimal fromInteger(long a) { 350 return new BigDecimal(a, context); 351 } 352 353 354 /** 355 * Get a BigDecimal element from long. 356 * @param a long. 357 * @return a as BigDecimal. 358 */ 359 public static BigDecimal valueOf(long a) { 360 return new BigDecimal(a, DEFAULT_CONTEXT); 361 } 362 363 364 /** 365 * Is BigDecimal number zero. 366 * @return If this is 0 then true is returned, else false. 367 * @see edu.jas.structure.RingElem#isZERO() 368 */ 369 public boolean isZERO() { 370 if (EXACT_EQUAL) { 371 return val.compareTo(java.math.BigDecimal.ZERO) == 0; 372 } 373 return compareTo(ZERO) == 0; 374 } 375 376 377 /** 378 * Is BigDecimal number one. 379 * @see edu.jas.structure.RingElem#isONE() 380 */ 381 public boolean isONE() { 382 if (EXACT_EQUAL) { 383 return val.compareTo(java.math.BigDecimal.ONE) == 0; 384 } 385 return compareTo(ONE) == 0; 386 } 387 388 389 /** 390 * Is BigDecimal number unit. 391 * @see edu.jas.structure.RingElem#isUnit() 392 */ 393 public boolean isUnit() { 394 return (!isZERO()); 395 } 396 397 398 /** 399 * Get the String representation. 400 * @see java.lang.Object#toString() 401 */ 402 @Override 403 public String toString() { 404 //return val.toString() + "(ulp=" + val.ulp() + ")"; 405 return val.toString(); 406 } 407 408 409 /** 410 * Get this decimal as a <tt>double</tt>. 411 * @return the decimal as a <tt>double</tt> 412 * @see java.lang.Number#doubleValue() 413 */ 414 public double doubleValue() { 415 return val.doubleValue(); 416 } 417 418 419 /** 420 * Get a scripting compatible string representation. 421 * @return script compatible representation for this Element. 422 * @see edu.jas.structure.Element#toScript() 423 */ 424 @Override 425 public String toScript() { 426 // Python+Ruby case 427 return toString(); 428 } 429 430 431 /** 432 * Get a scripting compatible string representation of the factory. 433 * @return script compatible representation for this ElemFactory. 434 * @see edu.jas.structure.Element#toScriptFactory() 435 */ 436 @Override 437 public String toScriptFactory() { 438 // Python+Ruby case 439 return "DD()"; 440 } 441 442 443 /** 444 * Compare to BigDecimal b. Experimental, is hacked. 445 * @param b BigDecimal. 446 * @return 0 if abs(this-b) < epsilon, 1 if this > b, -1 if this < 447 * b. 448 */ 449 @Override 450 public int compareTo(BigDecimal b) { 451 //return compareToAbsolute(b); 452 //return compareToRelative(b); 453 return val.compareTo(b.val); 454 } 455 456 457 /** 458 * Compare absolute to BigDecimal b. Experimental, is hacked. 459 * @param b BigDecimal. 460 * @return 0 if abs(this-b) < epsilon, 1 if this > b, -1 if this < 461 * b. 462 */ 463 public int compareToAbsolute(BigDecimal b) { 464 //if (EXACT_EQUAL) { 465 // return val.compareTo(b.val); 466 //} 467 java.math.BigDecimal s = val.subtract(b.val, context); 468 java.math.BigDecimal u1 = val.ulp(); 469 java.math.BigDecimal u2 = b.val.ulp(); 470 int u = Math.min(u1.scale(), u2.scale()); 471 //System.out.println("u = " + u + ", s = " + s); 472 java.math.BigDecimal eps; 473 if (u <= 0) { 474 eps = u1.max(u2); 475 } else { 476 eps = u1.min(u2); 477 } 478 //eps = eps.movePointRight(1); 479 //System.out.println("ctx = " + context); 480 //System.out.println("eps = " + eps); 481 int t = s.abs().compareTo(eps); 482 if (t < 1) { 483 return 0; 484 } 485 return s.signum(); 486 } 487 488 489 /** 490 * Compare to relative BigDecimal b. Experimental, is hacked. 491 * @param b BigDecimal. 492 * @return 0 if abs(this-b)/max(this,b) < epsilon, 1 if this > b, -1 493 * if this < b. 494 */ 495 public int compareToRelative(BigDecimal b) { 496 //if (EXACT_EQUAL) { 497 // return val.compareTo(b.val); 498 //} 499 java.math.BigDecimal s = val.subtract(b.val, context); 500 java.math.BigDecimal u1 = val.ulp(); 501 java.math.BigDecimal u2 = b.val.ulp(); 502 int u = Math.min(u1.scale(), u2.scale()); 503 //System.out.println("u = " + u + ", s = " + s); 504 java.math.BigDecimal eps; 505 if (u <= 0) { 506 eps = u1.max(u2); 507 } else { 508 eps = u1.min(u2); 509 } 510 eps = eps.movePointRight(1); 511 //System.out.println("ctx = " + context); 512 //System.out.println("eps = " + eps); 513 java.math.BigDecimal m = val.abs().max(b.val.abs()); 514 int t; 515 if (m.compareTo(java.math.BigDecimal.ONE) <= 1) { 516 t = s.abs().compareTo(eps); 517 } else { 518 t = s.abs().divide(m, context).compareTo(eps); 519 } 520 if (t < 1) { 521 return 0; 522 } 523 return s.signum(); 524 } 525 526 527 /** 528 * Comparison with any other object. 529 * @see java.lang.Object#equals(java.lang.Object) 530 */ 531 @Override 532 public boolean equals(Object b) { 533 if (!(b instanceof BigDecimal)) { 534 return false; 535 } 536 BigDecimal bi = (BigDecimal) b; 537 if (EXACT_EQUAL) { 538 return val.equals(bi.val); 539 } 540 return compareTo(bi) == 0; 541 } 542 543 544 /** 545 * Hash code for this BigDecimal. 546 * @see java.lang.Object#hashCode() 547 */ 548 @Override 549 public int hashCode() { 550 return val.hashCode(); 551 } 552 553 554 /** 555 * Absolute value of this. 556 * @see edu.jas.structure.RingElem#abs() 557 */ 558 public BigDecimal abs() { 559 return new BigDecimal(val.abs(), context); 560 } 561 562 563 /* Negative value of this. 564 * @see edu.jas.structure.RingElem#negate() 565 */ 566 public BigDecimal negate() { 567 return new BigDecimal(val.negate(), context); 568 } 569 570 571 /** 572 * signum. 573 * @see edu.jas.structure.RingElem#signum() 574 */ 575 public int signum() { 576 return val.signum(); 577 } 578 579 580 /** 581 * BigDecimal subtract. 582 * @param S BigDecimal. 583 * @return this-S. 584 */ 585 public BigDecimal subtract(BigDecimal S) { 586 return new BigDecimal(val.subtract(S.val, context), context); 587 } 588 589 590 /** 591 * BigDecimal divide. 592 * @param S BigDecimal. 593 * @return this/S. 594 */ 595 public BigDecimal divide(BigDecimal S) { 596 return new BigDecimal(val.divide(S.val, context), context); 597 } 598 599 600 /** 601 * Integer inverse. R is a non-zero integer. S=1/R if defined else 0. 602 * @see edu.jas.structure.RingElem#inverse() 603 */ 604 public BigDecimal inverse() { 605 return ONE.divide(this); 606 } 607 608 609 /** 610 * BigDecimal remainder. 611 * @param S BigDecimal. 612 * @return this - (this/S)*S. 613 */ 614 public BigDecimal remainder(BigDecimal S) { 615 return new BigDecimal(val.remainder(S.val, context), context); 616 } 617 618 619 /** 620 * BigDecimal compute quotient and remainder. 621 * @param S BigDecimal. 622 * @return BigDecimal[] { q, r } with q = this/S and r = rem(this,S). 623 */ 624 public BigDecimal[] quotientRemainder(BigDecimal S) { 625 BigDecimal[] qr = new BigDecimal[2]; 626 java.math.BigDecimal[] C = val.divideAndRemainder(S.val, context); 627 qr[0] = new BigDecimal(C[0], context); 628 qr[1] = new BigDecimal(C[1], context); 629 return qr; 630 } 631 632 633 /** 634 * BigDecimal greatest common divisor. 635 * @param S BigDecimal. 636 * @return gcd(this,S). 637 */ 638 public BigDecimal gcd(BigDecimal S) { 639 throw new UnsupportedOperationException("BigDecimal.gcd() not implemented"); 640 //return new BigDecimal( val.gcd( S.val ) ); 641 } 642 643 644 /** 645 * BigDecimal extended greatest common divisor. 646 * @param S BigDecimal. 647 * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). 648 */ 649 public BigDecimal[] egcd(BigDecimal S) { 650 throw new UnsupportedOperationException("BigDecimal.egcd() not implemented"); 651 } 652 653 654 /** 655 * BigDecimal random. 656 * @param n such that 0 ≤ val(r) ≤ (2<sup>n</sup>-1). 0 ≤ exp(r) 657 * ≤ (10-1). 658 * @return r, a random BigDecimal. 659 */ 660 public BigDecimal random(int n) { 661 return random(n, random); 662 } 663 664 665 /** 666 * BigDecimal random. 667 * @param n such that 0 ≤ val(r) ≤ (2<sup>n</sup>-1). 0 ≤ exp(r) 668 * ≤ (10-1). 669 * @param rnd is a source for random bits. 670 * @return r, a random BigDecimal. 671 */ 672 public BigDecimal random(int n, Random rnd) { 673 return random(n, 10, rnd); 674 } 675 676 677 /** 678 * BigDecimal random. 679 * @param n such that 0 ≤ val(r) ≤ (2<sup>n</sup>-1). 680 * @param e such that 0 ≤ exp(r) ≤ (e-1). 681 * @return r, a random BigDecimal. 682 */ 683 public BigDecimal random(int n, int e) { 684 return random(n, e, random); 685 } 686 687 688 /** 689 * BigDecimal random. 690 * @param n such that 0 ≤ val(r) ≤ (2<sup>n</sup>-1). 691 * @param e such that 0 ≤ exp(r) ≤ (e-1). 692 * @param rnd is a source for random bits. 693 * @return r, a random BigDecimal. 694 */ 695 public BigDecimal random(int n, int e, Random rnd) { 696 java.math.BigInteger r = new java.math.BigInteger(n, rnd); 697 if (rnd.nextBoolean()) { 698 r = r.negate(); 699 } 700 int scale = rnd.nextInt(e); 701 //if (rnd.nextBoolean()) { // not according to param spec 702 // scale = -scale; 703 //} 704 java.math.BigDecimal d = new java.math.BigDecimal(r, scale, context); 705 return new BigDecimal(d, context); 706 } 707 708 709 /** 710 * BigDecimal multiply. 711 * @param S BigDecimal. 712 * @return this*S. 713 */ 714 public BigDecimal multiply(BigDecimal S) { 715 return new BigDecimal(val.multiply(S.val, context), context); 716 } 717 718 719 /** 720 * BigDecimal summation. 721 * @param S BigDecimal. 722 * @return this+S. 723 */ 724 public BigDecimal sum(BigDecimal S) { 725 return new BigDecimal(val.add(S.val, context), context); 726 } 727 728 729 /** 730 * BigDecimal parse from String. 731 * @param s String. 732 * @return Biginteger from s. 733 */ 734 public BigDecimal parse(String s) { 735 int i = s.indexOf("/"); 736 if (i < 0) { // i = 0 also error 737 return new BigDecimal(s, context); 738 } 739 String sd = s.substring(0,i); 740 String sn = s.substring(i+1); 741 //System.out.println("s = " + s + ", sd = " + sd + ", sn = " + sn); 742 BigDecimal dd = new BigDecimal(sd, context); 743 BigDecimal dn = new BigDecimal(sn, context); 744 return dd.divide(dn); 745 } 746 747 748 /** 749 * BigDecimal parse from Reader. 750 * @param r Reader. 751 * @return next Biginteger from r. 752 */ 753 public BigDecimal parse(Reader r) { 754 return parse(StringUtil.nextString(r)); 755 } 756 757 758 /** 759 * Returns the number of bits in the representation of this BigDecimal, 760 * including a sign bit. For positive BigDecimal, this is equivalent to 761 * {@code val.unscaledValue().bitLength()}.) 762 * @return number of bits in the representation of this BigDecimal, 763 * including a sign bit. 764 */ 765 public long bitLength() { 766 long n = val.unscaledValue().bitLength(); 767 if (val.signum() < 0) { 768 n++; 769 } 770 n++; 771 n += BigInteger.bitLength(val.scale()); 772 return n; 773 } 774 775}