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