001/* 002 * $Id$ 003 */ 004 005package edu.jas.arith; 006 007 008import java.util.List; 009import java.util.Random; 010 011import org.apache.logging.log4j.LogManager; 012import org.apache.logging.log4j.Logger; 013 014import edu.jas.structure.GcdRingElem; 015import edu.jas.structure.StarRingElem; 016 017 018/** 019 * BigQuaternion class based on BigRational implementing the RingElem interface 020 * and with the familiar MAS static method names. Objects of this class are 021 * immutable. The integer quaternion methods are implemented after 022 * https://de.wikipedia.org/wiki/Hurwitzquaternion see also 023 * https://en.wikipedia.org/wiki/Hurwitz_quaternion 024 * @author Heinz Kredel 025 */ 026 027public /*final*/ class BigQuaternion implements StarRingElem<BigQuaternion>, GcdRingElem<BigQuaternion> { 028 029 030 /** 031 * Real part of the data structure. 032 */ 033 public final BigRational re; // real part 034 035 036 /** 037 * Imaginary part i of the data structure. 038 */ 039 public final BigRational im; // i imaginary part 040 041 042 /** 043 * Imaginary part j of the data structure. 044 */ 045 public final BigRational jm; // j imaginary part 046 047 048 /** 049 * Imaginary part k of the data structure. 050 */ 051 public final BigRational km; // k imaginary part 052 053 054 /** 055 * Corresponding BigQuaternion ring. 056 */ 057 public final BigQuaternionRing ring; 058 059 060 protected final static Random random = new Random(); 061 062 063 private static final Logger logger = LogManager.getLogger(BigQuaternion.class); 064 065 066 private static final boolean debug = logger.isDebugEnabled(); 067 068 069 /** 070 * Constructor for a BigQuaternion from BigRationals. 071 * @param fac BigQuaternionRing. 072 * @param r BigRational. 073 * @param i BigRational. 074 * @param j BigRational. 075 * @param k BigRational. 076 */ 077 public BigQuaternion(BigQuaternionRing fac, BigRational r, BigRational i, BigRational j, BigRational k) { 078 ring = fac; 079 re = r; 080 im = i; 081 jm = j; 082 km = k; 083 } 084 085 086 /** 087 * Constructor for a BigQuaternion from BigRationals. 088 * @param fac BigQuaternionRing. 089 * @param r BigRational. 090 * @param i BigRational. 091 * @param j BigRational. 092 */ 093 public BigQuaternion(BigQuaternionRing fac, BigRational r, BigRational i, BigRational j) { 094 this(fac, r, i, j, BigRational.ZERO); 095 } 096 097 098 /** 099 * Constructor for a BigQuaternion from BigRationals. 100 * @param fac BigQuaternionRing. 101 * @param r BigRational. 102 * @param i BigRational. 103 */ 104 public BigQuaternion(BigQuaternionRing fac, BigRational r, BigRational i) { 105 this(fac, r, i, BigRational.ZERO); 106 } 107 108 109 /** 110 * Constructor for a BigQuaternion from BigRationals. 111 * @param fac BigQuaternionRing. 112 * @param r BigRational. 113 */ 114 public BigQuaternion(BigQuaternionRing fac, BigRational r) { 115 this(fac, r, BigRational.ZERO); 116 } 117 118 119 /** 120 * Constructor for a BigQuaternion from BigComplex. 121 * @param fac BigQuaternionRing. 122 * @param r BigComplex. 123 */ 124 public BigQuaternion(BigQuaternionRing fac, BigComplex r) { 125 this(fac, r.re, r.im); 126 } 127 128 129 /** 130 * Constructor for a BigQuaternion from long. 131 * @param fac BigQuaternionRing. 132 * @param r long. 133 */ 134 public BigQuaternion(BigQuaternionRing fac, long r) { 135 this(fac, new BigRational(r), BigRational.ZERO); 136 } 137 138 139 /** 140 * Constructor for a BigQuaternion with no arguments. 141 * @param fac BigQuaternionRing. 142 */ 143 public BigQuaternion(BigQuaternionRing fac) { 144 this(fac, BigRational.ZERO); 145 } 146 147 148 /** 149 * The BigQuaternion string constructor accepts the following formats: empty 150 * string, "rational", or "rat i rat j rat k rat" with no blanks around i, j 151 * or k if used as polynoial coefficient. 152 * @param fac BigQuaternionRing. 153 * @param s String. 154 * @throws NumberFormatException 155 */ 156 public BigQuaternion(BigQuaternionRing fac, String s) throws NumberFormatException { 157 ring = fac; 158 if (s == null || s.length() == 0) { 159 re = BigRational.ZERO; 160 im = BigRational.ZERO; 161 jm = BigRational.ZERO; 162 km = BigRational.ZERO; 163 return; 164 } 165 //System.out.println("init: s = " + s); 166 s = s.trim(); 167 int r = s.indexOf("i") + s.indexOf("j") + s.indexOf("k"); 168 if (r == -3) { 169 re = new BigRational(s); 170 im = BigRational.ZERO; 171 jm = BigRational.ZERO; 172 km = BigRational.ZERO; 173 return; 174 } 175 176 s = s.replaceAll("~", "-"); // when used with GenPolynomialTokenizer 177 int i = s.indexOf("i"); 178 String sr = ""; 179 if (i > 0) { 180 sr = s.substring(0, i); 181 } else if (i < 0) { 182 throw new NumberFormatException("BigQuaternion missing i: " + s); 183 } 184 String si = ""; 185 if (i < s.length()) { 186 s = s.substring(i + 1, s.length()); 187 } 188 int j = s.indexOf("j"); 189 if (j > 0) { 190 si = s.substring(0, j); 191 } else if (j < 0) { 192 throw new NumberFormatException("BigQuaternion missing j: " + s); 193 } 194 String sj = ""; 195 if (j < s.length()) { 196 s = s.substring(j + 1, s.length()); 197 } 198 int k = s.indexOf("k"); 199 if (k > 0) { 200 sj = s.substring(0, k); 201 } else if (k < 0) { 202 throw new NumberFormatException("BigQuaternion missing k: " + s); 203 } 204 String sk = ""; 205 if (k < s.length()) { 206 s = s.substring(k + 1, s.length()); 207 } 208 sk = s; 209 210 re = new BigRational(sr.trim()); 211 im = new BigRational(si.trim()); 212 jm = new BigRational(sj.trim()); 213 km = new BigRational(sk.trim()); 214 } 215 216 217 /** 218 * Get the corresponding element factory. 219 * @return factory for this Element. 220 * @see edu.jas.structure.Element#factory() 221 */ 222 public BigQuaternionRing factory() { 223 return ring; 224 } 225 226 227 /** 228 * Clone this. 229 * @see java.lang.Object#clone() 230 */ 231 @Override 232 public BigQuaternion copy() { 233 return new BigQuaternion(ring, re, im, jm, km); 234 } 235 236 237 /** 238 * Get the real part. 239 * @return re. 240 */ 241 public BigRational getRe() { 242 return re; 243 } 244 245 246 /** 247 * Get the imaginary part im. 248 * @return im. 249 */ 250 public BigRational getIm() { 251 return im; 252 } 253 254 255 /** 256 * Get the imaginary part jm. 257 * @return jm. 258 */ 259 public BigRational getJm() { 260 return jm; 261 } 262 263 264 /** 265 * Get the imaginary part km. 266 * @return km. 267 */ 268 public BigRational getKm() { 269 return km; 270 } 271 272 273 /** 274 * Get the string representation. Is compatible with the string constructor. 275 * @see java.lang.Object#toString() 276 */ 277 @Override 278 public String toString() { 279 StringBuffer sb = new StringBuffer(); 280 int r = re.compareTo(BigRational.ZERO); 281 if (r != 0) { 282 sb.append(re.toString()); 283 } 284 int i = im.compareTo(BigRational.ZERO); 285 int j = jm.compareTo(BigRational.ZERO); 286 int k = km.compareTo(BigRational.ZERO); 287 if (debug) { 288 logger.debug("compareTo {} ? 0 = {}", im, i); 289 logger.debug("compareTo {} ? 0 = {}", jm, j); 290 logger.debug("compareTo {} ? 0 = {}", km, k); 291 } 292 if (i == 0 && j == 0 && k == 0) { 293 if (r == 0) { 294 sb.append(re.toString()); 295 } 296 return sb.toString(); 297 } 298 if (i != 0) { 299 sb.append("i" + im); 300 } 301 if (j != 0) { 302 sb.append("j" + jm); 303 } 304 if (k != 0) { 305 sb.append("k" + km); 306 } 307 String s = sb.toString(); 308 //s = s.replaceAll("-","~"); 309 return s; 310 } 311 312 313 /** 314 * Get a scripting compatible string representation. 315 * @return script compatible representation for this Element. 316 * @see edu.jas.structure.Element#toScript() 317 */ 318 @Override 319 public String toScript() { 320 // Python case 321 StringBuffer s = new StringBuffer(); 322 boolean i = im.isZERO(); 323 boolean j = jm.isZERO(); 324 boolean k = km.isZERO(); 325 if (i && j && k) { 326 if (re.isZERO()) { 327 return "0 "; 328 } 329 if (!re.isONE()) { 330 s.append(re.toScript() + "*"); 331 } 332 s.append("oneQ "); 333 return s.toString(); 334 } 335 if (!re.isZERO()) { 336 if (!re.isONE()) { 337 s.append(re.toScript() + "*"); 338 } 339 s.append("oneQ "); 340 } 341 if (!i) { 342 if (s.length() > 0) { 343 s.append("+ "); 344 } 345 if (!im.isONE()) { 346 s.append(im.toScript() + "*"); 347 } 348 s.append("IQ "); 349 } 350 if (!j) { 351 if (s.length() > 0) { 352 s.append("+ "); 353 } 354 if (!jm.isONE()) { 355 s.append(jm.toScript() + "*"); 356 } 357 s.append("JQ "); 358 } 359 if (!k) { 360 if (s.length() > 0) { 361 s.append("+ "); 362 } 363 if (!km.isONE()) { 364 s.append(km.toScript() + "*"); 365 } 366 s.append("KQ "); 367 } 368 return s.toString(); 369 } 370 371 372 /** 373 * Get a scripting compatible string representation of the factory. 374 * @return script compatible representation for this ElemFactory. 375 * @see edu.jas.structure.Element#toScriptFactory() 376 */ 377 @Override 378 public String toScriptFactory() { 379 // Python case 380 return ring.toScript(); 381 } 382 383 384 /** 385 * Is Quaternion number zero. 386 * @param A BigQuaternion. 387 * @return true if A is 0, else false. 388 */ 389 public static boolean isQZERO(BigQuaternion A) { 390 if (A == null) 391 return false; 392 return A.isZERO(); 393 } 394 395 396 /** 397 * Is BigQuaternion number zero. 398 * @return true if this is 0, else false. 399 * @see edu.jas.structure.RingElem#isZERO() 400 */ 401 public boolean isZERO() { 402 return re.isZERO() && im.isZERO() && jm.isZERO() && km.isZERO(); 403 } 404 405 406 /** 407 * Is BigQuaternion number one. 408 * @param A is a quaternion number. 409 * @return true if A is 1, else false. 410 */ 411 public static boolean isQONE(BigQuaternion A) { 412 if (A == null) 413 return false; 414 return A.isONE(); 415 } 416 417 418 /** 419 * Is BigQuaternion number one. 420 * @see edu.jas.structure.RingElem#isONE() 421 * @return true if this is 1, else false. 422 */ 423 public boolean isONE() { 424 return re.isONE() && im.isZERO() && jm.isZERO() && km.isZERO(); 425 } 426 427 428 /** 429 * Is BigQuaternion imaginary one. 430 * @return true if this is i, else false. 431 */ 432 public boolean isIMAG() { 433 return re.isZERO() && im.isONE() && jm.isZERO() && km.isZERO(); 434 } 435 436 437 /** 438 * Is BigQuaternion unit element. 439 * @return If this is a unit then true is returned, else false. 440 * @see edu.jas.structure.RingElem#isUnit() 441 */ 442 public boolean isUnit() { 443 //if (ring.integral) { not meaningful to test 444 // System.out.println("*** entier isUnit case not implemented ***"); 445 //} 446 return !isZERO(); 447 } 448 449 450 /** 451 * Is BigQuaternion entier element. 452 * @return If this is an integer Hurwitz element then true is returned, else 453 * false. 454 */ 455 public boolean isEntier() { 456 if (re.isEntier() && im.isEntier() && jm.isEntier() && km.isEntier()) { 457 return true; 458 } 459 java.math.BigInteger TWO = BigInteger.TWO.val; 460 return re.den.equals(TWO) && im.den.equals(TWO) && jm.den.equals(TWO) && km.den.equals(TWO); 461 } 462 463 464 /** 465 * Comparison with any other object. 466 * @see java.lang.Object#equals(java.lang.Object) 467 */ 468 @Override 469 public boolean equals(Object b) { 470 if (!(b instanceof BigQuaternion)) { 471 return false; 472 } 473 BigQuaternion B = (BigQuaternion) b; 474 // ring == B.ring ? 475 return re.equals(B.re) && im.equals(B.im) && jm.equals(B.jm) && km.equals(B.km); 476 } 477 478 479 /** 480 * Hash code for this BigQuaternion. 481 * @see java.lang.Object#hashCode() 482 */ 483 @Override 484 public int hashCode() { 485 int h = re.hashCode(); 486 h += h * 37 + im.hashCode(); 487 h += h * 37 + jm.hashCode(); 488 h += h * 37 + km.hashCode(); 489 return h; 490 } 491 492 493 /** 494 * Since quaternion numbers are unordered, we use lexicographical order of 495 * re, im, jm and km. 496 * @param b BigQuaternion. 497 * @return 0 if b is equal to this, 1 if this is greater b and -1 else. 498 */ 499 @Override 500 public int compareTo(BigQuaternion b) { 501 int s = re.compareTo(b.re); 502 if (s != 0) { 503 return s; 504 } 505 s = im.compareTo(b.im); 506 if (s != 0) { 507 return s; 508 } 509 s = jm.compareTo(b.jm); 510 if (s != 0) { 511 return s; 512 } 513 return km.compareTo(b.km); 514 } 515 516 517 /** 518 * Since quaternion numbers are unordered, we use lexicographical order of 519 * re, im, jm and km. 520 * @return 0 if this is equal to 0; 1 if re > 0, or re == 0 and im > 521 * 0, or ...; -1 if re < 0, or re == 0 and im < 0, or ... 522 * @see edu.jas.structure.RingElem#signum() 523 */ 524 public int signum() { 525 int s = re.signum(); 526 if (s != 0) { 527 return s; 528 } 529 s = im.signum(); 530 if (s != 0) { 531 return s; 532 } 533 s = jm.signum(); 534 if (s != 0) { 535 return s; 536 } 537 return km.signum(); 538 } 539 540 541 /* arithmetic operations: +, -, - 542 */ 543 544 /** 545 * BigQuaternion summation. 546 * @param B BigQuaternion. 547 * @return this+B. 548 */ 549 public BigQuaternion sum(BigQuaternion B) { 550 return new BigQuaternion(ring, re.sum(B.re), im.sum(B.im), jm.sum(B.jm), km.sum(B.km)); 551 } 552 553 554 /** 555 * Quaternion number sum. 556 * @param A BigQuaternion. 557 * @param B BigQuaternion. 558 * @return A+B. 559 */ 560 public static BigQuaternion QSUM(BigQuaternion A, BigQuaternion B) { 561 if (A == null) 562 return null; 563 return A.sum(B); 564 } 565 566 567 /** 568 * Quaternion number difference. 569 * @param A BigQuaternion. 570 * @param B BigQuaternion. 571 * @return A-B. 572 */ 573 public static BigQuaternion QDIF(BigQuaternion A, BigQuaternion B) { 574 if (A == null) 575 return null; 576 return A.subtract(B); 577 } 578 579 580 /** 581 * BigQuaternion subtraction. 582 * @param B BigQuaternion. 583 * @return this-B. 584 */ 585 public BigQuaternion subtract(BigQuaternion B) { 586 return new BigQuaternion(ring, re.subtract(B.re), im.subtract(B.im), jm.subtract(B.jm), 587 km.subtract(B.km)); 588 } 589 590 591 /** 592 * Quaternion number negative. 593 * @param A is a quaternion number 594 * @return -A. 595 */ 596 public static BigQuaternion QNEG(BigQuaternion A) { 597 if (A == null) 598 return null; 599 return A.negate(); 600 } 601 602 603 /** 604 * BigQuaternion number negative. 605 * @return -this. 606 * @see edu.jas.structure.RingElem#negate() 607 */ 608 public BigQuaternion negate() { 609 return new BigQuaternion(ring, re.negate(), im.negate(), jm.negate(), km.negate()); 610 } 611 612 613 /** 614 * Quaternion number conjugate. 615 * @param A is a quaternion number. 616 * @return the quaternion conjugate of A. 617 */ 618 public static BigQuaternion QCON(BigQuaternion A) { 619 if (A == null) 620 return null; 621 return A.conjugate(); 622 } 623 624 625 /* arithmetic operations: conjugate, absolute value 626 */ 627 628 /** 629 * BigQuaternion conjugate. 630 * @return conjugate(this). 631 */ 632 public BigQuaternion conjugate() { 633 return new BigQuaternion(ring, re, im.negate(), jm.negate(), km.negate()); 634 } 635 636 637 /** 638 * Quaternion number norm. 639 * @see edu.jas.structure.StarRingElem#norm() 640 * @return ||this||. 641 */ 642 public BigQuaternion norm() { 643 // this.multiply(this.conjugate()); 644 BigRational v = re.multiply(re); 645 v = v.sum(im.multiply(im)); 646 v = v.sum(jm.multiply(jm)); 647 v = v.sum(km.multiply(km)); 648 return new BigQuaternion(ring, v); 649 } 650 651 652 /** 653 * Quaternion number absolute value. 654 * @see edu.jas.structure.RingElem#abs() 655 * @return |this|. 656 */ 657 public BigQuaternion abs() { 658 BigQuaternion n = norm(); 659 BigRational r = Roots.sqrt(n.re); 660 //logger.error("abs() square root missing"); 661 return new BigQuaternion(ring, r); 662 } 663 664 665 /** 666 * Quaternion number absolute value. 667 * @param A is a quaternion number. 668 * @return the absolute value of A, a rational number. Note: The square root 669 * is not jet implemented. 670 */ 671 public static BigRational QABS(BigQuaternion A) { 672 if (A == null) 673 return null; 674 return A.abs().re; 675 } 676 677 678 /** 679 * Quaternion number product. 680 * @param A BigQuaternion. 681 * @param B BigQuaternion. 682 * @return A*B. 683 */ 684 public static BigQuaternion QPROD(BigQuaternion A, BigQuaternion B) { 685 if (A == null) 686 return null; 687 return A.multiply(B); 688 } 689 690 691 /* arithmetic operations: *, inverse, / 692 */ 693 694 /** 695 * BigQuaternion multiply with BigRational. 696 * @param b BigRational. 697 * @return this*b. 698 */ 699 public BigQuaternion multiply(BigRational b) { 700 BigRational r = re.multiply(b); 701 BigRational i = im.multiply(b); 702 BigRational j = jm.multiply(b); 703 BigRational k = km.multiply(b); 704 return new BigQuaternion(ring, r, i, j, k); 705 } 706 707 708 /** 709 * BigQuaternion multiply. 710 * @param B BigQuaternion. 711 * @return this*B. 712 */ 713 public BigQuaternion multiply(BigQuaternion B) { 714 BigRational r = re.multiply(B.re); 715 r = r.subtract(im.multiply(B.im)); 716 r = r.subtract(jm.multiply(B.jm)); 717 r = r.subtract(km.multiply(B.km)); 718 719 BigRational i = re.multiply(B.im); 720 i = i.sum(im.multiply(B.re)); 721 i = i.sum(jm.multiply(B.km)); 722 i = i.subtract(km.multiply(B.jm)); 723 724 BigRational j = re.multiply(B.jm); 725 j = j.subtract(im.multiply(B.km)); 726 j = j.sum(jm.multiply(B.re)); 727 j = j.sum(km.multiply(B.im)); 728 729 BigRational k = re.multiply(B.km); 730 k = k.sum(im.multiply(B.jm)); 731 k = k.subtract(jm.multiply(B.im)); 732 k = k.sum(km.multiply(B.re)); 733 734 return new BigQuaternion(ring, r, i, j, k); 735 } 736 737 738 /** 739 * BigQuaternion multiply left. 740 * @param B BigQuaternion. 741 * @return B*this. 742 */ 743 public BigQuaternion multiplyLeft(BigQuaternion B) { 744 return B.multiply(this); 745 } 746 747 748 /** 749 * Quaternion number inverse. 750 * @param A is a non-zero quaternion number. 751 * @return S with S * A = A * S = 1. 752 */ 753 public static BigQuaternion QINV(BigQuaternion A) { 754 if (A == null) 755 return null; 756 return A.inverse(); 757 } 758 759 760 /** 761 * BigQuaternion inverse. 762 * @return S with S * this = this * S = 1. 763 * @see edu.jas.structure.RingElem#inverse() 764 */ 765 public BigQuaternion inverse() { 766 BigRational a = norm().re.inverse(); 767 return new BigQuaternion(ring, re.multiply(a), im.negate().multiply(a), jm.negate().multiply(a), 768 km.negate().multiply(a)); 769 } 770 771 772 /** 773 * BigQuaternion right remainder. 774 * @param S BigQuaternion. 775 * @return 0. 776 */ 777 public BigQuaternion rightRemainder(BigQuaternion S) { 778 if (S.isZERO()) { 779 throw new ArithmeticException("division by zero"); 780 } 781 if (ring.integral) { 782 //System.out.println( 783 // "*** entier right remainder(" + this + ", " + S + "): " + ring + " ***"); 784 BigQuaternionInteger c = new BigQuaternionInteger(ring, this); 785 BigQuaternionInteger d = new BigQuaternionInteger(ring, S); 786 return c.rightRemainder(d); 787 } 788 return ring.getZERO(); 789 } 790 791 792 /** 793 * BigQuaternion (right) remainder. 794 * @param S BigQuaternion. 795 * @return 0. 796 */ 797 public BigQuaternion remainder(BigQuaternion S) { 798 return rightRemainder(S); 799 } 800 801 802 /** 803 * BigQuaternion left remainder. 804 * @param S BigQuaternion. 805 * @return 0. 806 */ 807 public BigQuaternion leftRemainder(BigQuaternion S) { 808 if (S.isZERO()) { 809 throw new ArithmeticException("division by zero"); 810 } 811 if (ring.integral) { 812 //System.out.println( 813 // "*** entier right remainder(" + this + ", " + S + "): " + ring + " ***"); 814 BigQuaternionInteger c = new BigQuaternionInteger(ring, this); 815 BigQuaternionInteger d = new BigQuaternionInteger(ring, S); 816 return c.leftRemainder(d); 817 } 818 return ring.getZERO(); 819 } 820 821 822 /** 823 * Quaternion number quotient. 824 * @param A BigQuaternion. 825 * @param B BigQuaternion. 826 * @return R/S. 827 */ 828 public static BigQuaternion QQ(BigQuaternion A, BigQuaternion B) { 829 if (A == null) 830 return null; 831 return A.divide(B); 832 } 833 834 835 /** 836 * BigQuaternion right divide. 837 * @param b BigQuaternion. 838 * @return this * b**(-1). 839 */ 840 public BigQuaternion divide(BigQuaternion b) { 841 return rightDivide(b); 842 } 843 844 845 /** 846 * BigQuaternion right divide. 847 * @param b BigQuaternion. 848 * @return q = this * b**(-1), such that q * b = this. 849 */ 850 @Override 851 public BigQuaternion rightDivide(BigQuaternion b) { 852 if (ring.integral) { 853 //System.out.println("*** entier right divide(" + this + ", " + b + "): " + ring + " ***"); 854 BigQuaternionInteger c = new BigQuaternionInteger(ring, this); 855 BigQuaternionInteger d = new BigQuaternionInteger(ring, b); 856 return c.rightDivide(d); 857 } 858 return this.multiply(b.inverse()); 859 } 860 861 862 /** 863 * BigQuaternion left divide. 864 * @param b BigQuaternion. 865 * @return q = b**(-1) * this, such that b * q = this. 866 */ 867 @Override 868 public BigQuaternion leftDivide(BigQuaternion b) { 869 if (ring.integral) { 870 //System.out.println("*** entier left divide(" + this + ", " + b + "): " + ring + " ***"); 871 BigQuaternionInteger c = new BigQuaternionInteger(ring, this); 872 BigQuaternionInteger d = new BigQuaternionInteger(ring, b); 873 return c.leftDivide(d); 874 } 875 return b.inverse().multiply(this); 876 } 877 878 879 /** 880 * BigQuaternion divide. 881 * @param b BigRational. 882 * @return this/b. 883 */ 884 public BigQuaternion divide(BigRational b) { 885 BigRational bi = b.inverse(); 886 return new BigQuaternion(ring, re.multiply(bi), im.multiply(bi), jm.multiply(bi), km.multiply(bi)); 887 } 888 889 890 /** 891 * Quotient and remainder by division of this by S. 892 * @param S a quaternion number 893 * @return [this*S**(-1), this - (this*S**(-1))*S]. 894 */ 895 public BigQuaternion[] quotientRemainder(BigQuaternion S) { 896 if (ring.integral) { 897 //System.out.println( 898 // "*** entier left quotient remainder(" + this + ", " + S + "): " + ring + " ***"); 899 BigQuaternionInteger c = new BigQuaternionInteger(ring, this); 900 BigQuaternionInteger d = new BigQuaternionInteger(ring, S); 901 return c.rightQuotientAndRemainder(d); 902 } 903 return new BigQuaternion[] { divide(S), ring.getZERO() }; 904 } 905 906 907 /** 908 * Quaternion number greatest common divisor. 909 * @param S BigQuaternion. 910 * @return gcd(this,S). 911 */ 912 public BigQuaternion gcd(BigQuaternion S) { 913 return leftGcd(S); 914 } 915 916 917 /** 918 * Quaternion number greatest common divisor. 919 * @param S BigQuaternion. 920 * @return leftCcd(this,S). 921 */ 922 public BigQuaternion leftGcd(BigQuaternion S) { 923 if (S == null || S.isZERO()) { 924 return this; 925 } 926 if (this.isZERO()) { 927 return S; 928 } 929 if (ring.integral) { 930 //System.out.println("*** entier left gcd(" + this + ", " + S + "): " + ring + " ***"); 931 BigQuaternionInteger a = new BigQuaternionInteger(ring, this); 932 BigQuaternionInteger b = new BigQuaternionInteger(ring, S); 933 return a.leftGcd(b); 934 } 935 return ring.getONE(); 936 } 937 938 939 /** 940 * Quaternion number greatest common divisor. 941 * @param S BigQuaternion. 942 * @return rightCcd(this,S). 943 */ 944 public BigQuaternion rightGcd(BigQuaternion S) { 945 if (S == null || S.isZERO()) { 946 return this; 947 } 948 if (this.isZERO()) { 949 return S; 950 } 951 if (ring.integral) { 952 //System.out.println("*** entier right gcd(" + this + ", " + S + "): " + ring + " ***"); 953 BigQuaternionInteger a = new BigQuaternionInteger(ring, this); 954 BigQuaternionInteger b = new BigQuaternionInteger(ring, S); 955 return a.rightGcd(b); 956 } 957 return ring.getONE(); 958 } 959 960 961 /** 962 * BigQuaternion extended greatest common divisor. 963 * @param S BigQuaternion. 964 * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). 965 */ 966 public BigQuaternion[] egcd(BigQuaternion S) { 967 if (ring.integral) { 968 System.out.println("*** entier egcd case not implemented ***"); 969 } 970 BigQuaternion[] ret = new BigQuaternion[3]; 971 ret[0] = null; 972 ret[1] = null; 973 ret[2] = null; 974 if (S == null || S.isZERO()) { 975 ret[0] = this; 976 return ret; 977 } 978 if (this.isZERO()) { 979 ret[0] = S; 980 return ret; 981 } 982 BigQuaternion half = new BigQuaternion(ring, new BigRational(1, 2)); 983 ret[0] = ring.getONE(); 984 ret[1] = this.inverse().multiply(half); 985 ret[2] = S.inverse().multiply(half); 986 return ret; 987 } 988 989 990 /** 991 * Returns the number of bits in the representation of this BigQuaternion, 992 * including a sign bit. It is equivalent to 993 * {@code re.bitLength()+im.bitLength()+jm.bitLength()+km.bitLength()}.) 994 * @return number of bits in the representation of this BigQuaternion, 995 * including a sign bit. 996 */ 997 public long bitLength() { 998 return re.bitLength() + im.bitLength() + jm.bitLength() + km.bitLength(); 999 } 1000 1001 1002 /** 1003 * BigQuaternion ceiling, component wise. 1004 * @return ceiling of this. 1005 */ 1006 public BigQuaternion ceil() { 1007 BigRational r = new BigRational(re.ceil()); 1008 BigRational i = new BigRational(im.ceil()); 1009 BigRational j = new BigRational(jm.ceil()); 1010 BigRational k = new BigRational(km.ceil()); 1011 return new BigQuaternion(ring, r, i, j, k); 1012 } 1013 1014 1015 /** 1016 * BigQuaternion floor, component wise. 1017 * @return floor of this. 1018 */ 1019 public BigQuaternion floor() { 1020 BigRational r = new BigRational(re.floor()); 1021 BigRational i = new BigRational(im.floor()); 1022 BigRational j = new BigRational(jm.floor()); 1023 BigRational k = new BigRational(km.floor()); 1024 return new BigQuaternion(ring, r, i, j, k); 1025 } 1026 1027 1028 /** 1029 * BigQuaternion round to next Lipschitz integer. BigQuaternion with all 1030 * integer components. 1031 * @return Lipschitz integer of this. 1032 */ 1033 public BigQuaternionInteger roundToLipschitzian() { 1034 BigRational half = BigRational.HALF; 1035 BigRational r = new BigRational(re.sum(half).floor()); 1036 BigRational i = new BigRational(im.sum(half).floor()); 1037 BigRational j = new BigRational(jm.sum(half).floor()); 1038 BigRational k = new BigRational(km.sum(half).floor()); 1039 return new BigQuaternionInteger(ring, r, i, j, k); 1040 } 1041 1042 1043 /** 1044 * BigQuaternion round to next Hurwitz integer. BigQuaternion with all 1045 * integer or all 1/2 times integer components. 1046 * @return Hurwitz integer near this. 1047 */ 1048 public BigQuaternionInteger roundToHurwitzian() { 1049 if (isEntier()) { 1050 //System.out.println("*** short cut to round ***"); 1051 return new BigQuaternionInteger(ring, this); 1052 } 1053 BigQuaternionInteger g = this.roundToLipschitzian(); 1054 BigQuaternion d = ring.getZERO(); 1055 //BigRational half = BigRational.HALF; 1056 BigQuaternion s = this.subtract(g).norm(); 1057 //System.out.println("s = " + s.toScript()); 1058 //if (s.re.compareTo(half) < 0) { // wrong 1059 List<BigQuaternion> units = ring.unitsOfHurwitzian(); 1060 BigQuaternion t = null; 1061 for (BigQuaternion ue : units) { 1062 //t = this.subtract(g).sum(ue).norm(); // bug 1063 t = this.subtract(g.sum(ue)).norm(); 1064 if (t.re.compareTo(s.re) < 0) { 1065 s = t; 1066 d = ue; 1067 } 1068 } 1069 //System.out.println("ring = " + ring); 1070 g = new BigQuaternionInteger(ring, g.sum(d)); 1071 return g; 1072 } 1073 1074}