001/* 002 * $Id$ 003 */ 004 005package edu.jas.arith; 006 007 008import java.io.Reader; 009import java.math.BigInteger; 010import java.util.ArrayList; 011import java.util.List; 012import java.util.Random; 013 014import org.apache.logging.log4j.Logger; 015import org.apache.logging.log4j.LogManager; 016 017import edu.jas.kern.StringUtil; 018import edu.jas.structure.GcdRingElem; 019import edu.jas.structure.RingFactory; 020import edu.jas.structure.StarRingElem; 021 022 023/** 024 * BigComplex class based on BigDecimal implementing the RingElem respectively 025 * the StarRingElem interface. Objects of this class are immutable. 026 * @author Heinz Kredel 027 */ 028public final class BigDecimalComplex implements StarRingElem<BigDecimalComplex>, 029 GcdRingElem<BigDecimalComplex>, RingFactory<BigDecimalComplex> { 030 031 032 /** 033 * Real part of the data structure. 034 */ 035 public final BigDecimal re; 036 037 038 /** 039 * Imaginary part of the data structure. 040 */ 041 public final BigDecimal im; 042 043 044 private final static Random random = new Random(); 045 046 047 private static final Logger logger = LogManager.getLogger(BigDecimalComplex.class); 048 049 050 /** 051 * The constant 0. 052 */ // depends on math context, should be in factory 053 public final static BigDecimalComplex ZERO = new BigDecimalComplex(); 054 055 056 /** 057 * The constant 1. 058 */ // depends on math context, should be in factory 059 public final static BigDecimalComplex ONE = new BigDecimalComplex(1l); 060 061 062 /** 063 * The constant i. 064 */ // depends on math context, should be in factory 065 public final static BigDecimalComplex I = new BigDecimalComplex(0l,1l); 066 067 068 /** 069 * The constructor creates a BigDecimalComplex object from two BigDecimal 070 * objects real and imaginary part. 071 * @param r real part. 072 * @param i imaginary part. 073 */ 074 public BigDecimalComplex(BigDecimal r, BigDecimal i) { 075 re = r; 076 im = i; 077 } 078 079 080 /** 081 * The constructor creates a BigDecimalComplex object with real part 0 and 082 * imaginary part 0. 083 */ 084 public BigDecimalComplex() { 085 this(0l); 086 } 087 088 089 /** 090 * The constructor creates a BigDecimalComplex object from a BigDecimal 091 * object as real part, the imaginary part is set to 0. 092 * @param r real part. 093 */ 094 public BigDecimalComplex(BigDecimal r) { 095 this(r, r.getZERO()); 096 } 097 098 099 /** 100 * The constructor creates a BigDecimalComplex object from a long element as 101 * real part, the imaginary part is set to 0. 102 * @param r real part. 103 */ 104 public BigDecimalComplex(long r) { 105 this(new BigDecimal(r)); 106 } 107 108 109 /** 110 * The constructor creates a BigDecimalComplex object from a long element as 111 * real part and the imaginary part. 112 * @param r real part. 113 * @param i imaginary part. 114 */ 115 public BigDecimalComplex(long r, long i) { 116 this(new BigDecimal(r), new BigDecimal(i)); 117 } 118 119 120 /** 121 * The constructor creates a BigDecimalComplex object from a String 122 * representation. 123 * @param s string of a BigDecimalComplex. 124 * @throws NumberFormatException 125 */ 126 public BigDecimalComplex(String s) throws NumberFormatException { 127 if (s == null || s.length() == 0) { 128 re = new BigDecimal(0l); 129 im = re.getZERO(); 130 return; 131 } 132 s = s.trim(); 133 int i = s.indexOf("i"); 134 if (i < 0) { 135 re = new BigDecimal(s); 136 im = re.getZERO(); 137 return; 138 } 139 //logger.warn("String constructor not done"); 140 String sr = ""; 141 if (i > 0) { 142 sr = s.substring(0, i); 143 } 144 String si = ""; 145 if (i < s.length()) { 146 si = s.substring(i + 1, s.length()); 147 } 148 //int j = sr.indexOf("+"); 149 re = new BigDecimal(sr.trim()); 150 im = new BigDecimal(si.trim()); 151 } 152 153 154 /** 155 * The constructor creates a BigDecimalComplex object from a BigComplex 156 * object. 157 * @param a rational BigComplex. 158 */ 159 public BigDecimalComplex(BigComplex a) { 160 this(new BigDecimal(a.re), new BigDecimal(a.im)); 161 } 162 163 164 /** 165 * Get the corresponding element factory. 166 * @return factory for this Element. 167 * @see edu.jas.structure.Element#factory() 168 */ 169 public BigDecimalComplex factory() { 170 return this; 171 } 172 173 174 /** 175 * Get a list of the generating elements. 176 * @return list of generators for the algebraic structure. 177 * @see edu.jas.structure.ElemFactory#generators() 178 */ 179 public List<BigDecimalComplex> generators() { 180 List<BigDecimalComplex> g = new ArrayList<BigDecimalComplex>(2); 181 g.add(getONE()); 182 g.add(getIMAG()); 183 return g; 184 } 185 186 187 /** 188 * Is this structure finite or infinite. 189 * @return true if this structure is finite, else false. 190 * @see edu.jas.structure.ElemFactory#isFinite() 191 */ 192 public boolean isFinite() { 193 return false; 194 } 195 196 197 /** 198 * Clone this. 199 * @see java.lang.Object#clone() 200 */ 201 @Override 202 public BigDecimalComplex copy() { 203 return new BigDecimalComplex(re, im); 204 } 205 206 207 /** 208 * Copy BigDecimalComplex element c. 209 * @param c BigDecimalComplex. 210 * @return a copy of c. 211 */ 212 public BigDecimalComplex copy(BigDecimalComplex c) { 213 return new BigDecimalComplex(c.re, c.im); 214 } 215 216 217 /** 218 * Get the zero element. 219 * @return 0 as BigDecimalComplex. 220 */ 221 public BigDecimalComplex getZERO() { 222 return ZERO; 223 } 224 225 226 /** 227 * Get the one element. 228 * @return 1 as BigDecimalComplex. 229 */ 230 public BigDecimalComplex getONE() { 231 return ONE; 232 } 233 234 235 /** 236 * Get the i element. 237 * @return i as BigDecimalComplex. 238 */ 239 public BigDecimalComplex getIMAG() { 240 return I; 241 } 242 243 244 /** 245 * Query if this ring is commutative. 246 * @return true. 247 */ 248 public boolean isCommutative() { 249 return true; 250 } 251 252 253 /** 254 * Query if this ring is associative. 255 * @return true. 256 */ 257 public boolean isAssociative() { 258 return true; 259 } 260 261 262 /** 263 * Query if this ring is a field. 264 * @return true. 265 */ 266 public boolean isField() { 267 return true; 268 } 269 270 271 /** 272 * Characteristic of this ring. 273 * @return characteristic of this ring. 274 */ 275 public java.math.BigInteger characteristic() { 276 return java.math.BigInteger.ZERO; 277 } 278 279 280 /** 281 * Get a BigDecimalComplex element from a BigInteger. 282 * @param a BigInteger. 283 * @return a BigDecimalComplex. 284 */ 285 public BigDecimalComplex fromInteger(BigInteger a) { 286 return new BigDecimalComplex(new BigDecimal(a)); 287 } 288 289 290 /** 291 * Get a BigDecimalComplex element from a long. 292 * @param a long. 293 * @return a BigDecimalComplex. 294 */ 295 public BigDecimalComplex fromInteger(long a) { 296 return new BigDecimalComplex(new BigDecimal(a)); 297 } 298 299 300 /** 301 * Get the real part. 302 * @return re. 303 */ 304 public BigDecimal getRe() { 305 return re; 306 } 307 308 309 /** 310 * Get the imaginary part. 311 * @return im. 312 */ 313 public BigDecimal getIm() { 314 return im; 315 } 316 317 318 /** 319 * Get the String representation. 320 */ 321 @Override 322 public String toString() { 323 String s = re.toString(); 324 //int i = im.compareTo(BigDecimal.ZERO); 325 //logger.info("compareTo {} ? 0 = {}", im, i); 326 if (im.isZERO()) { 327 return s; 328 } 329 s += "i" + im; 330 return s; 331 } 332 333 334 /** 335 * Get a scripting compatible string representation. 336 * @return script compatible representation for this Element. 337 * @see edu.jas.structure.Element#toScript() 338 */ 339 @Override 340 public String toScript() { 341 // Python case: re or re+im*i 342 // was (re,im) or (re,) 343 StringBuffer s = new StringBuffer(); 344 boolean iz = im.isZERO(); 345 if (iz) { 346 s.append(re.toScript()); 347 return s.toString(); 348 } 349 boolean rz = re.isZERO(); 350 if (rz) { 351 if (!im.isONE()) { 352 if (im.signum() > 0) { 353 s.append(im.toScript() + "*"); 354 } else { 355 s.append("-"); 356 BigDecimal ii = im.negate(); 357 if (!ii.isONE()) { 358 s.append(ii.toScript() + "*"); 359 } 360 } 361 } 362 } else { 363 s.append(re.toScript()); 364 if (im.signum() > 0) { 365 s.append("+"); 366 if (!im.isONE()) { 367 s.append(im.toScript() + "*"); 368 } 369 } else { 370 s.append("-"); 371 BigDecimal ii = im.negate(); 372 if (!ii.isONE()) { 373 s.append(ii.toScript() + "*"); 374 } 375 } 376 } 377 s.append("I"); 378 return s.toString(); 379 } 380 381 382 /** 383 * Get a scripting compatible string representation of the factory. 384 * @return script compatible representation for this ElemFactory. 385 * @see edu.jas.structure.Element#toScriptFactory() 386 */ 387 @Override 388 public String toScriptFactory() { 389 // Python case 390 return "CD()"; 391 } 392 393 394 /** 395 * Complex number zero. 396 * @param A is a complex number. 397 * @return If A is 0 then true is returned, else false. 398 */ 399 public static boolean isCZERO(BigDecimalComplex A) { 400 if (A == null) { 401 return false; 402 } 403 return A.isZERO(); 404 } 405 406 407 /** 408 * Is Complex number zero. 409 * @return If this is 0 then true is returned, else false. 410 * @see edu.jas.structure.RingElem#isZERO() 411 */ 412 public boolean isZERO() { 413 return re.isZERO() && im.isZERO(); 414 } 415 416 417 /** 418 * Complex number one. 419 * @param A is a complex number. 420 * @return If A is 1 then true is returned, else false. 421 */ 422 public static boolean isCONE(BigDecimalComplex A) { 423 if (A == null) { 424 return false; 425 } 426 return A.isONE(); 427 } 428 429 430 /** 431 * Is Complex number one. 432 * @return If this is 1 then true is returned, else false. 433 * @see edu.jas.structure.RingElem#isONE() 434 */ 435 public boolean isONE() { 436 return re.isONE() && im.isZERO(); 437 } 438 439 440 /** 441 * Is Complex imaginary one. 442 * @return If this is i then true is returned, else false. 443 */ 444 public boolean isIMAG() { 445 return re.isZERO() && im.isONE(); 446 } 447 448 449 /** 450 * Is Complex unit element. 451 * @return If this is a unit then true is returned, else false. 452 * @see edu.jas.structure.RingElem#isUnit() 453 */ 454 public boolean isUnit() { 455 return (!isZERO()); 456 } 457 458 459 /** 460 * Comparison with any other object. 461 * @see java.lang.Object#equals(java.lang.Object) 462 */ 463 @Override 464 public boolean equals(Object b) { 465 if (!(b instanceof BigDecimalComplex)) { 466 return false; 467 } 468 BigDecimalComplex bc = (BigDecimalComplex) b; 469 //return re.equals(bc.re) && im.equals(bc.im); 470 return re.compareTo(bc.re) == 0 && im.compareTo(bc.im) == 0; 471 } 472 473 474 /** 475 * Hash code for this BigDecimalComplex. 476 * @see java.lang.Object#hashCode() 477 */ 478 @Override 479 public int hashCode() { 480 return 37 * re.hashCode() + im.hashCode(); 481 } 482 483 484 /** 485 * Since complex numbers are unordered, we use lexicographical order of re 486 * and im. 487 * @return 0 if this is equal to b; 1 if re > b.re, or re == b.re and im 488 * > b.im; -1 if re < b.re, or re == b.re and im < b.im 489 */ 490 @Override 491 public int compareTo(BigDecimalComplex b) { 492 int s = re.compareTo(b.re); 493 //System.out.println("compareTo(a.re,b.re) = " + s); 494 if (s != 0) { 495 return s; 496 } 497 s = im.compareTo(b.im); 498 //System.out.println("compareTo(a.im,b.im) = " + s); 499 return s; 500 } 501 502 503 /** 504 * Since complex numbers are unordered, we use lexicographical order of re 505 * and im. 506 * @return 0 if this is equal to 0; 1 if re > 0, or re == 0 and im > 507 * 0; -1 if re < 0, or re == 0 and im < 0 508 * @see edu.jas.structure.RingElem#signum() 509 */ 510 public int signum() { 511 int s = re.signum(); 512 if (s != 0) { 513 return s; 514 } 515 return im.signum(); 516 } 517 518 519 /* arithmetic operations: +, -, - 520 */ 521 522 /** 523 * Complex number summation. 524 * @param B a BigDecimalComplex number. 525 * @return this+B. 526 */ 527 public BigDecimalComplex sum(BigDecimalComplex B) { 528 return new BigDecimalComplex(re.sum(B.re), im.sum(B.im)); 529 } 530 531 532 /** 533 * Complex number sum. 534 * @param A and B are complex numbers. 535 * @return A+B. 536 */ 537 public static BigDecimalComplex CSUM(BigDecimalComplex A, BigDecimalComplex B) { 538 if (A == null) { 539 return null; 540 } 541 return A.sum(B); 542 } 543 544 545 /** 546 * Complex number difference. 547 * @param A and B are complex numbers. 548 * @return A-B. 549 */ 550 public static BigDecimalComplex CDIF(BigDecimalComplex A, BigDecimalComplex B) { 551 if (A == null) { 552 return null; 553 } 554 return A.subtract(B); 555 } 556 557 558 /** 559 * Complex number subtract. 560 * @param B a BigDecimalComplex number. 561 * @return this-B. 562 */ 563 public BigDecimalComplex subtract(BigDecimalComplex B) { 564 return new BigDecimalComplex(re.subtract(B.re), im.subtract(B.im)); 565 } 566 567 568 /** 569 * Complex number negative. 570 * @param A is a complex number. 571 * @return -A 572 */ 573 public static BigDecimalComplex CNEG(BigDecimalComplex A) { 574 if (A == null) { 575 return null; 576 } 577 return A.negate(); 578 } 579 580 581 /** 582 * Complex number negative. 583 * @return -this. 584 * @see edu.jas.structure.RingElem#negate() 585 */ 586 public BigDecimalComplex negate() { 587 return new BigDecimalComplex(re.negate(), im.negate()); 588 } 589 590 591 /** 592 * Complex number conjugate. 593 * @param A is a complex number. 594 * @return the complex conjugate of A. 595 */ 596 public static BigDecimalComplex CCON(BigDecimalComplex A) { 597 if (A == null) { 598 return null; 599 } 600 return A.conjugate(); 601 } 602 603 604 /* arithmetic operations: conjugate, absolute value 605 */ 606 607 /** 608 * Complex number conjugate. 609 * @return the complex conjugate of this. 610 */ 611 public BigDecimalComplex conjugate() { 612 return new BigDecimalComplex(re, im.negate()); 613 } 614 615 616 /** 617 * Complex number norm. 618 * @see edu.jas.structure.StarRingElem#norm() 619 * @return ||this||. 620 */ 621 public BigDecimalComplex norm() { 622 // this.multiply(this.conjugate()); 623 BigDecimal v = re.multiply(re); 624 if (!im.isZERO()) { 625 v = v.sum(im.multiply(im)); 626 } 627 return new BigDecimalComplex(v); 628 } 629 630 631 /** 632 * Complex number absolute value. 633 * @see edu.jas.structure.RingElem#abs() 634 * @return |this|. 635 */ 636 public BigDecimalComplex abs() { 637 if (im.isZERO()) { 638 return new BigDecimalComplex(re.abs()); 639 } 640 BigDecimalComplex n = norm(); 641 BigDecimal d = Roots.sqrt(n.re); 642 logger.debug("sqrt(re) = {}", d); 643 return new BigDecimalComplex(d); 644 } 645 646 647 /** 648 * Complex number absolute value. 649 * @param A is a complex number. 650 * @return the absolute value of A, a rational number. Note: The square root 651 * is not jet implemented. 652 */ 653 public static BigDecimal CABS(BigDecimalComplex A) { 654 if (A == null) { 655 return null; 656 } 657 return A.abs().re; 658 } 659 660 661 /** 662 * Complex number product. 663 * @param A and B are complex numbers. 664 * @return A*B. 665 */ 666 public static BigDecimalComplex CPROD(BigDecimalComplex A, BigDecimalComplex B) { 667 if (A == null) { 668 return null; 669 } 670 return A.multiply(B); 671 } 672 673 674 /* arithmetic operations: *, inverse, / 675 */ 676 677 678 /** 679 * Complex number product. 680 * @param B is a complex number. 681 * @return this*B. 682 */ 683 public BigDecimalComplex multiply(BigDecimalComplex B) { 684 return new BigDecimalComplex(re.multiply(B.re).subtract(im.multiply(B.im)), re.multiply(B.im).sum( 685 im.multiply(B.re))); 686 } 687 688 689 /** 690 * Complex number inverse. 691 * @param A is a non-zero complex number. 692 * @return S with S*A = 1. 693 */ 694 public static BigDecimalComplex CINV(BigDecimalComplex A) { 695 if (A == null) { 696 return null; 697 } 698 return A.inverse(); 699 } 700 701 702 /** 703 * Complex number inverse. 704 * @return S with S*this = 1. 705 * @see edu.jas.structure.RingElem#inverse() 706 */ 707 public BigDecimalComplex inverse() { 708 BigDecimal a = norm().re.inverse(); 709 return new BigDecimalComplex(re.multiply(a), im.multiply(a.negate())); 710 } 711 712 713 /** 714 * Complex number inverse. 715 * @param S is a complex number. 716 * @return 0. 717 */ 718 public BigDecimalComplex remainder(BigDecimalComplex S) { 719 if (S.isZERO()) { 720 throw new ArithmeticException("division by zero"); 721 } 722 return ZERO; 723 } 724 725 726 /** 727 * Complex number quotient. 728 * @param A and B are complex numbers, B non-zero. 729 * @return A/B. 730 */ 731 public static BigDecimalComplex CQ(BigDecimalComplex A, BigDecimalComplex B) { 732 if (A == null) { 733 return null; 734 } 735 return A.divide(B); 736 } 737 738 739 /** 740 * Complex number divide. 741 * @param B is a complex number, non-zero. 742 * @return this/B. 743 */ 744 public BigDecimalComplex divide(BigDecimalComplex B) { 745 return this.multiply(B.inverse()); 746 } 747 748 749 /** 750 * Quotient and remainder by division of this by S. 751 * @param S a complex number 752 * @return [this/S, this - (this/S)*S]. 753 */ 754 public BigDecimalComplex[] quotientRemainder(BigDecimalComplex S) { 755 return new BigDecimalComplex[] { divide(S), ZERO }; 756 } 757 758 759 /** 760 * Complex number, random. Random rational numbers A and B are generated 761 * using random(n). Then R is the complex number with real part A and 762 * imaginary part B. 763 * @param n such that 0 ≤ A, B ≤ (2<sup>n</sup>-1). 764 * @return R. 765 */ 766 public BigDecimalComplex random(int n) { 767 return random(n, random); 768 } 769 770 771 /** 772 * Complex number, random. Random rational numbers A and B are generated 773 * using random(n). Then R is the complex number with real part A and 774 * imaginary part B. 775 * @param n such that 0 ≤ A, B ≤ (2<sup>n</sup>-1). 776 * @param rnd is a source for random bits. 777 * @return R. 778 */ 779 public BigDecimalComplex random(int n, Random rnd) { 780 BigDecimal r = ZERO.re.random(n, rnd); 781 BigDecimal i = ZERO.re.random(n, rnd); 782 return new BigDecimalComplex(r, i); 783 } 784 785 786 /** 787 * Complex number, random. Random rational numbers A and B are generated 788 * using random(n). Then R is the complex number with real part A and 789 * imaginary part B. 790 * @param n such that 0 ≤ A, B ≤ (2<sup>n</sup>-1). 791 * @return R. 792 */ 793 public static BigDecimalComplex CRAND(int n) { 794 return new BigDecimalComplex().random(n, random); 795 } 796 797 798 /** 799 * Parse complex number from string. 800 * @param s String. 801 * @return BigDecimalComplex from s. 802 */ 803 public BigDecimalComplex parse(String s) { 804 return new BigDecimalComplex(s); 805 } 806 807 808 /** 809 * Parse complex number from Reader. 810 * @param r Reader. 811 * @return next BigDecimalComplex from r. 812 */ 813 public BigDecimalComplex parse(Reader r) { 814 return parse(StringUtil.nextString(r)); 815 } 816 817 818 /** 819 * Complex number greatest common divisor. 820 * @param S BigDecimalComplex. 821 * @return gcd(this,S). 822 */ 823 public BigDecimalComplex gcd(BigDecimalComplex S) { 824 if (S == null || S.isZERO()) { 825 return this; 826 } 827 if (this.isZERO()) { 828 return S; 829 } 830 return ONE; 831 } 832 833 834 /** 835 * BigDecimalComplex extended greatest common divisor. 836 * @param S BigDecimalComplex. 837 * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). 838 */ 839 public BigDecimalComplex[] egcd(BigDecimalComplex S) { 840 BigDecimalComplex[] ret = new BigDecimalComplex[3]; 841 ret[0] = null; 842 ret[1] = null; 843 ret[2] = null; 844 if (S == null || S.isZERO()) { 845 ret[0] = this; 846 return ret; 847 } 848 if (this.isZERO()) { 849 ret[0] = S; 850 return ret; 851 } 852 BigDecimalComplex half = fromInteger(2).inverse(); 853 ret[0] = ONE; 854 ret[1] = this.inverse().multiply(half); 855 ret[2] = S.inverse().multiply(half); 856 return ret; 857 } 858 859 860 /** 861 * Returns the number of bits in the representation of this 862 * BigDecimalComplex, including a sign bit. It is equivalent to 863 * {@code re.bitLength() + im.bitLength()}.) 864 * @return number of bits in the representation of this BigDecimalComplex, 865 * including a sign bit. 866 */ 867 public long bitLength() { 868 return re.bitLength() + im.bitLength(); 869 } 870 871}