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