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