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