001/* 002 * $Id: BigQuaternion.java 5945 2018-10-27 10:19:22Z kredel $ 003 */ 004 005package edu.jas.arith; 006 007 008import java.util.List; 009import java.util.Random; 010 011import org.apache.logging.log4j.Logger; 012import org.apache.logging.log4j.LogManager; 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(re.toString()); 280 int i = im.compareTo(BigRational.ZERO); 281 int j = jm.compareTo(BigRational.ZERO); 282 int k = km.compareTo(BigRational.ZERO); 283 if (debug) { 284 logger.debug("compareTo " + im + " ? 0 = " + i); 285 logger.debug("compareTo " + jm + " ? 0 = " + j); 286 logger.debug("compareTo " + km + " ? 0 = " + k); 287 } 288 if (i == 0 && j == 0 && k == 0) { 289 return sb.toString(); 290 } 291 sb.append("i" + im); 292 sb.append("j" + jm); 293 sb.append("k" + km); 294 String s = sb.toString(); 295 //s = s.replaceAll("-","~"); 296 return s; 297 } 298 299 300 /** 301 * Get a scripting compatible string representation. 302 * @return script compatible representation for this Element. 303 * @see edu.jas.structure.Element#toScript() 304 */ 305 @Override 306 public String toScript() { 307 // Python case 308 StringBuffer s = new StringBuffer(); 309 boolean i = im.isZERO(); 310 boolean j = jm.isZERO(); 311 boolean k = km.isZERO(); 312 if (i && j && k) { 313 if (re.isZERO()) { 314 return "0 "; 315 } 316 if (!re.isONE()) { 317 s.append(re.toScript() + "*"); 318 } 319 s.append("oneQ "); 320 return s.toString(); 321 } 322 if (!re.isZERO()) { 323 if (!re.isONE()) { 324 s.append(re.toScript() + "*"); 325 } 326 s.append("oneQ "); 327 } 328 if (!i) { 329 if (s.length() > 0) { 330 s.append("+ "); 331 } 332 if (!im.isONE()) { 333 s.append(im.toScript() + "*"); 334 } 335 s.append("IQ "); 336 } 337 if (!j) { 338 if (s.length() > 0) { 339 s.append("+ "); 340 } 341 if (!jm.isONE()) { 342 s.append(jm.toScript() + "*"); 343 } 344 s.append("JQ "); 345 } 346 if (!k) { 347 if (s.length() > 0) { 348 s.append("+ "); 349 } 350 if (!km.isONE()) { 351 s.append(km.toScript() + "*"); 352 } 353 s.append("KQ "); 354 } 355 return s.toString(); 356 } 357 358 359 /** 360 * Get a scripting compatible string representation of the factory. 361 * @return script compatible representation for this ElemFactory. 362 * @see edu.jas.structure.Element#toScriptFactory() 363 */ 364 @Override 365 public String toScriptFactory() { 366 // Python case 367 return ring.toScript(); 368 } 369 370 371 /** 372 * Is Quaternion number zero. 373 * @param A BigQuaternion. 374 * @return true if A is 0, else false. 375 */ 376 public static boolean isQZERO(BigQuaternion A) { 377 if (A == null) 378 return false; 379 return A.isZERO(); 380 } 381 382 383 /** 384 * Is BigQuaternion number zero. 385 * @return true if this is 0, else false. 386 * @see edu.jas.structure.RingElem#isZERO() 387 */ 388 public boolean isZERO() { 389 return re.isZERO() && im.isZERO() && jm.isZERO() && km.isZERO(); 390 } 391 392 393 /** 394 * Is BigQuaternion number one. 395 * @param A is a quaternion number. 396 * @return true if A is 1, else false. 397 */ 398 public static boolean isQONE(BigQuaternion A) { 399 if (A == null) 400 return false; 401 return A.isONE(); 402 } 403 404 405 /** 406 * Is BigQuaternion number one. 407 * @see edu.jas.structure.RingElem#isONE() 408 * @return true if this is 1, else false. 409 */ 410 public boolean isONE() { 411 return re.isONE() && im.isZERO() && jm.isZERO() && km.isZERO(); 412 } 413 414 415 /** 416 * Is BigQuaternion imaginary one. 417 * @return true if this is i, else false. 418 */ 419 public boolean isIMAG() { 420 return re.isZERO() && im.isONE() && jm.isZERO() && km.isZERO(); 421 } 422 423 424 /** 425 * Is BigQuaternion unit element. 426 * @return If this is a unit then true is returned, else false. 427 * @see edu.jas.structure.RingElem#isUnit() 428 */ 429 public boolean isUnit() { 430 //if (ring.integral) { not meaningful to test 431 // System.out.println("*** entier isUnit case not implemented ***"); 432 //} 433 return !isZERO(); 434 } 435 436 437 /** 438 * Is BigQuaternion entier element. 439 * @return If this is an integer Hurwitz element then true is returned, else 440 * false. 441 */ 442 public boolean isEntier() { 443 if (re.isEntier() && im.isEntier() && jm.isEntier() && km.isEntier()) { 444 return true; 445 } 446 java.math.BigInteger TWO = BigInteger.TWO.val; 447 return re.den.equals(TWO) && im.den.equals(TWO) && jm.den.equals(TWO) && km.den.equals(TWO); 448 } 449 450 451 /** 452 * Comparison with any other object. 453 * @see java.lang.Object#equals(java.lang.Object) 454 */ 455 @Override 456 public boolean equals(Object b) { 457 if (!(b instanceof BigQuaternion)) { 458 return false; 459 } 460 BigQuaternion B = (BigQuaternion) b; 461 // ring == B.ring ? 462 return re.equals(B.re) && im.equals(B.im) && jm.equals(B.jm) && km.equals(B.km); 463 } 464 465 466 /** 467 * Hash code for this BigQuaternion. 468 * @see java.lang.Object#hashCode() 469 */ 470 @Override 471 public int hashCode() { 472 int h = re.hashCode(); 473 h += h * 37 + im.hashCode(); 474 h += h * 37 + jm.hashCode(); 475 h += h * 37 + km.hashCode(); 476 return h; 477 } 478 479 480 /** 481 * Since quaternion numbers are unordered, we use lexicographical order of 482 * re, im, jm and km. 483 * @param b BigQuaternion. 484 * @return 0 if b is equal to this, 1 if this is greater b and -1 else. 485 */ 486 @Override 487 public int compareTo(BigQuaternion b) { 488 int s = re.compareTo(b.re); 489 if (s != 0) { 490 return s; 491 } 492 s = im.compareTo(b.im); 493 if (s != 0) { 494 return s; 495 } 496 s = jm.compareTo(b.jm); 497 if (s != 0) { 498 return s; 499 } 500 return km.compareTo(b.km); 501 } 502 503 504 /** 505 * Since quaternion numbers are unordered, we use lexicographical order of 506 * re, im, jm and km. 507 * @return 0 if this is equal to 0; 1 if re > 0, or re == 0 and im > 0, or 508 * ...; -1 if re < 0, or re == 0 and im < 0, or ... 509 * @see edu.jas.structure.RingElem#signum() 510 */ 511 public int signum() { 512 int s = re.signum(); 513 if (s != 0) { 514 return s; 515 } 516 s = im.signum(); 517 if (s != 0) { 518 return s; 519 } 520 s = jm.signum(); 521 if (s != 0) { 522 return s; 523 } 524 return km.signum(); 525 } 526 527 528 /* arithmetic operations: +, -, - 529 */ 530 531 /** 532 * BigQuaternion summation. 533 * @param B BigQuaternion. 534 * @return this+B. 535 */ 536 public BigQuaternion sum(BigQuaternion B) { 537 return new BigQuaternion(ring, re.sum(B.re), im.sum(B.im), jm.sum(B.jm), km.sum(B.km)); 538 } 539 540 541 /** 542 * Quaternion number sum. 543 * @param A BigQuaternion. 544 * @param B BigQuaternion. 545 * @return A+B. 546 */ 547 public static BigQuaternion QSUM(BigQuaternion A, BigQuaternion B) { 548 if (A == null) 549 return null; 550 return A.sum(B); 551 } 552 553 554 /** 555 * Quaternion number difference. 556 * @param A BigQuaternion. 557 * @param B BigQuaternion. 558 * @return A-B. 559 */ 560 public static BigQuaternion QDIF(BigQuaternion A, BigQuaternion B) { 561 if (A == null) 562 return null; 563 return A.subtract(B); 564 } 565 566 567 /** 568 * BigQuaternion subtraction. 569 * @param B BigQuaternion. 570 * @return this-B. 571 */ 572 public BigQuaternion subtract(BigQuaternion B) { 573 return new BigQuaternion(ring, re.subtract(B.re), im.subtract(B.im), jm.subtract(B.jm), 574 km.subtract(B.km)); 575 } 576 577 578 /** 579 * Quaternion number negative. 580 * @param A is a quaternion number 581 * @return -A. 582 */ 583 public static BigQuaternion QNEG(BigQuaternion A) { 584 if (A == null) 585 return null; 586 return A.negate(); 587 } 588 589 590 /** 591 * BigQuaternion number negative. 592 * @return -this. 593 * @see edu.jas.structure.RingElem#negate() 594 */ 595 public BigQuaternion negate() { 596 return new BigQuaternion(ring, re.negate(), im.negate(), jm.negate(), km.negate()); 597 } 598 599 600 /** 601 * Quaternion number conjugate. 602 * @param A is a quaternion number. 603 * @return the quaternion conjugate of A. 604 */ 605 public static BigQuaternion QCON(BigQuaternion A) { 606 if (A == null) 607 return null; 608 return A.conjugate(); 609 } 610 611 612 /* arithmetic operations: conjugate, absolute value 613 */ 614 615 /** 616 * BigQuaternion conjugate. 617 * @return conjugate(this). 618 */ 619 public BigQuaternion conjugate() { 620 return new BigQuaternion(ring, re, im.negate(), jm.negate(), km.negate()); 621 } 622 623 624 /** 625 * Quaternion number norm. 626 * @see edu.jas.structure.StarRingElem#norm() 627 * @return ||this||. 628 */ 629 public BigQuaternion norm() { 630 // this.multiply(this.conjugate()); 631 BigRational v = re.multiply(re); 632 v = v.sum(im.multiply(im)); 633 v = v.sum(jm.multiply(jm)); 634 v = v.sum(km.multiply(km)); 635 return new BigQuaternion(ring, v); 636 } 637 638 639 /** 640 * Quaternion number absolute value. 641 * @see edu.jas.structure.RingElem#abs() 642 * @return |this|. 643 */ 644 public BigQuaternion abs() { 645 BigQuaternion n = norm(); 646 BigRational r = Roots.sqrt(n.re); 647 //logger.error("abs() square root missing"); 648 return new BigQuaternion(ring, r); 649 } 650 651 652 /** 653 * Quaternion number absolute value. 654 * @param A is a quaternion number. 655 * @return the absolute value of A, a rational number. Note: The square root 656 * is not jet implemented. 657 */ 658 public static BigRational QABS(BigQuaternion A) { 659 if (A == null) 660 return null; 661 return A.abs().re; 662 } 663 664 665 /** 666 * Quaternion number product. 667 * @param A BigQuaternion. 668 * @param B BigQuaternion. 669 * @return A*B. 670 */ 671 public static BigQuaternion QPROD(BigQuaternion A, BigQuaternion B) { 672 if (A == null) 673 return null; 674 return A.multiply(B); 675 } 676 677 678 /* arithmetic operations: *, inverse, / 679 */ 680 681 /** 682 * BigQuaternion multiply with BigRational. 683 * @param b BigRational. 684 * @return this*b. 685 */ 686 public BigQuaternion multiply(BigRational b) { 687 BigRational r = re.multiply(b); 688 BigRational i = im.multiply(b); 689 BigRational j = jm.multiply(b); 690 BigRational k = km.multiply(b); 691 return new BigQuaternion(ring, r, i, j, k); 692 } 693 694 695 /** 696 * BigQuaternion multiply. 697 * @param B BigQuaternion. 698 * @return this*B. 699 */ 700 public BigQuaternion multiply(BigQuaternion B) { 701 BigRational r = re.multiply(B.re); 702 r = r.subtract(im.multiply(B.im)); 703 r = r.subtract(jm.multiply(B.jm)); 704 r = r.subtract(km.multiply(B.km)); 705 706 BigRational i = re.multiply(B.im); 707 i = i.sum(im.multiply(B.re)); 708 i = i.sum(jm.multiply(B.km)); 709 i = i.subtract(km.multiply(B.jm)); 710 711 BigRational j = re.multiply(B.jm); 712 j = j.subtract(im.multiply(B.km)); 713 j = j.sum(jm.multiply(B.re)); 714 j = j.sum(km.multiply(B.im)); 715 716 BigRational k = re.multiply(B.km); 717 k = k.sum(im.multiply(B.jm)); 718 k = k.subtract(jm.multiply(B.im)); 719 k = k.sum(km.multiply(B.re)); 720 721 return new BigQuaternion(ring, r, i, j, k); 722 } 723 724 725 /** 726 * Quaternion number inverse. 727 * @param A is a non-zero quaternion number. 728 * @return S with S * A = A * S = 1. 729 */ 730 public static BigQuaternion QINV(BigQuaternion A) { 731 if (A == null) 732 return null; 733 return A.inverse(); 734 } 735 736 737 /** 738 * BigQuaternion inverse. 739 * @return S with S * this = this * S = 1. 740 * @see edu.jas.structure.RingElem#inverse() 741 */ 742 public BigQuaternion inverse() { 743 BigRational a = norm().re.inverse(); 744 return new BigQuaternion(ring, re.multiply(a), im.negate().multiply(a), jm.negate().multiply(a), 745 km.negate().multiply(a)); 746 } 747 748 749 /** 750 * BigQuaternion remainder. 751 * @param S BigQuaternion. 752 * @return 0. 753 */ 754 public BigQuaternion remainder(BigQuaternion S) { 755 if (S.isZERO()) { 756 throw new ArithmeticException("division by zero"); 757 } 758 if (ring.integral) { 759 //System.out.println( 760 // "*** entier right remainder(" + this + ", " + S + "): " + ring + " ***"); 761 BigQuaternionInteger c = new BigQuaternionInteger(ring, this); 762 BigQuaternionInteger d = new BigQuaternionInteger(ring, S); 763 return c.rightRemainder(d); 764 } 765 return ring.getZERO(); 766 } 767 768 769 /** 770 * Quaternion number quotient. 771 * @param A BigQuaternion. 772 * @param B BigQuaternion. 773 * @return R/S. 774 */ 775 public static BigQuaternion QQ(BigQuaternion A, BigQuaternion B) { 776 if (A == null) 777 return null; 778 return A.divide(B); 779 } 780 781 782 /** 783 * BigQuaternion right divide. 784 * @param b BigQuaternion. 785 * @return this * b**(-1). 786 */ 787 public BigQuaternion divide(BigQuaternion b) { 788 return rightDivide(b); 789 } 790 791 792 /** 793 * BigQuaternion right divide. 794 * @param b BigQuaternion. 795 * @return this * b**(-1). 796 */ 797 @Override 798 public BigQuaternion rightDivide(BigQuaternion b) { 799 if (ring.integral) { 800 //System.out.println("*** entier right divide(" + this + ", " + b + "): " + ring + " ***"); 801 BigQuaternionInteger c = new BigQuaternionInteger(ring, this); 802 BigQuaternionInteger d = new BigQuaternionInteger(ring, b); 803 return c.rightDivide(d); 804 } 805 return this.multiply(b.inverse()); 806 } 807 808 809 /** 810 * BigQuaternion left divide. 811 * @param b BigQuaternion. 812 * @return b**(-1) * this. 813 */ 814 @Override 815 public BigQuaternion leftDivide(BigQuaternion b) { 816 if (ring.integral) { 817 //System.out.println("*** entier left divide(" + this + ", " + b + "): " + ring + " ***"); 818 BigQuaternionInteger c = new BigQuaternionInteger(ring, this); 819 BigQuaternionInteger d = new BigQuaternionInteger(ring, b); 820 return c.leftDivide(d); 821 } 822 return b.inverse().multiply(this); 823 } 824 825 826 /** 827 * BigQuaternion divide. 828 * @param b BigRational. 829 * @return this/b. 830 */ 831 public BigQuaternion divide(BigRational b) { 832 BigRational bi = b.inverse(); 833 return new BigQuaternion(ring, re.multiply(bi), im.multiply(bi), jm.multiply(bi), km.multiply(bi)); 834 } 835 836 837 /** 838 * Quotient and remainder by division of this by S. 839 * @param S a quaternion number 840 * @return [this*S**(-1), this - (this*S**(-1))*S]. 841 */ 842 public BigQuaternion[] quotientRemainder(BigQuaternion S) { 843 if (ring.integral) { 844 //System.out.println( 845 // "*** entier left quotient remainder(" + this + ", " + S + "): " + ring + " ***"); 846 BigQuaternionInteger c = new BigQuaternionInteger(ring, this); 847 BigQuaternionInteger d = new BigQuaternionInteger(ring, S); 848 return c.rightQuotientAndRemainder(d); 849 } 850 return new BigQuaternion[] { divide(S), ring.getZERO() }; 851 } 852 853 854 /** 855 * Quaternion number greatest common divisor. 856 * @param S BigQuaternion. 857 * @return gcd(this,S). 858 */ 859 public BigQuaternion gcd(BigQuaternion S) { 860 return leftGcd(S); 861 } 862 863 864 /** 865 * Quaternion number greatest common divisor. 866 * @param S BigQuaternion. 867 * @return leftCcd(this,S). 868 */ 869 public BigQuaternion leftGcd(BigQuaternion S) { 870 if (S == null || S.isZERO()) { 871 return this; 872 } 873 if (this.isZERO()) { 874 return S; 875 } 876 if (ring.integral) { 877 //System.out.println("*** entier left gcd(" + this + ", " + S + "): " + ring + " ***"); 878 BigQuaternionInteger a = new BigQuaternionInteger(ring, this); 879 BigQuaternionInteger b = new BigQuaternionInteger(ring, S); 880 return a.leftGcd(b); 881 } 882 return ring.getONE(); 883 } 884 885 886 /** 887 * Quaternion number greatest common divisor. 888 * @param S BigQuaternion. 889 * @return rightCcd(this,S). 890 */ 891 public BigQuaternion rightGcd(BigQuaternion S) { 892 if (S == null || S.isZERO()) { 893 return this; 894 } 895 if (this.isZERO()) { 896 return S; 897 } 898 if (ring.integral) { 899 //System.out.println("*** entier right gcd(" + this + ", " + S + "): " + ring + " ***"); 900 BigQuaternionInteger a = new BigQuaternionInteger(ring, this); 901 BigQuaternionInteger b = new BigQuaternionInteger(ring, S); 902 return a.rightGcd(b); 903 } 904 return ring.getONE(); 905 } 906 907 908 /** 909 * BigQuaternion extended greatest common divisor. 910 * @param S BigQuaternion. 911 * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). 912 */ 913 public BigQuaternion[] egcd(BigQuaternion S) { 914 if (ring.integral) { 915 System.out.println("*** entier egcd case not implemented ***"); 916 } 917 BigQuaternion[] ret = new BigQuaternion[3]; 918 ret[0] = null; 919 ret[1] = null; 920 ret[2] = null; 921 if (S == null || S.isZERO()) { 922 ret[0] = this; 923 return ret; 924 } 925 if (this.isZERO()) { 926 ret[0] = S; 927 return ret; 928 } 929 BigQuaternion half = new BigQuaternion(ring, new BigRational(1, 2)); 930 ret[0] = ring.getONE(); 931 ret[1] = this.inverse().multiply(half); 932 ret[2] = S.inverse().multiply(half); 933 return ret; 934 } 935 936 937 /** 938 * Returns the number of bits in the representation of this BigQuaternion, 939 * including a sign bit. It is equivalent to 940 * {@code re.bitLength()+im.bitLength()+jm.bitLength()+km.bitLength()}.) 941 * @return number of bits in the representation of this BigQuaternion, 942 * including a sign bit. 943 */ 944 public long bitLength() { 945 return re.bitLength() + im.bitLength() + jm.bitLength() + km.bitLength(); 946 } 947 948 949 /** 950 * BigQuaternion ceiling, component wise. 951 * @return ceiling of this. 952 */ 953 public BigQuaternion ceil() { 954 BigRational r = new BigRational(re.ceil()); 955 BigRational i = new BigRational(im.ceil()); 956 BigRational j = new BigRational(jm.ceil()); 957 BigRational k = new BigRational(km.ceil()); 958 return new BigQuaternion(ring, r, i, j, k); 959 } 960 961 962 /** 963 * BigQuaternion floor, component wise. 964 * @return floor of this. 965 */ 966 public BigQuaternion floor() { 967 BigRational r = new BigRational(re.floor()); 968 BigRational i = new BigRational(im.floor()); 969 BigRational j = new BigRational(jm.floor()); 970 BigRational k = new BigRational(km.floor()); 971 return new BigQuaternion(ring, r, i, j, k); 972 } 973 974 975 /** 976 * BigQuaternion round to next Lipschitz integer. BigQuaternion with all 977 * integer components. 978 * @return Lipschitz integer of this. 979 */ 980 public BigQuaternionInteger roundToLipschitzian() { 981 BigRational half = BigRational.HALF; 982 BigRational r = new BigRational(re.sum(half).floor()); 983 BigRational i = new BigRational(im.sum(half).floor()); 984 BigRational j = new BigRational(jm.sum(half).floor()); 985 BigRational k = new BigRational(km.sum(half).floor()); 986 return new BigQuaternionInteger(ring, r, i, j, k); 987 } 988 989 990 /** 991 * BigQuaternion round to next Hurwitz integer. BigQuaternion with all 992 * integer or all 1/2 times integer components. 993 * @return Hurwitz integer near this. 994 */ 995 public BigQuaternionInteger roundToHurwitzian() { 996 if (isEntier()) { 997 //System.out.println("*** short cut to round ***"); 998 return new BigQuaternionInteger(ring, this); 999 } 1000 BigQuaternionInteger g = this.roundToLipschitzian(); 1001 BigQuaternion d = ring.getZERO(); 1002 //BigRational half = BigRational.HALF; 1003 BigQuaternion s = this.subtract(g).norm(); 1004 //System.out.println("s = " + s.toScript()); 1005 //if (s.re.compareTo(half) < 0) { // wrong 1006 List<BigQuaternion> units = ring.unitsOfHurwitzian(); 1007 BigQuaternion t = null; 1008 for (BigQuaternion ue : units) { 1009 //t = this.subtract(g).sum(ue).norm(); // bug 1010 t = this.subtract(g.sum(ue)).norm(); 1011 if (t.re.compareTo(s.re) < 0) { 1012 s = t; 1013 d = ue; 1014 } 1015 } 1016 //System.out.println("ring = " + ring); 1017 g = new BigQuaternionInteger(ring, g.sum(d)); 1018 return g; 1019 } 1020 1021}