KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > JSci > maths > Complex


1 package JSci.maths;
2
3 import java.lang.Double JavaDoc;
4
5 import JSci.GlobalSettings;
6 import JSci.maths.groups.AbelianGroup;
7 import JSci.maths.fields.*;
8 import JSci.maths.algebras.*;
9
10 /**
11 * The Complex class encapsulates complex numbers.
12 * @jsci.planetmath Complex
13 * @version 2.25
14 * @author Mark Hale
15 */

16 public final class Complex extends Object JavaDoc implements Field.Member, CStarAlgebra.Member {
17         private static final long serialVersionUID = 6561957920497208796L;
18
19         private double re;
20         private double im;
21         /**
22         * Caching.
23         */

24         private transient boolean isModCached=false;
25         private transient double modCache;
26         private transient boolean isArgCached=false;
27         private transient double argCache;
28         /**
29         * The complex number 0+1i.
30         */

31         public static final Complex I=ComplexField.I;
32         /**
33         * The complex number 1+0i.
34         */

35         public static final Complex ONE=ComplexField.ONE;
36         /**
37         * The complex number 0+0i.
38         */

39         public static final Complex ZERO=ComplexField.ZERO;
40         /**
41         * Constructs the complex number x+iy.
42         * @param x the real value of a complex number.
43         * @param y the imaginary value of a complex number.
44         */

45         public Complex(final double x,final double y) {
46                 re=x;
47                 im=y;
48         }
49         /**
50         * Constructs the complex number represented by a string.
51         * @param s a string representing a complex number.
52         * @exception NumberFormatException if the string does not contain a parsable number.
53         */

54         public Complex(final String JavaDoc s) throws NumberFormatException JavaDoc {
55                 final int iPos = s.indexOf('i');
56                 if(iPos == -1) {
57                         // no 'i' so must be real
58
re = Double.parseDouble(s);
59                         im = 0.0;
60                 } else {
61                         int signPos = indexOf(s, '+', '-', 1);
62                         int expPos = indexOf(s, 'E', 'e', 1);
63                         if(signPos == expPos+1)
64                                 signPos = indexOf(s, '+', '-', signPos+1);
65                         String JavaDoc imStr;
66                         if(signPos == -1) {
67                                 re=0.0;
68                                 imStr=s;
69                         } else {
70                                 if(iPos<signPos) {
71                                         // im+re
72
imStr=s.substring(0,signPos);
73                                         re=Double.parseDouble(s.substring(signPos));
74                                 } else {
75                                         // re+im
76
re=Double.parseDouble(s.substring(0,signPos));
77                                         imStr=s.substring(signPos);
78                                 }
79                         }
80                         if(imStr.endsWith("i")) {
81                                 im=Double.parseDouble(imStr.substring(0,imStr.length()-1));
82                         } else {
83                                 char ch = imStr.charAt(0);
84                                 if(ch == 'i') {
85                                         im=Double.parseDouble(imStr.substring(1));
86                                 } else if((ch == '+' || ch == '-') && imStr.charAt(1) == 'i') {
87                                         im=Double.parseDouble(imStr.substring(2));
88                                         im=(ch == '+' ? im : -im);
89                                 } else
90                                         throw new NumberFormatException JavaDoc("The imaginary unit, 'i', is in an invalid position");
91                         }
92                 }
93         }
94         private static int indexOf(String JavaDoc s, char a, char b, final int start) {
95                 final int aPos = s.indexOf(a, start);
96                 final int bPos = s.indexOf(b, start);
97                 return (aPos == -1 ? bPos : aPos);
98         }
99         /**
100         * Creates a complex number with the given modulus and argument.
101         * @param mod the modulus of a complex number.
102         * @param arg the argument of a complex number.
103         */

104         public static Complex polar(final double mod,final double arg) {
105                 final Complex z=new Complex(mod*Math.cos(arg),mod*Math.sin(arg));
106                 z.modCache=mod;
107                 z.isModCached=true;
108                 z.argCache=arg;
109                 z.isArgCached=true;
110                 return z;
111         }
112         /**
113         * Compares two complex numbers for equality.
114         * @param obj a complex number.
115         */

116         public boolean equals(Object JavaDoc obj) {
117         return equals(obj, GlobalSettings.ZERO_TOL);
118         }
119     public boolean equals(Object JavaDoc obj, double tol) {
120                 if(obj instanceof Complex) {
121                         final Complex z=(Complex)obj;
122                         return equals(z.re,z.im,tol);
123                 } else
124                         return false;
125         }
126         /**
127         * Compares two complex numbers for equality.
128         */

129         public boolean equals(double real,double imag) {
130         return equals(real, imag, GlobalSettings.ZERO_TOL);
131         }
132     public boolean equals(double real, double imag, double tol) {
133                 return (mod(re-real, im-imag) <= tol);
134         }
135         /**
136         * Returns a string representing the value of this complex number.
137         */

138         public String JavaDoc toString() {
139                 return toString(re,im);
140         }
141         /**
142         * Returns a string representing the value of this complex number.
143         */

144         public static String JavaDoc toString(double real, double imag) {
145                 final StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
146                 buf.append(real);
147                 if(imag>=0.0)
148                         buf.append("+");
149                 buf.append(imag);
150                 buf.append("i");
151                 return buf.toString();
152         }
153         /**
154         * Returns a hashcode for this complex number.
155         */

156         public int hashCode() {
157                 return (int)(Math.exp(mod()));
158         }
159         /**
160         * Returns true if the modulus of this complex number is within the zero tolerance.
161         */

162         public boolean isZero() {
163                 return (mod() <= GlobalSettings.ZERO_TOL);
164         }
165         /**
166         * Returns true if either the real or imaginary part is NaN.
167         */

168         public boolean isNaN() {
169                 return (re==Double.NaN) || (im==Double.NaN);
170         }
171         /**
172         * Returns true if either the real or imaginary part is infinite.
173         */

174         public boolean isInfinite() {
175                 return (re==Double.POSITIVE_INFINITY) || (re==Double.NEGATIVE_INFINITY)
176                         || (im==Double.POSITIVE_INFINITY) || (im==Double.NEGATIVE_INFINITY);
177         }
178         /**
179         * Returns the real part of this complex number.
180         */

181         public double real() {
182                 return re;
183         }
184         /**
185         * Returns the imaginary part of this complex number.
186         */

187         public double imag() {
188                 return im;
189         }
190         /**
191         * Returns the modulus of this complex number.
192         */

193         public double mod() {
194                 if(isModCached)
195                         return modCache;
196                 modCache=mod(re,im);
197                 isModCached=true;
198                 return modCache;
199         }
200         private static double mod(final double real,final double imag) {
201                 final double reAbs=Math.abs(real);
202                 final double imAbs=Math.abs(imag);
203                 if(reAbs==0.0 && imAbs==0.0)
204                         return 0.0;
205                 else if(reAbs<imAbs)
206                         return imAbs*Math.sqrt(1.0+(real/imag)*(real/imag));
207                 else
208                         return reAbs*Math.sqrt(1.0+(imag/real)*(imag/real));
209         }
210         /**
211         * Returns the square of the modulus of this complex number.
212         */

213         public double modSqr() {
214                 return re*re+im*im;
215         }
216         /**
217         * Returns the argument of this complex number.
218         */

219         public double arg() {
220                 if(isArgCached)
221                         return argCache;
222                 argCache=arg(re,im);
223                 isArgCached=true;
224                 return argCache;
225         }
226         private static double arg(final double real,final double imag) {
227                 return Math.atan2(imag,real);
228         }
229         /**
230         * Returns the C<sup>*</sup> norm.
231         */

232         public double norm() {
233                 return mod();
234         }
235     public Object JavaDoc getSet() {
236         return ComplexField.getInstance();
237     }
238
239 //============
240
// OPERATIONS
241
//============
242

243         /**
244         * Returns the negative of this complex number.
245         */

246         public AbelianGroup.Member negate() {
247                 return new Complex(-re,-im);
248         }
249         /**
250         * Returns the inverse of this complex number.
251         */

252         public Field.Member inverse() {
253                 double denominator,real,imag;
254                 if(Math.abs(re)<Math.abs(im)) {
255                         real=re/im;
256                         imag=-1.0;
257                         denominator=re*real+im;
258                 } else {
259                         real=1.0;
260                         imag=-im/re;
261                         denominator=re-im*imag;
262                 }
263                 return new Complex(real/denominator,imag/denominator);
264         }
265         /**
266         * Returns the involution of this complex number.
267         */

268         public CStarAlgebra.Member involution() {
269                 return conjugate();
270         }
271         /**
272         * Returns the complex conjugate of this complex number.
273         */

274         public Complex conjugate() {
275                 return new Complex(re,-im);
276         }
277
278 // ADDITION
279

280         /**
281         * Returns the addition of this number and another.
282         */

283         public AbelianGroup.Member add(final AbelianGroup.Member x) {
284                 if(x instanceof Complex)
285                         return add((Complex)x);
286                 else if(x instanceof MathDouble)
287                         return addReal(((MathDouble)x).value());
288                 else if(x instanceof MathInteger)
289                         return addReal(((MathInteger)x).value());
290                 else
291                         throw new IllegalArgumentException JavaDoc("Member class not recognised by this method.");
292         }
293         /**
294         * Returns the addition of this complex number and another.
295         * @param z a complex number.
296         */

297         public Complex add(final Complex z) {
298                 return new Complex(re+z.re,im+z.im);
299         }
300         /**
301         * Returns the addition of this complex number with a real part.
302         * @param real a real part.
303         */

304         public Complex addReal(final double real) {
305                 return new Complex(re+real,im);
306         }
307         /**
308         * Returns the addition of this complex number with an imaginary part.
309         * @param imag an imaginary part.
310         */

311         public Complex addImag(final double imag) {
312                 return new Complex(re,im+imag);
313         }
314
315 // SUBTRACTION
316

317         /**
318         * Returns the subtraction of this number and another.
319         */

320         public AbelianGroup.Member subtract(final AbelianGroup.Member x) {
321                 if(x instanceof Complex)
322                         return subtract((Complex)x);
323                 else if(x instanceof MathDouble)
324                         return subtractReal(((MathDouble)x).value());
325                 else if(x instanceof MathInteger)
326                         return subtractReal(((MathInteger)x).value());
327                 else
328                         throw new IllegalArgumentException JavaDoc("Member class not recognised by this method.");
329         }
330         /**
331         * Returns the subtraction of this complex number by another.
332         * @param z a complex number.
333         */

334         public Complex subtract(final Complex z) {
335                 return new Complex(re-z.re,im-z.im);
336         }
337         /**
338         * Returns the subtraction of this complex number by a real part.
339         * @param real a real part.
340         */

341         public Complex subtractReal(final double real) {
342                 return new Complex(re-real,im);
343         }
344         /**
345         * Returns the subtraction of this complex number by an imaginary part.
346         * @param imag an imaginary part.
347         */

348         public Complex subtractImag(final double imag) {
349                 return new Complex(re,im-imag);
350         }
351
352 // MULTIPLICATION
353

354         /**
355         * Returns the multiplication of this number by a complex scalar.
356         */

357         public Module.Member scalarMultiply(final Ring.Member x) {
358                 return (Complex)multiply(x);
359         }
360         /**
361         * Returns the multiplication of this number and another.
362         */

363         public Ring.Member multiply(final Ring.Member x) {
364                 if(x instanceof Complex)
365                         return multiply((Complex)x);
366                 else if(x instanceof MathDouble)
367                         return multiply(((MathDouble)x).value());
368                 else if(x instanceof MathInteger)
369                         return multiply(((MathInteger)x).value());
370                 else
371                         throw new IllegalArgumentException JavaDoc("Member class not recognised by this method.");
372         }
373         /**
374         * Returns the multiplication of this complex number and another.
375         * @param z a complex number.
376         */

377         public Complex multiply(final Complex z) {
378                 return new Complex(re*z.re-im*z.im,re*z.im+im*z.re);
379         }
380         /**
381         * Returns the multiplication of this complex number by a scalar.
382         * @param x a real number.
383         */

384         public Complex multiply(final double x) {
385                 return new Complex(x*re,x*im);
386         }
387
388 // DIVISION
389

390         /**
391         * Returns the division of this number by a complex scalar.
392         */

393         public VectorSpace.Member scalarDivide(final Field.Member x) {
394                 return (Complex)divide(x);
395         }
396         /**
397         * Returns the division of this number and another.
398         */

399         public Field.Member divide(final Field.Member x) {
400                 if(x instanceof Complex)
401                         return divide((Complex)x);
402                 else if(x instanceof MathDouble)
403                         return divide(((MathDouble)x).value());
404                 else
405                         throw new IllegalArgumentException JavaDoc("Member class not recognised by this method.");
406         }
407         /**
408         * Returns the division of this complex number by another.
409         * @param z a complex number.
410         * @exception ArithmeticException If divide by zero.
411         */

412         public Complex divide(final Complex z) {
413                 final double denominator,real,imag,a;
414                 if(Math.abs(z.re)<Math.abs(z.im)) {
415                         a=z.re/z.im;
416                         denominator=z.re*a+z.im;
417                         real=re*a+im;
418                         imag=im*a-re;
419                 } else {
420                         a=z.im/z.re;
421                         denominator=z.re+z.im*a;
422                         real=re+im*a;
423                         imag=im-re*a;
424                 }
425                 return new Complex(real/denominator,imag/denominator);
426         }
427         /**
428         * Returns the division of this complex number by a scalar.
429         * @param x a real number.
430         * @exception ArithmeticException If divide by zero.
431         */

432         public Complex divide(final double x) {
433                 return new Complex(re/x,im/x);
434         }
435
436 // POWER
437

438         /**
439         * Returns this complex number raised to the power of another.
440         * @param z a complex number.
441         */

442         public Complex pow(final Complex z) {
443                 final double thisMod=mod();
444                 final double thisArg=arg();
445                 final double r=Math.pow(thisMod,z.re)/Math.exp(thisArg*z.im);
446                 final double a=thisArg*z.re+Math.log(thisMod)*z.im;
447                 return polar(r,a);
448         }
449         /**
450         * Returns this complex number raised to the power of a scalar.
451         * @param x a real number.
452         */

453         public Complex pow(final double x) {
454                 return polar(Math.pow(mod(),x),arg()*x);
455         }
456         /**
457         * Returns the square of this complex number.
458         */

459         public Complex sqr() {
460                 return new Complex(re*re-im*im,2.0*re*im);
461         }
462         /**
463         * Returns the square root of this complex number.
464         */

465         public Complex sqrt() {
466                 return polar(Math.sqrt(mod()),arg()/2.0);
467         }
468         private static Complex sqrt(final double real,final double imag) {
469                 return polar(Math.sqrt(mod(real,imag)),arg(real,imag)/2.0);
470         }
471
472 //===========
473
// FUNCTIONS
474
//===========
475

476 // EXP
477

478         /**
479         * Returns the exponential number e (2.718...) raised to the power of a complex number.
480         * @jsci.planetmath ExponentialFunction
481         * @param z a complex number.
482         */

483         public static Complex exp(final Complex z) {
484                 return new Complex(
485                         Math.exp(z.re)*Math.cos(z.im),
486                         Math.exp(z.re)*Math.sin(z.im)
487                 );
488         }
489
490 // LOG
491

492         /**
493         * Returns the natural logarithm (base e) of a complex number.
494         * @jsci.planetmath NaturalLogarithm2
495         * @param z a complex number.
496         */

497         public static Complex log(final Complex z) {
498                 return new Complex(Math.log(z.mod()),z.arg());
499         }
500         private final static Complex log(final double real,final double imag) {
501                 return new Complex(Math.log(mod(real,imag)),arg(real,imag));
502         }
503         private final static Complex log_2(final double real,final double imag) {
504                 return new Complex(Math.log(mod(real,imag))/2.0,arg(real,imag)/2.0);
505         }
506         private final static Complex log_2I(final double real,final double imag) {
507                 return new Complex(arg(real,imag)/2.0,-Math.log(mod(real,imag))/2.0);
508         }
509         private final static Complex log_2IplusPI_2(final double real,final double imag) {
510                 return new Complex((arg(real,imag)+Math.PI)/2.0,-Math.log(mod(real,imag))/2.0);
511         }
512
513 // SIN
514

515         /**
516         * Returns the trigonometric sine of a complex angle.
517         * @param z an angle that is measured in radians.
518         */

519         public static Complex sin(final Complex z) {
520                 return new Complex(
521                         Math.sin(z.re)*ExtraMath.cosh(z.im),
522                         Math.cos(z.re)*ExtraMath.sinh(z.im)
523                 );
524         }
525
526 // COS
527

528         /**
529         * Returns the trigonometric cosine of a complex angle.
530         * @param z an angle that is measured in radians.
531         */

532         public static Complex cos(final Complex z) {
533                 return new Complex(
534                         Math.cos(z.re)*ExtraMath.cosh(z.im),
535                        -Math.sin(z.re)*ExtraMath.sinh(z.im)
536                 );
537         }
538
539 // TAN
540

541         /**
542         * Returns the trigonometric tangent of a complex angle.
543         * @param z an angle that is measured in radians.
544         */

545         public static Complex tan(final Complex z) {
546                 final double sinRe=Math.sin(z.re);
547                 final double cosRe=Math.cos(z.re);
548                 final double sinhIm=ExtraMath.sinh(z.im);
549                 final double coshIm=ExtraMath.cosh(z.im);
550                 final double denom=cosRe*cosRe*coshIm*coshIm+sinRe*sinRe*sinhIm*sinhIm;
551                 return new Complex(sinRe*cosRe/denom,sinhIm*coshIm/denom);
552         }
553
554 // SINH
555

556         /**
557         * Returns the hyperbolic sine of a complex number.
558         * @param z a complex number.
559         */

560         public static Complex sinh(final Complex z) {
561                 return new Complex(
562                         ExtraMath.sinh(z.re)*Math.cos(z.im),
563                         ExtraMath.cosh(z.re)*Math.sin(z.im)
564                 );
565         }
566
567 // COSH
568

569         /**
570         * Returns the hyperbolic cosine of a complex number.
571         * @param z a complex number.
572         */

573         public static Complex cosh(final Complex z) {
574                 return new Complex(
575                         ExtraMath.cosh(z.re)*Math.cos(z.im),
576                         ExtraMath.sinh(z.re)*Math.sin(z.im)
577                 );
578         }
579
580 // TANH
581

582         /**
583         * Returns the hyperbolic tangent of a complex number.
584         * @param z a complex number.
585         */

586         public static Complex tanh(final Complex z) {
587                 final double sinhRe=ExtraMath.sinh(z.re);
588                 final double coshRe=ExtraMath.cosh(z.re);
589                 final double sinIm=Math.sin(z.im);
590                 final double cosIm=Math.cos(z.im);
591                 final double denom=coshRe*coshRe*cosIm*cosIm+sinhRe*sinhRe*sinIm*sinIm;
592                 return new Complex(sinhRe*coshRe/denom,sinIm*cosIm/denom);
593         }
594
595 // INVERSE SIN
596

597         /**
598         * Returns the arc sine of a complex number, in the range of
599         * (-<img border=0 alt="pi" SRC="doc-files/pi.gif">/2 through <img border=0 alt="pi" SRC="doc-files/pi.gif">/2,
600         * -<img border=0 alt="infinity" SRC="doc-files/infinity.gif"> through <img border=0 alt="infinity" SRC="doc-files/infinity.gif">).
601         * @param z a complex number.
602         */

603         public static Complex asin(final Complex z) {
604                 if(z.equals(ONE))
605                         return ComplexField.PI_2;
606                 else if(z.equals(ComplexField.MINUS_ONE))
607                         return ComplexField.MINUS_PI_2;
608                 else {
609                         // atan(z/sqrt(1-z*z))
610
final Complex root=sqrt(1.0-z.re*z.re+z.im*z.im,-2.0*z.re*z.im);
611                         final double zModSqr=z.re*z.re+z.im*z.im;
612                         final double rootModSqr=root.re*root.re+root.im*root.im;
613                         final double denom=rootModSqr+zModSqr+2.0*(root.re*z.im-root.im*z.re);
614                         return log_2I((rootModSqr-zModSqr)/denom,2.0*(root.re*z.re+root.im*z.im)/denom);
615                 }
616         }
617
618 // INVERSE COS
619

620         /**
621         * Returns the arc cosine of a complex number, in the range of
622         * (0.0 through <img border=0 alt="pi" SRC="doc-files/pi.gif">,
623         * 0.0 through <img border=0 alt="infinity" SRC="doc-files/infinity.gif">).
624         * @param z a complex number.
625         */

626         public static Complex acos(final Complex z) {
627                 if(z.equals(ONE))
628                         return ZERO;
629                 else if(z.equals(ComplexField.MINUS_ONE))
630                         return ComplexField.PI;
631                 else {
632                         // atan(-z/sqrt(1-z*z))+PI/2
633
final Complex root=sqrt(1.0-z.re*z.re+z.im*z.im,-2.0*z.re*z.im);
634                         final double zModSqr=z.re*z.re+z.im*z.im;
635                         final double rootModSqr=root.re*root.re+root.im*root.im;
636                         final double denom=rootModSqr+zModSqr+2.0*(root.im*z.re-root.re*z.im);
637                         return log_2IplusPI_2((rootModSqr-zModSqr)/denom,-2.0*(root.re*z.re+root.im*z.im)/denom);
638                 }
639         }
640
641 // INVERSE TAN
642

643         /**
644         * Returns the arc tangent of a complex number, in the range of
645         * (-<img border=0 alt="pi" SRC="doc-files/pi.gif">/2 through <img border=0 alt="pi" SRC="doc-files/pi.gif">/2,
646         * -<img border=0 alt="infinity" SRC="doc-files/infinity.gif"> through <img border=0 alt="infinity" SRC="doc-files/infinity.gif">).
647         * @param z a complex number.
648         */

649         public static Complex atan(final Complex z) {
650                 // -i atanh(iz) = -i/2 log((1+iz)/(1-iz))
651
final double modSqr=z.modSqr();
652                 final double denom=1.0+modSqr+2.0*z.im;
653                 return log_2I((1.0-modSqr)/denom,2.0*z.re/denom);
654         }
655
656 // INVERSE SINH
657

658         /**
659         * Returns the arc hyperbolic sine of a complex number, in the range of
660         * (-<img border=0 alt="infinity" SRC="doc-files/infinity.gif"> through <img border=0 alt="infinity" SRC="doc-files/infinity.gif">,
661         * -<img border=0 alt="pi" SRC="doc-files/pi.gif">/2 through <img border=0 alt="pi" SRC="doc-files/pi.gif">/2).
662         * @param z a complex number.
663         */

664         public static Complex asinh(final Complex z) {
665                 if(z.equals(I))
666                         return ComplexField.PI_2_I;
667                 else if(z.equals(ComplexField.MINUS_I))
668                         return ComplexField.MINUS_PI_2_I;
669                 else {
670                         // log(z+sqrt(z*z+1))
671
final Complex root=sqrt(z.re*z.re-z.im*z.im+1.0,2.0*z.re*z.im);
672                         return log(z.re+root.re,z.im+root.im);
673                 }
674         }
675
676 // INVERSE COSH
677

678         /**
679         * Returns the arc hyperbolic cosine of a complex number, in the range of
680         * (0.0 through <img border=0 alt="infinity" SRC="doc-files/infinity.gif">,
681         * 0.0 through <img border=0 alt="pi" SRC="doc-files/pi.gif">).
682         * @param z a complex number.
683         */

684         public static Complex acosh(final Complex z) {
685                 if(z.equals(ONE))
686                         return ZERO;
687                 else if(z.equals(ComplexField.MINUS_ONE))
688                         return ComplexField.PI_I;
689                 else {
690                         // log(z+sqrt(z*z-1))
691
final Complex root=sqrt(z.re*z.re-z.im*z.im-1.0,2.0*z.re*z.im);
692                         return log(z.re+root.re,z.im+root.im);
693                 }
694         }
695
696 // INVERSE TANH
697

698         /**
699         * Returns the arc hyperbolic tangent of a complex number, in the range of
700         * (-<img border=0 alt="infinity" SRC="doc-files/infinity.gif"> through <img border=0 alt="infinity" SRC="doc-files/infinity.gif">,
701         * -<img border=0 alt="pi" SRC="doc-files/pi.gif">/2 through <img border=0 alt="pi" SRC="doc-files/pi.gif">/2).
702         * @param z a complex number.
703         */

704         public static Complex atanh(final Complex z) {
705                 // 1/2 log((1+z)/(1-z))
706
final double modSqr=z.modSqr();
707                 final double denom=1.0+modSqr-2.0*z.re;
708                 return log_2((1.0-modSqr)/denom,2.0*z.im/denom);
709         }
710 }
711
Popular Tags