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 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 return val.compareTo(b.val); 435 } 436 437 438 /** 439 * Compare absolute to BigDecimal b. Experimental, is hacked. 440 * @param b BigDecimal. 441 * @return 0 if abs(this-b) < epsilon, 1 if this > b, -1 if this < 442 * b. 443 */ 444 public int compareToAbsolute(BigDecimal b) { 445 //if (EXACT_EQUAL) { 446 // return val.compareTo(b.val); 447 //} 448 java.math.BigDecimal s = val.subtract(b.val, context); 449 java.math.BigDecimal u1 = val.ulp(); 450 java.math.BigDecimal u2 = b.val.ulp(); 451 int u = Math.min(u1.scale(), u2.scale()); 452 //System.out.println("u = " + u + ", s = " + s); 453 java.math.BigDecimal eps; 454 if (u <= 0) { 455 eps = u1.max(u2); 456 } else { 457 eps = u1.min(u2); 458 } 459 //eps = eps.movePointRight(1); 460 //System.out.println("ctx = " + context); 461 //System.out.println("eps = " + eps); 462 int t = s.abs().compareTo(eps); 463 if (t < 1) { 464 return 0; 465 } 466 return s.signum(); 467 } 468 469 470 /** 471 * Compare to relative BigDecimal b. Experimental, is hacked. 472 * @param b BigDecimal. 473 * @return 0 if abs(this-b)/max(this,b) < epsilon, 1 if this > b, -1 474 * if this < b. 475 */ 476 public int compareToRelative(BigDecimal b) { 477 //if (EXACT_EQUAL) { 478 // return val.compareTo(b.val); 479 //} 480 java.math.BigDecimal s = val.subtract(b.val, context); 481 java.math.BigDecimal u1 = val.ulp(); 482 java.math.BigDecimal u2 = b.val.ulp(); 483 int u = Math.min(u1.scale(), u2.scale()); 484 //System.out.println("u = " + u + ", s = " + s); 485 java.math.BigDecimal eps; 486 if (u <= 0) { 487 eps = u1.max(u2); 488 } else { 489 eps = u1.min(u2); 490 } 491 eps = eps.movePointRight(1); 492 //System.out.println("ctx = " + context); 493 //System.out.println("eps = " + eps); 494 java.math.BigDecimal m = val.abs().max(b.val.abs()); 495 int t; 496 if (m.compareTo(java.math.BigDecimal.ONE) <= 1) { 497 t = s.abs().compareTo(eps); 498 } else { 499 t = s.abs().divide(m, context).compareTo(eps); 500 } 501 if (t < 1) { 502 return 0; 503 } 504 return s.signum(); 505 } 506 507 508 /** 509 * Comparison with any other object. 510 * @see java.lang.Object#equals(java.lang.Object) 511 */ 512 @Override 513 public boolean equals(Object b) { 514 if (!(b instanceof BigDecimal)) { 515 return false; 516 } 517 BigDecimal bi = (BigDecimal) b; 518 if (EXACT_EQUAL) { 519 return val.equals(bi.val); 520 } 521 return compareTo(bi) == 0; 522 } 523 524 525 /** 526 * Hash code for this BigDecimal. 527 * @see java.lang.Object#hashCode() 528 */ 529 @Override 530 public int hashCode() { 531 return val.hashCode(); 532 } 533 534 535 /** 536 * Absolute value of this. 537 * @see edu.jas.structure.RingElem#abs() 538 */ 539 public BigDecimal abs() { 540 return new BigDecimal(val.abs(), context); 541 } 542 543 544 /* Negative value of this. 545 * @see edu.jas.structure.RingElem#negate() 546 */ 547 public BigDecimal negate() { 548 return new BigDecimal(val.negate(), context); 549 } 550 551 552 /** 553 * signum. 554 * @see edu.jas.structure.RingElem#signum() 555 */ 556 public int signum() { 557 return val.signum(); 558 } 559 560 561 /** 562 * BigDecimal subtract. 563 * @param S BigDecimal. 564 * @return this-S. 565 */ 566 public BigDecimal subtract(BigDecimal S) { 567 return new BigDecimal(val.subtract(S.val, context), context); 568 } 569 570 571 /** 572 * BigDecimal divide. 573 * @param S BigDecimal. 574 * @return this/S. 575 */ 576 public BigDecimal divide(BigDecimal S) { 577 return new BigDecimal(val.divide(S.val, context), context); 578 } 579 580 581 /** 582 * Integer inverse. R is a non-zero integer. S=1/R if defined else 0. 583 * @see edu.jas.structure.RingElem#inverse() 584 */ 585 public BigDecimal inverse() { 586 return ONE.divide(this); 587 } 588 589 590 /** 591 * BigDecimal remainder. 592 * @param S BigDecimal. 593 * @return this - (this/S)*S. 594 */ 595 public BigDecimal remainder(BigDecimal S) { 596 return new BigDecimal(val.remainder(S.val, context), context); 597 } 598 599 600 /** 601 * BigDecimal compute quotient and remainder. 602 * @param S BigDecimal. 603 * @return BigDecimal[] { q, r } with q = this/S and r = rem(this,S). 604 */ 605 public BigDecimal[] quotientRemainder(BigDecimal S) { 606 BigDecimal[] qr = new BigDecimal[2]; 607 java.math.BigDecimal[] C = val.divideAndRemainder(S.val, context); 608 qr[0] = new BigDecimal(C[0], context); 609 qr[1] = new BigDecimal(C[1], context); 610 return qr; 611 } 612 613 614 /** 615 * BigDecimal greatest common divisor. 616 * @param S BigDecimal. 617 * @return gcd(this,S). 618 */ 619 public BigDecimal gcd(BigDecimal S) { 620 throw new UnsupportedOperationException("BigDecimal.gcd() not implemented"); 621 //return new BigDecimal( val.gcd( S.val ) ); 622 } 623 624 625 /** 626 * BigDecimal extended greatest common divisor. 627 * @param S BigDecimal. 628 * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). 629 */ 630 public BigDecimal[] egcd(BigDecimal S) { 631 throw new UnsupportedOperationException("BigDecimal.egcd() not implemented"); 632 } 633 634 635 /** 636 * BigDecimal random. 637 * @param n such that 0 ≤ val(r) ≤ (2<sup>n</sup>-1). 0 ≤ exp(r) 638 * ≤ (10-1). 639 * @return r, a random BigDecimal. 640 */ 641 public BigDecimal random(int n) { 642 return random(n, random); 643 } 644 645 646 /** 647 * BigDecimal random. 648 * @param n such that 0 ≤ val(r) ≤ (2<sup>n</sup>-1). 0 ≤ exp(r) 649 * ≤ (10-1). 650 * @param rnd is a source for random bits. 651 * @return r, a random BigDecimal. 652 */ 653 public BigDecimal random(int n, Random rnd) { 654 return random(n, 10, rnd); 655 } 656 657 658 /** 659 * BigDecimal random. 660 * @param n such that 0 ≤ val(r) ≤ (2<sup>n</sup>-1). 661 * @param e such that 0 ≤ exp(r) ≤ (e-1). 662 * @return r, a random BigDecimal. 663 */ 664 public BigDecimal random(int n, int e) { 665 return random(n, e, random); 666 } 667 668 669 /** 670 * BigDecimal random. 671 * @param n such that 0 ≤ val(r) ≤ (2<sup>n</sup>-1). 672 * @param e such that 0 ≤ exp(r) ≤ (e-1). 673 * @param rnd is a source for random bits. 674 * @return r, a random BigDecimal. 675 */ 676 public BigDecimal random(int n, int e, Random rnd) { 677 java.math.BigInteger r = new java.math.BigInteger(n, rnd); 678 if (rnd.nextBoolean()) { 679 r = r.negate(); 680 } 681 int scale = rnd.nextInt(e); 682 //if (rnd.nextBoolean()) { // not according to param spec 683 // scale = -scale; 684 //} 685 java.math.BigDecimal d = new java.math.BigDecimal(r, scale, context); 686 return new BigDecimal(d, context); 687 } 688 689 690 /** 691 * BigDecimal multiply. 692 * @param S BigDecimal. 693 * @return this*S. 694 */ 695 public BigDecimal multiply(BigDecimal S) { 696 return new BigDecimal(val.multiply(S.val, context), context); 697 } 698 699 700 /** 701 * BigDecimal summation. 702 * @param S BigDecimal. 703 * @return this+S. 704 */ 705 public BigDecimal sum(BigDecimal S) { 706 return new BigDecimal(val.add(S.val, context), context); 707 } 708 709 710 /** 711 * BigDecimal parse from String. 712 * @param s String. 713 * @return Biginteger from s. 714 */ 715 public BigDecimal parse(String s) { 716 return new BigDecimal(s, context); 717 } 718 719 720 /** 721 * BigDecimal parse from Reader. 722 * @param r Reader. 723 * @return next Biginteger from r. 724 */ 725 public BigDecimal parse(Reader r) { 726 return parse(StringUtil.nextString(r)); 727 } 728 729 730 /** 731 * Returns the number of bits in the representation of this BigDecimal, 732 * including a sign bit. For positive BigDecimal, this is equivalent to 733 * {@code val.unscaledValue().bitLength()}.) 734 * @return number of bits in the representation of this BigDecimal, 735 * including a sign bit. 736 */ 737 public long bitLength() { 738 long n = val.unscaledValue().bitLength(); 739 if (val.signum() < 0) { 740 n++; 741 } 742 n++; 743 n += BigInteger.bitLength(val.scale()); 744 return n; 745 } 746 747}