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 remainder. 774 * @param S BigQuaternion. 775 * @return 0. 776 */ 777 public BigQuaternion remainder(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 * Quaternion number quotient. 794 * @param A BigQuaternion. 795 * @param B BigQuaternion. 796 * @return R/S. 797 */ 798 public static BigQuaternion QQ(BigQuaternion A, BigQuaternion B) { 799 if (A == null) 800 return null; 801 return A.divide(B); 802 } 803 804 805 /** 806 * BigQuaternion right divide. 807 * @param b BigQuaternion. 808 * @return this * b**(-1). 809 */ 810 public BigQuaternion divide(BigQuaternion b) { 811 return rightDivide(b); 812 } 813 814 815 /** 816 * BigQuaternion right divide. 817 * @param b BigQuaternion. 818 * @return this * b**(-1). 819 */ 820 @Override 821 public BigQuaternion rightDivide(BigQuaternion b) { 822 if (ring.integral) { 823 //System.out.println("*** entier right divide(" + this + ", " + b + "): " + ring + " ***"); 824 BigQuaternionInteger c = new BigQuaternionInteger(ring, this); 825 BigQuaternionInteger d = new BigQuaternionInteger(ring, b); 826 return c.rightDivide(d); 827 } 828 return this.multiply(b.inverse()); 829 } 830 831 832 /** 833 * BigQuaternion left divide. 834 * @param b BigQuaternion. 835 * @return b**(-1) * this. 836 */ 837 @Override 838 public BigQuaternion leftDivide(BigQuaternion b) { 839 if (ring.integral) { 840 //System.out.println("*** entier left divide(" + this + ", " + b + "): " + ring + " ***"); 841 BigQuaternionInteger c = new BigQuaternionInteger(ring, this); 842 BigQuaternionInteger d = new BigQuaternionInteger(ring, b); 843 return c.leftDivide(d); 844 } 845 return b.inverse().multiply(this); 846 } 847 848 849 /** 850 * BigQuaternion divide. 851 * @param b BigRational. 852 * @return this/b. 853 */ 854 public BigQuaternion divide(BigRational b) { 855 BigRational bi = b.inverse(); 856 return new BigQuaternion(ring, re.multiply(bi), im.multiply(bi), jm.multiply(bi), km.multiply(bi)); 857 } 858 859 860 /** 861 * Quotient and remainder by division of this by S. 862 * @param S a quaternion number 863 * @return [this*S**(-1), this - (this*S**(-1))*S]. 864 */ 865 public BigQuaternion[] quotientRemainder(BigQuaternion S) { 866 if (ring.integral) { 867 //System.out.println( 868 // "*** entier left quotient remainder(" + this + ", " + S + "): " + ring + " ***"); 869 BigQuaternionInteger c = new BigQuaternionInteger(ring, this); 870 BigQuaternionInteger d = new BigQuaternionInteger(ring, S); 871 return c.rightQuotientAndRemainder(d); 872 } 873 return new BigQuaternion[] { divide(S), ring.getZERO() }; 874 } 875 876 877 /** 878 * Quaternion number greatest common divisor. 879 * @param S BigQuaternion. 880 * @return gcd(this,S). 881 */ 882 public BigQuaternion gcd(BigQuaternion S) { 883 return leftGcd(S); 884 } 885 886 887 /** 888 * Quaternion number greatest common divisor. 889 * @param S BigQuaternion. 890 * @return leftCcd(this,S). 891 */ 892 public BigQuaternion leftGcd(BigQuaternion S) { 893 if (S == null || S.isZERO()) { 894 return this; 895 } 896 if (this.isZERO()) { 897 return S; 898 } 899 if (ring.integral) { 900 //System.out.println("*** entier left gcd(" + this + ", " + S + "): " + ring + " ***"); 901 BigQuaternionInteger a = new BigQuaternionInteger(ring, this); 902 BigQuaternionInteger b = new BigQuaternionInteger(ring, S); 903 return a.leftGcd(b); 904 } 905 return ring.getONE(); 906 } 907 908 909 /** 910 * Quaternion number greatest common divisor. 911 * @param S BigQuaternion. 912 * @return rightCcd(this,S). 913 */ 914 public BigQuaternion rightGcd(BigQuaternion S) { 915 if (S == null || S.isZERO()) { 916 return this; 917 } 918 if (this.isZERO()) { 919 return S; 920 } 921 if (ring.integral) { 922 //System.out.println("*** entier right gcd(" + this + ", " + S + "): " + ring + " ***"); 923 BigQuaternionInteger a = new BigQuaternionInteger(ring, this); 924 BigQuaternionInteger b = new BigQuaternionInteger(ring, S); 925 return a.rightGcd(b); 926 } 927 return ring.getONE(); 928 } 929 930 931 /** 932 * BigQuaternion extended greatest common divisor. 933 * @param S BigQuaternion. 934 * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). 935 */ 936 public BigQuaternion[] egcd(BigQuaternion S) { 937 if (ring.integral) { 938 System.out.println("*** entier egcd case not implemented ***"); 939 } 940 BigQuaternion[] ret = new BigQuaternion[3]; 941 ret[0] = null; 942 ret[1] = null; 943 ret[2] = null; 944 if (S == null || S.isZERO()) { 945 ret[0] = this; 946 return ret; 947 } 948 if (this.isZERO()) { 949 ret[0] = S; 950 return ret; 951 } 952 BigQuaternion half = new BigQuaternion(ring, new BigRational(1, 2)); 953 ret[0] = ring.getONE(); 954 ret[1] = this.inverse().multiply(half); 955 ret[2] = S.inverse().multiply(half); 956 return ret; 957 } 958 959 960 /** 961 * Returns the number of bits in the representation of this BigQuaternion, 962 * including a sign bit. It is equivalent to 963 * {@code re.bitLength()+im.bitLength()+jm.bitLength()+km.bitLength()}.) 964 * @return number of bits in the representation of this BigQuaternion, 965 * including a sign bit. 966 */ 967 public long bitLength() { 968 return re.bitLength() + im.bitLength() + jm.bitLength() + km.bitLength(); 969 } 970 971 972 /** 973 * BigQuaternion ceiling, component wise. 974 * @return ceiling of this. 975 */ 976 public BigQuaternion ceil() { 977 BigRational r = new BigRational(re.ceil()); 978 BigRational i = new BigRational(im.ceil()); 979 BigRational j = new BigRational(jm.ceil()); 980 BigRational k = new BigRational(km.ceil()); 981 return new BigQuaternion(ring, r, i, j, k); 982 } 983 984 985 /** 986 * BigQuaternion floor, component wise. 987 * @return floor of this. 988 */ 989 public BigQuaternion floor() { 990 BigRational r = new BigRational(re.floor()); 991 BigRational i = new BigRational(im.floor()); 992 BigRational j = new BigRational(jm.floor()); 993 BigRational k = new BigRational(km.floor()); 994 return new BigQuaternion(ring, r, i, j, k); 995 } 996 997 998 /** 999 * BigQuaternion round to next Lipschitz integer. BigQuaternion with all 1000 * integer components. 1001 * @return Lipschitz integer of this. 1002 */ 1003 public BigQuaternionInteger roundToLipschitzian() { 1004 BigRational half = BigRational.HALF; 1005 BigRational r = new BigRational(re.sum(half).floor()); 1006 BigRational i = new BigRational(im.sum(half).floor()); 1007 BigRational j = new BigRational(jm.sum(half).floor()); 1008 BigRational k = new BigRational(km.sum(half).floor()); 1009 return new BigQuaternionInteger(ring, r, i, j, k); 1010 } 1011 1012 1013 /** 1014 * BigQuaternion round to next Hurwitz integer. BigQuaternion with all 1015 * integer or all 1/2 times integer components. 1016 * @return Hurwitz integer near this. 1017 */ 1018 public BigQuaternionInteger roundToHurwitzian() { 1019 if (isEntier()) { 1020 //System.out.println("*** short cut to round ***"); 1021 return new BigQuaternionInteger(ring, this); 1022 } 1023 BigQuaternionInteger g = this.roundToLipschitzian(); 1024 BigQuaternion d = ring.getZERO(); 1025 //BigRational half = BigRational.HALF; 1026 BigQuaternion s = this.subtract(g).norm(); 1027 //System.out.println("s = " + s.toScript()); 1028 //if (s.re.compareTo(half) < 0) { // wrong 1029 List<BigQuaternion> units = ring.unitsOfHurwitzian(); 1030 BigQuaternion t = null; 1031 for (BigQuaternion ue : units) { 1032 //t = this.subtract(g).sum(ue).norm(); // bug 1033 t = this.subtract(g.sum(ue)).norm(); 1034 if (t.re.compareTo(s.re) < 0) { 1035 s = t; 1036 d = ue; 1037 } 1038 } 1039 //System.out.println("ring = " + ring); 1040 g = new BigQuaternionInteger(ring, g.sum(d)); 1041 return g; 1042 } 1043 1044}