%mathpiper,def="Complex"

0 # Complex(_r,i_IsZero) <-- r;
2 # Complex(Complex(_r1,_i1),_i2) <-- Complex(r1,i1+i2);
2 # Complex(_r1,Complex(_r2,_i2)) <-- Complex(r1-i2,r2);

6 # Complex(Undefined,_x) <-- Undefined;
6 # Complex(_x,Undefined) <-- Undefined;


/* Addition */

110 # Complex(_r1,_i1) + Complex(_r2,_i2) <-- Complex(r1+r2,i1+i2);
300 # Complex(_r,_i) + x_IsConstant <-- Complex(r+x,i);
300 # x_IsConstant + Complex(_r,_i) <-- Complex(r+x,i);

110 # - Complex(_r,_i) <-- Complex(-r,-i);

300 # Complex(_r,_i) - x_IsConstant <-- Complex(r-x,i);
300 # x_IsConstant - Complex(_r,_i) <-- Complex((-r)+x,-i);
111 # Complex(_r1,_i1) - Complex(_r2,_i2) <-- Complex(r1-r2,i1-i2);

/* Multiplication */
110 # Complex(_r1,_i1) * Complex(_r2,_i2) <-- Complex(r1*r2-i1*i2,r1*i2+r2*i1);
/* right now this is slower than above
110 # Complex(_r1,_i1) * Complex(_r2,_i2) <--
[	// the Karatsuba trick
	Local(A,B);
	A:=r1*r2;
	B:=i1*i2;
	Complex(A-B,(r1+i1)*(r2+i2)-A-B);
];
*/


// Multiplication in combination with complex numbers in the light of infinity
250 # Complex(r_IsZero,_i) * x_IsInfinity <-- Complex(0,i*x);
250 # Complex(_r,i_IsZero) * x_IsInfinity <-- Complex(r*x,0);
251 # Complex(_r,_i) * x_IsInfinity <-- Complex(r*x,i*x);

250 # x_IsInfinity * Complex(r_IsZero,_i) <-- Complex(0,i*x);
250 # x_IsInfinity * Complex(_r,i_IsZero) <-- Complex(r*x,0);
251 # x_IsInfinity * Complex(_r,_i) <-- Complex(r*x,i*x);


300 # Complex(_r,_i) * y_IsConstant <-- Complex(r*y,i*y);
300 # y_IsConstant * Complex(_r,_i) <-- Complex(r*y,i*y);

330 # Complex(_r,_i) * (y_IsConstant / _z) <-- (Complex(r*y,i*y))/z;
330 # (y_IsConstant / _z) * Complex(_r,_i) <-- (Complex(r*y,i*y))/z;


110 # x_IsConstant / Complex(_r,_i) <-- (x*Conjugate(Complex(r,i)))/(r^2+i^2);


300 # Complex(_r,_i) / y_IsConstant <-- Complex(r/y,i/y);

110 # (_x ^ Complex(_r,_i)) <-- Exp(Complex(r,i)*Ln(x));

110 # Sqrt(Complex(_r,_i)) <-- Exp(Ln(Complex(r,i))/2);
110 # (Complex(_r,_i) ^ x_IsRationalOrNumber)_(Not(IsInteger(x))) <-- Exp(x*Ln(Complex(r,i)));

// This is commented out because it used PowerN so (2*I)^(-10) became a floating-point number. Now everything is handled by binary algorithm below
//120 # Complex(r_IsZero,_i) ^ n_IsInteger <-- {1,I,-1,-I}[1+Modulo(n,4)] * i^n;

123 # Complex(_r, _i) ^ n_IsNegativeInteger <-- 1/Complex(r, i)^(-n);

124 # Complex(_r, _i) ^ (p_IsZero) <-- 1;	// cannot have Complex(0,0) here

125 # Complex(_r, _i) ^ n_IsPositiveInteger <--
[
	// use binary method
	Local(result, x);
	x:=Complex(r,i);
	result:=1;
	While(n > 0)
	[
		if ((n&1) = 1)
		[
		  result := result*x;
		];
		x := x*x;
		n := n>>1;
	];
	result;
];


/*[	// this method is disabled b/c it suffers from severe roundoff errors
  Local(rr,ii,count,sign);
  rr:=r^n;
  ii:=0;
  For(count:=1,count<=n,count:=count+2) [
    sign:=If(IsZero(Modulo(count-1,4)),1,-1);
    ii:=ii+sign*BinomialCoefficient(n,count)*i^count*r^(n-count);
    If(count<n,
      rr:=rr-sign*BinomialCoefficient(n,count+1)*i^(count+1)*r^(n-count-1));
  ];
  Complex(rr,ii);
];
*/

%/mathpiper



%mathpiper_docs,name="Complex",categories="User Functions;Numbers (Complex)"
*CMD Complex --- construct a complex number
*STD
*CALL
	Complex(r, c)

*PARMS

{r} -- real part

{c} -- imaginary part

*DESC

This function represents the complex number "r + I*c", where "I"
is the imaginary unit. It is the standard representation used in MathPiper
to represent complex numbers. Both "r" and "c" are supposed to be
real.

Note that, at the moment, many functions in MathPiper assume that all
numbers are real unless it is obvious that it is a complex
number. Hence {Im(Sqrt(x))} evaluates to {0} which is only true for nonnegative "x".

*E.G.

In> I
Result: Complex(0,1);
In> 3+4*I
Result: Complex(3,4);
In> Complex(-2,0)
Result: -2;

*SEE Re, Im, I, Abs, Arg
%/mathpiper_docs