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