xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/lib/Math/Complex.pm (revision 0:68f95e015346)
1*0Sstevel@tonic-gate#
2*0Sstevel@tonic-gate# Complex numbers and associated mathematical functions
3*0Sstevel@tonic-gate# -- Raphael Manfredi	Since Sep 1996
4*0Sstevel@tonic-gate# -- Jarkko Hietaniemi	Since Mar 1997
5*0Sstevel@tonic-gate# -- Daniel S. Lewart	Since Sep 1997
6*0Sstevel@tonic-gate#
7*0Sstevel@tonic-gate
8*0Sstevel@tonic-gatepackage Math::Complex;
9*0Sstevel@tonic-gate
10*0Sstevel@tonic-gateour($VERSION, @ISA, @EXPORT, %EXPORT_TAGS, $Inf);
11*0Sstevel@tonic-gate
12*0Sstevel@tonic-gate$VERSION = 1.34;
13*0Sstevel@tonic-gate
14*0Sstevel@tonic-gateBEGIN {
15*0Sstevel@tonic-gate    unless ($^O eq 'unicosmk') {
16*0Sstevel@tonic-gate        my $e = $!;
17*0Sstevel@tonic-gate	# We do want an arithmetic overflow, Inf INF inf Infinity:.
18*0Sstevel@tonic-gate        undef $Inf unless eval <<'EOE' and $Inf =~ /^inf(?:inity)?$/i;
19*0Sstevel@tonic-gate	  local $SIG{FPE} = sub {die};
20*0Sstevel@tonic-gate	  my $t = CORE::exp 30;
21*0Sstevel@tonic-gate	  $Inf = CORE::exp $t;
22*0Sstevel@tonic-gateEOE
23*0Sstevel@tonic-gate	if (!defined $Inf) {		# Try a different method
24*0Sstevel@tonic-gate	  undef $Inf unless eval <<'EOE' and $Inf =~ /^inf(?:inity)?$/i;
25*0Sstevel@tonic-gate	    local $SIG{FPE} = sub {die};
26*0Sstevel@tonic-gate	    my $t = 1;
27*0Sstevel@tonic-gate	    $Inf = $t + "1e99999999999999999999999999999999";
28*0Sstevel@tonic-gateEOE
29*0Sstevel@tonic-gate	}
30*0Sstevel@tonic-gate        $! = $e; # Clear ERANGE.
31*0Sstevel@tonic-gate    }
32*0Sstevel@tonic-gate    $Inf = "Inf" if !defined $Inf || !($Inf > 0); # Desperation.
33*0Sstevel@tonic-gate}
34*0Sstevel@tonic-gate
35*0Sstevel@tonic-gateuse strict;
36*0Sstevel@tonic-gate
37*0Sstevel@tonic-gatemy $i;
38*0Sstevel@tonic-gatemy %LOGN;
39*0Sstevel@tonic-gate
40*0Sstevel@tonic-gate# Regular expression for floating point numbers.
41*0Sstevel@tonic-gatemy $gre = qr'\s*([\+\-]?(?:(?:(?:\d+(?:_\d+)*(?:\.\d*(?:_\d+)*)?|\.\d+(?:_\d+)*)(?:[eE][\+\-]?\d+(?:_\d+)*)?)))';
42*0Sstevel@tonic-gate
43*0Sstevel@tonic-gaterequire Exporter;
44*0Sstevel@tonic-gate
45*0Sstevel@tonic-gate@ISA = qw(Exporter);
46*0Sstevel@tonic-gate
47*0Sstevel@tonic-gatemy @trig = qw(
48*0Sstevel@tonic-gate	      pi
49*0Sstevel@tonic-gate	      tan
50*0Sstevel@tonic-gate	      csc cosec sec cot cotan
51*0Sstevel@tonic-gate	      asin acos atan
52*0Sstevel@tonic-gate	      acsc acosec asec acot acotan
53*0Sstevel@tonic-gate	      sinh cosh tanh
54*0Sstevel@tonic-gate	      csch cosech sech coth cotanh
55*0Sstevel@tonic-gate	      asinh acosh atanh
56*0Sstevel@tonic-gate	      acsch acosech asech acoth acotanh
57*0Sstevel@tonic-gate	     );
58*0Sstevel@tonic-gate
59*0Sstevel@tonic-gate@EXPORT = (qw(
60*0Sstevel@tonic-gate	     i Re Im rho theta arg
61*0Sstevel@tonic-gate	     sqrt log ln
62*0Sstevel@tonic-gate	     log10 logn cbrt root
63*0Sstevel@tonic-gate	     cplx cplxe
64*0Sstevel@tonic-gate	     ),
65*0Sstevel@tonic-gate	   @trig);
66*0Sstevel@tonic-gate
67*0Sstevel@tonic-gate%EXPORT_TAGS = (
68*0Sstevel@tonic-gate    'trig' => [@trig],
69*0Sstevel@tonic-gate);
70*0Sstevel@tonic-gate
71*0Sstevel@tonic-gateuse overload
72*0Sstevel@tonic-gate	'+'	=> \&plus,
73*0Sstevel@tonic-gate	'-'	=> \&minus,
74*0Sstevel@tonic-gate	'*'	=> \&multiply,
75*0Sstevel@tonic-gate	'/'	=> \&divide,
76*0Sstevel@tonic-gate	'**'	=> \&power,
77*0Sstevel@tonic-gate	'=='	=> \&numeq,
78*0Sstevel@tonic-gate	'<=>'	=> \&spaceship,
79*0Sstevel@tonic-gate	'neg'	=> \&negate,
80*0Sstevel@tonic-gate	'~'	=> \&conjugate,
81*0Sstevel@tonic-gate	'abs'	=> \&abs,
82*0Sstevel@tonic-gate	'sqrt'	=> \&sqrt,
83*0Sstevel@tonic-gate	'exp'	=> \&exp,
84*0Sstevel@tonic-gate	'log'	=> \&log,
85*0Sstevel@tonic-gate	'sin'	=> \&sin,
86*0Sstevel@tonic-gate	'cos'	=> \&cos,
87*0Sstevel@tonic-gate	'tan'	=> \&tan,
88*0Sstevel@tonic-gate	'atan2'	=> \&atan2,
89*0Sstevel@tonic-gate	qw("" stringify);
90*0Sstevel@tonic-gate
91*0Sstevel@tonic-gate#
92*0Sstevel@tonic-gate# Package "privates"
93*0Sstevel@tonic-gate#
94*0Sstevel@tonic-gate
95*0Sstevel@tonic-gatemy %DISPLAY_FORMAT = ('style' => 'cartesian',
96*0Sstevel@tonic-gate		      'polar_pretty_print' => 1);
97*0Sstevel@tonic-gatemy $eps            = 1e-14;		# Epsilon
98*0Sstevel@tonic-gate
99*0Sstevel@tonic-gate#
100*0Sstevel@tonic-gate# Object attributes (internal):
101*0Sstevel@tonic-gate#	cartesian	[real, imaginary] -- cartesian form
102*0Sstevel@tonic-gate#	polar		[rho, theta] -- polar form
103*0Sstevel@tonic-gate#	c_dirty		cartesian form not up-to-date
104*0Sstevel@tonic-gate#	p_dirty		polar form not up-to-date
105*0Sstevel@tonic-gate#	display		display format (package's global when not set)
106*0Sstevel@tonic-gate#
107*0Sstevel@tonic-gate
108*0Sstevel@tonic-gate# Die on bad *make() arguments.
109*0Sstevel@tonic-gate
110*0Sstevel@tonic-gatesub _cannot_make {
111*0Sstevel@tonic-gate    die "@{[(caller(1))[3]]}: Cannot take $_[0] of $_[1].\n";
112*0Sstevel@tonic-gate}
113*0Sstevel@tonic-gate
114*0Sstevel@tonic-gatesub _remake {
115*0Sstevel@tonic-gate    my $arg = shift;
116*0Sstevel@tonic-gate    my ($made, $p, $q);
117*0Sstevel@tonic-gate
118*0Sstevel@tonic-gate    if ($arg =~ /^(?:$gre)?$gre\s*i\s*$/) {
119*0Sstevel@tonic-gate	($p, $q) = ($1 || 0, $2);
120*0Sstevel@tonic-gate	$made = 'cart';
121*0Sstevel@tonic-gate    } elsif ($arg =~ /^\s*\[\s*$gre\s*(?:,\s*$gre\s*)?\]\s*$/) {
122*0Sstevel@tonic-gate	($p, $q) = ($1, $2 || 0);
123*0Sstevel@tonic-gate	$made = 'exp';
124*0Sstevel@tonic-gate    }
125*0Sstevel@tonic-gate
126*0Sstevel@tonic-gate    if ($made) {
127*0Sstevel@tonic-gate	$p =~ s/^\+//;
128*0Sstevel@tonic-gate	$q =~ s/^\+//;
129*0Sstevel@tonic-gate    }
130*0Sstevel@tonic-gate
131*0Sstevel@tonic-gate    return ($made, $p, $q);
132*0Sstevel@tonic-gate}
133*0Sstevel@tonic-gate
134*0Sstevel@tonic-gate#
135*0Sstevel@tonic-gate# ->make
136*0Sstevel@tonic-gate#
137*0Sstevel@tonic-gate# Create a new complex number (cartesian form)
138*0Sstevel@tonic-gate#
139*0Sstevel@tonic-gatesub make {
140*0Sstevel@tonic-gate	my $self = bless {}, shift;
141*0Sstevel@tonic-gate	my ($re, $im) = @_;
142*0Sstevel@tonic-gate	if (@_ == 1) {
143*0Sstevel@tonic-gate	    my ($remade, $p, $q) = _remake($re);
144*0Sstevel@tonic-gate	    if ($remade) {
145*0Sstevel@tonic-gate		if ($remade eq 'cart') {
146*0Sstevel@tonic-gate		    ($re, $im) = ($p, $q);
147*0Sstevel@tonic-gate		} else {
148*0Sstevel@tonic-gate		    return (ref $self)->emake($p, $q);
149*0Sstevel@tonic-gate		}
150*0Sstevel@tonic-gate	    }
151*0Sstevel@tonic-gate	}
152*0Sstevel@tonic-gate	my $rre = ref $re;
153*0Sstevel@tonic-gate	if ( $rre ) {
154*0Sstevel@tonic-gate	    if ( $rre eq ref $self ) {
155*0Sstevel@tonic-gate		$re = Re($re);
156*0Sstevel@tonic-gate	    } else {
157*0Sstevel@tonic-gate		_cannot_make("real part", $rre);
158*0Sstevel@tonic-gate	    }
159*0Sstevel@tonic-gate	}
160*0Sstevel@tonic-gate	my $rim = ref $im;
161*0Sstevel@tonic-gate	if ( $rim ) {
162*0Sstevel@tonic-gate	    if ( $rim eq ref $self ) {
163*0Sstevel@tonic-gate		$im = Im($im);
164*0Sstevel@tonic-gate	    } else {
165*0Sstevel@tonic-gate		_cannot_make("imaginary part", $rim);
166*0Sstevel@tonic-gate	    }
167*0Sstevel@tonic-gate	}
168*0Sstevel@tonic-gate	_cannot_make("real part",      $re) unless $re =~ /^$gre$/;
169*0Sstevel@tonic-gate	$im ||= 0;
170*0Sstevel@tonic-gate	_cannot_make("imaginary part", $im) unless $im =~ /^$gre$/;
171*0Sstevel@tonic-gate	$self->{'cartesian'} = [ $re, $im ];
172*0Sstevel@tonic-gate	$self->{c_dirty} = 0;
173*0Sstevel@tonic-gate	$self->{p_dirty} = 1;
174*0Sstevel@tonic-gate	$self->display_format('cartesian');
175*0Sstevel@tonic-gate	return $self;
176*0Sstevel@tonic-gate}
177*0Sstevel@tonic-gate
178*0Sstevel@tonic-gate#
179*0Sstevel@tonic-gate# ->emake
180*0Sstevel@tonic-gate#
181*0Sstevel@tonic-gate# Create a new complex number (exponential form)
182*0Sstevel@tonic-gate#
183*0Sstevel@tonic-gatesub emake {
184*0Sstevel@tonic-gate	my $self = bless {}, shift;
185*0Sstevel@tonic-gate	my ($rho, $theta) = @_;
186*0Sstevel@tonic-gate	if (@_ == 1) {
187*0Sstevel@tonic-gate	    my ($remade, $p, $q) = _remake($rho);
188*0Sstevel@tonic-gate	    if ($remade) {
189*0Sstevel@tonic-gate		if ($remade eq 'exp') {
190*0Sstevel@tonic-gate		    ($rho, $theta) = ($p, $q);
191*0Sstevel@tonic-gate		} else {
192*0Sstevel@tonic-gate		    return (ref $self)->make($p, $q);
193*0Sstevel@tonic-gate		}
194*0Sstevel@tonic-gate	    }
195*0Sstevel@tonic-gate	}
196*0Sstevel@tonic-gate	my $rrh = ref $rho;
197*0Sstevel@tonic-gate	if ( $rrh ) {
198*0Sstevel@tonic-gate	    if ( $rrh eq ref $self ) {
199*0Sstevel@tonic-gate		$rho = rho($rho);
200*0Sstevel@tonic-gate	    } else {
201*0Sstevel@tonic-gate		_cannot_make("rho", $rrh);
202*0Sstevel@tonic-gate	    }
203*0Sstevel@tonic-gate	}
204*0Sstevel@tonic-gate	my $rth = ref $theta;
205*0Sstevel@tonic-gate	if ( $rth ) {
206*0Sstevel@tonic-gate	    if ( $rth eq ref $self ) {
207*0Sstevel@tonic-gate		$theta = theta($theta);
208*0Sstevel@tonic-gate	    } else {
209*0Sstevel@tonic-gate		_cannot_make("theta", $rth);
210*0Sstevel@tonic-gate	    }
211*0Sstevel@tonic-gate	}
212*0Sstevel@tonic-gate	if ($rho < 0) {
213*0Sstevel@tonic-gate	    $rho   = -$rho;
214*0Sstevel@tonic-gate	    $theta = ($theta <= 0) ? $theta + pi() : $theta - pi();
215*0Sstevel@tonic-gate	}
216*0Sstevel@tonic-gate	_cannot_make("rho",   $rho)   unless $rho   =~ /^$gre$/;
217*0Sstevel@tonic-gate	$theta ||= 0;
218*0Sstevel@tonic-gate	_cannot_make("theta", $theta) unless $theta =~ /^$gre$/;
219*0Sstevel@tonic-gate	$self->{'polar'} = [$rho, $theta];
220*0Sstevel@tonic-gate	$self->{p_dirty} = 0;
221*0Sstevel@tonic-gate	$self->{c_dirty} = 1;
222*0Sstevel@tonic-gate	$self->display_format('polar');
223*0Sstevel@tonic-gate	return $self;
224*0Sstevel@tonic-gate}
225*0Sstevel@tonic-gate
226*0Sstevel@tonic-gatesub new { &make }		# For backward compatibility only.
227*0Sstevel@tonic-gate
228*0Sstevel@tonic-gate#
229*0Sstevel@tonic-gate# cplx
230*0Sstevel@tonic-gate#
231*0Sstevel@tonic-gate# Creates a complex number from a (re, im) tuple.
232*0Sstevel@tonic-gate# This avoids the burden of writing Math::Complex->make(re, im).
233*0Sstevel@tonic-gate#
234*0Sstevel@tonic-gatesub cplx {
235*0Sstevel@tonic-gate	return __PACKAGE__->make(@_);
236*0Sstevel@tonic-gate}
237*0Sstevel@tonic-gate
238*0Sstevel@tonic-gate#
239*0Sstevel@tonic-gate# cplxe
240*0Sstevel@tonic-gate#
241*0Sstevel@tonic-gate# Creates a complex number from a (rho, theta) tuple.
242*0Sstevel@tonic-gate# This avoids the burden of writing Math::Complex->emake(rho, theta).
243*0Sstevel@tonic-gate#
244*0Sstevel@tonic-gatesub cplxe {
245*0Sstevel@tonic-gate	return __PACKAGE__->emake(@_);
246*0Sstevel@tonic-gate}
247*0Sstevel@tonic-gate
248*0Sstevel@tonic-gate#
249*0Sstevel@tonic-gate# pi
250*0Sstevel@tonic-gate#
251*0Sstevel@tonic-gate# The number defined as pi = 180 degrees
252*0Sstevel@tonic-gate#
253*0Sstevel@tonic-gatesub pi () { 4 * CORE::atan2(1, 1) }
254*0Sstevel@tonic-gate
255*0Sstevel@tonic-gate#
256*0Sstevel@tonic-gate# pit2
257*0Sstevel@tonic-gate#
258*0Sstevel@tonic-gate# The full circle
259*0Sstevel@tonic-gate#
260*0Sstevel@tonic-gatesub pit2 () { 2 * pi }
261*0Sstevel@tonic-gate
262*0Sstevel@tonic-gate#
263*0Sstevel@tonic-gate# pip2
264*0Sstevel@tonic-gate#
265*0Sstevel@tonic-gate# The quarter circle
266*0Sstevel@tonic-gate#
267*0Sstevel@tonic-gatesub pip2 () { pi / 2 }
268*0Sstevel@tonic-gate
269*0Sstevel@tonic-gate#
270*0Sstevel@tonic-gate# deg1
271*0Sstevel@tonic-gate#
272*0Sstevel@tonic-gate# One degree in radians, used in stringify_polar.
273*0Sstevel@tonic-gate#
274*0Sstevel@tonic-gate
275*0Sstevel@tonic-gatesub deg1 () { pi / 180 }
276*0Sstevel@tonic-gate
277*0Sstevel@tonic-gate#
278*0Sstevel@tonic-gate# uplog10
279*0Sstevel@tonic-gate#
280*0Sstevel@tonic-gate# Used in log10().
281*0Sstevel@tonic-gate#
282*0Sstevel@tonic-gatesub uplog10 () { 1 / CORE::log(10) }
283*0Sstevel@tonic-gate
284*0Sstevel@tonic-gate#
285*0Sstevel@tonic-gate# i
286*0Sstevel@tonic-gate#
287*0Sstevel@tonic-gate# The number defined as i*i = -1;
288*0Sstevel@tonic-gate#
289*0Sstevel@tonic-gatesub i () {
290*0Sstevel@tonic-gate        return $i if ($i);
291*0Sstevel@tonic-gate	$i = bless {};
292*0Sstevel@tonic-gate	$i->{'cartesian'} = [0, 1];
293*0Sstevel@tonic-gate	$i->{'polar'}     = [1, pip2];
294*0Sstevel@tonic-gate	$i->{c_dirty} = 0;
295*0Sstevel@tonic-gate	$i->{p_dirty} = 0;
296*0Sstevel@tonic-gate	return $i;
297*0Sstevel@tonic-gate}
298*0Sstevel@tonic-gate
299*0Sstevel@tonic-gate#
300*0Sstevel@tonic-gate# ip2
301*0Sstevel@tonic-gate#
302*0Sstevel@tonic-gate# Half of i.
303*0Sstevel@tonic-gate#
304*0Sstevel@tonic-gatesub ip2 () { i / 2 }
305*0Sstevel@tonic-gate
306*0Sstevel@tonic-gate#
307*0Sstevel@tonic-gate# Attribute access/set routines
308*0Sstevel@tonic-gate#
309*0Sstevel@tonic-gate
310*0Sstevel@tonic-gatesub cartesian {$_[0]->{c_dirty} ?
311*0Sstevel@tonic-gate		   $_[0]->update_cartesian : $_[0]->{'cartesian'}}
312*0Sstevel@tonic-gatesub polar     {$_[0]->{p_dirty} ?
313*0Sstevel@tonic-gate		   $_[0]->update_polar : $_[0]->{'polar'}}
314*0Sstevel@tonic-gate
315*0Sstevel@tonic-gatesub set_cartesian { $_[0]->{p_dirty}++; $_[0]->{'cartesian'} = $_[1] }
316*0Sstevel@tonic-gatesub set_polar     { $_[0]->{c_dirty}++; $_[0]->{'polar'} = $_[1] }
317*0Sstevel@tonic-gate
318*0Sstevel@tonic-gate#
319*0Sstevel@tonic-gate# ->update_cartesian
320*0Sstevel@tonic-gate#
321*0Sstevel@tonic-gate# Recompute and return the cartesian form, given accurate polar form.
322*0Sstevel@tonic-gate#
323*0Sstevel@tonic-gatesub update_cartesian {
324*0Sstevel@tonic-gate	my $self = shift;
325*0Sstevel@tonic-gate	my ($r, $t) = @{$self->{'polar'}};
326*0Sstevel@tonic-gate	$self->{c_dirty} = 0;
327*0Sstevel@tonic-gate	return $self->{'cartesian'} = [$r * CORE::cos($t), $r * CORE::sin($t)];
328*0Sstevel@tonic-gate}
329*0Sstevel@tonic-gate
330*0Sstevel@tonic-gate#
331*0Sstevel@tonic-gate#
332*0Sstevel@tonic-gate# ->update_polar
333*0Sstevel@tonic-gate#
334*0Sstevel@tonic-gate# Recompute and return the polar form, given accurate cartesian form.
335*0Sstevel@tonic-gate#
336*0Sstevel@tonic-gatesub update_polar {
337*0Sstevel@tonic-gate	my $self = shift;
338*0Sstevel@tonic-gate	my ($x, $y) = @{$self->{'cartesian'}};
339*0Sstevel@tonic-gate	$self->{p_dirty} = 0;
340*0Sstevel@tonic-gate	return $self->{'polar'} = [0, 0] if $x == 0 && $y == 0;
341*0Sstevel@tonic-gate	return $self->{'polar'} = [CORE::sqrt($x*$x + $y*$y),
342*0Sstevel@tonic-gate				   CORE::atan2($y, $x)];
343*0Sstevel@tonic-gate}
344*0Sstevel@tonic-gate
345*0Sstevel@tonic-gate#
346*0Sstevel@tonic-gate# (plus)
347*0Sstevel@tonic-gate#
348*0Sstevel@tonic-gate# Computes z1+z2.
349*0Sstevel@tonic-gate#
350*0Sstevel@tonic-gatesub plus {
351*0Sstevel@tonic-gate	my ($z1, $z2, $regular) = @_;
352*0Sstevel@tonic-gate	my ($re1, $im1) = @{$z1->cartesian};
353*0Sstevel@tonic-gate	$z2 = cplx($z2) unless ref $z2;
354*0Sstevel@tonic-gate	my ($re2, $im2) = ref $z2 ? @{$z2->cartesian} : ($z2, 0);
355*0Sstevel@tonic-gate	unless (defined $regular) {
356*0Sstevel@tonic-gate		$z1->set_cartesian([$re1 + $re2, $im1 + $im2]);
357*0Sstevel@tonic-gate		return $z1;
358*0Sstevel@tonic-gate	}
359*0Sstevel@tonic-gate	return (ref $z1)->make($re1 + $re2, $im1 + $im2);
360*0Sstevel@tonic-gate}
361*0Sstevel@tonic-gate
362*0Sstevel@tonic-gate#
363*0Sstevel@tonic-gate# (minus)
364*0Sstevel@tonic-gate#
365*0Sstevel@tonic-gate# Computes z1-z2.
366*0Sstevel@tonic-gate#
367*0Sstevel@tonic-gatesub minus {
368*0Sstevel@tonic-gate	my ($z1, $z2, $inverted) = @_;
369*0Sstevel@tonic-gate	my ($re1, $im1) = @{$z1->cartesian};
370*0Sstevel@tonic-gate	$z2 = cplx($z2) unless ref $z2;
371*0Sstevel@tonic-gate	my ($re2, $im2) = @{$z2->cartesian};
372*0Sstevel@tonic-gate	unless (defined $inverted) {
373*0Sstevel@tonic-gate		$z1->set_cartesian([$re1 - $re2, $im1 - $im2]);
374*0Sstevel@tonic-gate		return $z1;
375*0Sstevel@tonic-gate	}
376*0Sstevel@tonic-gate	return $inverted ?
377*0Sstevel@tonic-gate		(ref $z1)->make($re2 - $re1, $im2 - $im1) :
378*0Sstevel@tonic-gate		(ref $z1)->make($re1 - $re2, $im1 - $im2);
379*0Sstevel@tonic-gate
380*0Sstevel@tonic-gate}
381*0Sstevel@tonic-gate
382*0Sstevel@tonic-gate#
383*0Sstevel@tonic-gate# (multiply)
384*0Sstevel@tonic-gate#
385*0Sstevel@tonic-gate# Computes z1*z2.
386*0Sstevel@tonic-gate#
387*0Sstevel@tonic-gatesub multiply {
388*0Sstevel@tonic-gate        my ($z1, $z2, $regular) = @_;
389*0Sstevel@tonic-gate	if ($z1->{p_dirty} == 0 and ref $z2 and $z2->{p_dirty} == 0) {
390*0Sstevel@tonic-gate	    # if both polar better use polar to avoid rounding errors
391*0Sstevel@tonic-gate	    my ($r1, $t1) = @{$z1->polar};
392*0Sstevel@tonic-gate	    my ($r2, $t2) = @{$z2->polar};
393*0Sstevel@tonic-gate	    my $t = $t1 + $t2;
394*0Sstevel@tonic-gate	    if    ($t >   pi()) { $t -= pit2 }
395*0Sstevel@tonic-gate	    elsif ($t <= -pi()) { $t += pit2 }
396*0Sstevel@tonic-gate	    unless (defined $regular) {
397*0Sstevel@tonic-gate		$z1->set_polar([$r1 * $r2, $t]);
398*0Sstevel@tonic-gate		return $z1;
399*0Sstevel@tonic-gate	    }
400*0Sstevel@tonic-gate	    return (ref $z1)->emake($r1 * $r2, $t);
401*0Sstevel@tonic-gate	} else {
402*0Sstevel@tonic-gate	    my ($x1, $y1) = @{$z1->cartesian};
403*0Sstevel@tonic-gate	    if (ref $z2) {
404*0Sstevel@tonic-gate		my ($x2, $y2) = @{$z2->cartesian};
405*0Sstevel@tonic-gate		return (ref $z1)->make($x1*$x2-$y1*$y2, $x1*$y2+$y1*$x2);
406*0Sstevel@tonic-gate	    } else {
407*0Sstevel@tonic-gate		return (ref $z1)->make($x1*$z2, $y1*$z2);
408*0Sstevel@tonic-gate	    }
409*0Sstevel@tonic-gate	}
410*0Sstevel@tonic-gate}
411*0Sstevel@tonic-gate
412*0Sstevel@tonic-gate#
413*0Sstevel@tonic-gate# _divbyzero
414*0Sstevel@tonic-gate#
415*0Sstevel@tonic-gate# Die on division by zero.
416*0Sstevel@tonic-gate#
417*0Sstevel@tonic-gatesub _divbyzero {
418*0Sstevel@tonic-gate    my $mess = "$_[0]: Division by zero.\n";
419*0Sstevel@tonic-gate
420*0Sstevel@tonic-gate    if (defined $_[1]) {
421*0Sstevel@tonic-gate	$mess .= "(Because in the definition of $_[0], the divisor ";
422*0Sstevel@tonic-gate	$mess .= "$_[1] " unless ("$_[1]" eq '0');
423*0Sstevel@tonic-gate	$mess .= "is 0)\n";
424*0Sstevel@tonic-gate    }
425*0Sstevel@tonic-gate
426*0Sstevel@tonic-gate    my @up = caller(1);
427*0Sstevel@tonic-gate
428*0Sstevel@tonic-gate    $mess .= "Died at $up[1] line $up[2].\n";
429*0Sstevel@tonic-gate
430*0Sstevel@tonic-gate    die $mess;
431*0Sstevel@tonic-gate}
432*0Sstevel@tonic-gate
433*0Sstevel@tonic-gate#
434*0Sstevel@tonic-gate# (divide)
435*0Sstevel@tonic-gate#
436*0Sstevel@tonic-gate# Computes z1/z2.
437*0Sstevel@tonic-gate#
438*0Sstevel@tonic-gatesub divide {
439*0Sstevel@tonic-gate	my ($z1, $z2, $inverted) = @_;
440*0Sstevel@tonic-gate	if ($z1->{p_dirty} == 0 and ref $z2 and $z2->{p_dirty} == 0) {
441*0Sstevel@tonic-gate	    # if both polar better use polar to avoid rounding errors
442*0Sstevel@tonic-gate	    my ($r1, $t1) = @{$z1->polar};
443*0Sstevel@tonic-gate	    my ($r2, $t2) = @{$z2->polar};
444*0Sstevel@tonic-gate	    my $t;
445*0Sstevel@tonic-gate	    if ($inverted) {
446*0Sstevel@tonic-gate		_divbyzero "$z2/0" if ($r1 == 0);
447*0Sstevel@tonic-gate		$t = $t2 - $t1;
448*0Sstevel@tonic-gate		if    ($t >   pi()) { $t -= pit2 }
449*0Sstevel@tonic-gate		elsif ($t <= -pi()) { $t += pit2 }
450*0Sstevel@tonic-gate		return (ref $z1)->emake($r2 / $r1, $t);
451*0Sstevel@tonic-gate	    } else {
452*0Sstevel@tonic-gate		_divbyzero "$z1/0" if ($r2 == 0);
453*0Sstevel@tonic-gate		$t = $t1 - $t2;
454*0Sstevel@tonic-gate		if    ($t >   pi()) { $t -= pit2 }
455*0Sstevel@tonic-gate		elsif ($t <= -pi()) { $t += pit2 }
456*0Sstevel@tonic-gate		return (ref $z1)->emake($r1 / $r2, $t);
457*0Sstevel@tonic-gate	    }
458*0Sstevel@tonic-gate	} else {
459*0Sstevel@tonic-gate	    my ($d, $x2, $y2);
460*0Sstevel@tonic-gate	    if ($inverted) {
461*0Sstevel@tonic-gate		($x2, $y2) = @{$z1->cartesian};
462*0Sstevel@tonic-gate		$d = $x2*$x2 + $y2*$y2;
463*0Sstevel@tonic-gate		_divbyzero "$z2/0" if $d == 0;
464*0Sstevel@tonic-gate		return (ref $z1)->make(($x2*$z2)/$d, -($y2*$z2)/$d);
465*0Sstevel@tonic-gate	    } else {
466*0Sstevel@tonic-gate		my ($x1, $y1) = @{$z1->cartesian};
467*0Sstevel@tonic-gate		if (ref $z2) {
468*0Sstevel@tonic-gate		    ($x2, $y2) = @{$z2->cartesian};
469*0Sstevel@tonic-gate		    $d = $x2*$x2 + $y2*$y2;
470*0Sstevel@tonic-gate		    _divbyzero "$z1/0" if $d == 0;
471*0Sstevel@tonic-gate		    my $u = ($x1*$x2 + $y1*$y2)/$d;
472*0Sstevel@tonic-gate		    my $v = ($y1*$x2 - $x1*$y2)/$d;
473*0Sstevel@tonic-gate		    return (ref $z1)->make($u, $v);
474*0Sstevel@tonic-gate		} else {
475*0Sstevel@tonic-gate		    _divbyzero "$z1/0" if $z2 == 0;
476*0Sstevel@tonic-gate		    return (ref $z1)->make($x1/$z2, $y1/$z2);
477*0Sstevel@tonic-gate		}
478*0Sstevel@tonic-gate	    }
479*0Sstevel@tonic-gate	}
480*0Sstevel@tonic-gate}
481*0Sstevel@tonic-gate
482*0Sstevel@tonic-gate#
483*0Sstevel@tonic-gate# (power)
484*0Sstevel@tonic-gate#
485*0Sstevel@tonic-gate# Computes z1**z2 = exp(z2 * log z1)).
486*0Sstevel@tonic-gate#
487*0Sstevel@tonic-gatesub power {
488*0Sstevel@tonic-gate	my ($z1, $z2, $inverted) = @_;
489*0Sstevel@tonic-gate	if ($inverted) {
490*0Sstevel@tonic-gate	    return 1 if $z1 == 0 || $z2 == 1;
491*0Sstevel@tonic-gate	    return 0 if $z2 == 0 && Re($z1) > 0;
492*0Sstevel@tonic-gate	} else {
493*0Sstevel@tonic-gate	    return 1 if $z2 == 0 || $z1 == 1;
494*0Sstevel@tonic-gate	    return 0 if $z1 == 0 && Re($z2) > 0;
495*0Sstevel@tonic-gate	}
496*0Sstevel@tonic-gate	my $w = $inverted ? &exp($z1 * &log($z2))
497*0Sstevel@tonic-gate	                  : &exp($z2 * &log($z1));
498*0Sstevel@tonic-gate	# If both arguments cartesian, return cartesian, else polar.
499*0Sstevel@tonic-gate	return $z1->{c_dirty} == 0 &&
500*0Sstevel@tonic-gate	       (not ref $z2 or $z2->{c_dirty} == 0) ?
501*0Sstevel@tonic-gate	       cplx(@{$w->cartesian}) : $w;
502*0Sstevel@tonic-gate}
503*0Sstevel@tonic-gate
504*0Sstevel@tonic-gate#
505*0Sstevel@tonic-gate# (spaceship)
506*0Sstevel@tonic-gate#
507*0Sstevel@tonic-gate# Computes z1 <=> z2.
508*0Sstevel@tonic-gate# Sorts on the real part first, then on the imaginary part. Thus 2-4i < 3+8i.
509*0Sstevel@tonic-gate#
510*0Sstevel@tonic-gatesub spaceship {
511*0Sstevel@tonic-gate	my ($z1, $z2, $inverted) = @_;
512*0Sstevel@tonic-gate	my ($re1, $im1) = ref $z1 ? @{$z1->cartesian} : ($z1, 0);
513*0Sstevel@tonic-gate	my ($re2, $im2) = ref $z2 ? @{$z2->cartesian} : ($z2, 0);
514*0Sstevel@tonic-gate	my $sgn = $inverted ? -1 : 1;
515*0Sstevel@tonic-gate	return $sgn * ($re1 <=> $re2) if $re1 != $re2;
516*0Sstevel@tonic-gate	return $sgn * ($im1 <=> $im2);
517*0Sstevel@tonic-gate}
518*0Sstevel@tonic-gate
519*0Sstevel@tonic-gate#
520*0Sstevel@tonic-gate# (numeq)
521*0Sstevel@tonic-gate#
522*0Sstevel@tonic-gate# Computes z1 == z2.
523*0Sstevel@tonic-gate#
524*0Sstevel@tonic-gate# (Required in addition to spaceship() because of NaNs.)
525*0Sstevel@tonic-gatesub numeq {
526*0Sstevel@tonic-gate	my ($z1, $z2, $inverted) = @_;
527*0Sstevel@tonic-gate	my ($re1, $im1) = ref $z1 ? @{$z1->cartesian} : ($z1, 0);
528*0Sstevel@tonic-gate	my ($re2, $im2) = ref $z2 ? @{$z2->cartesian} : ($z2, 0);
529*0Sstevel@tonic-gate	return $re1 == $re2 && $im1 == $im2 ? 1 : 0;
530*0Sstevel@tonic-gate}
531*0Sstevel@tonic-gate
532*0Sstevel@tonic-gate#
533*0Sstevel@tonic-gate# (negate)
534*0Sstevel@tonic-gate#
535*0Sstevel@tonic-gate# Computes -z.
536*0Sstevel@tonic-gate#
537*0Sstevel@tonic-gatesub negate {
538*0Sstevel@tonic-gate	my ($z) = @_;
539*0Sstevel@tonic-gate	if ($z->{c_dirty}) {
540*0Sstevel@tonic-gate		my ($r, $t) = @{$z->polar};
541*0Sstevel@tonic-gate		$t = ($t <= 0) ? $t + pi : $t - pi;
542*0Sstevel@tonic-gate		return (ref $z)->emake($r, $t);
543*0Sstevel@tonic-gate	}
544*0Sstevel@tonic-gate	my ($re, $im) = @{$z->cartesian};
545*0Sstevel@tonic-gate	return (ref $z)->make(-$re, -$im);
546*0Sstevel@tonic-gate}
547*0Sstevel@tonic-gate
548*0Sstevel@tonic-gate#
549*0Sstevel@tonic-gate# (conjugate)
550*0Sstevel@tonic-gate#
551*0Sstevel@tonic-gate# Compute complex's conjugate.
552*0Sstevel@tonic-gate#
553*0Sstevel@tonic-gatesub conjugate {
554*0Sstevel@tonic-gate	my ($z) = @_;
555*0Sstevel@tonic-gate	if ($z->{c_dirty}) {
556*0Sstevel@tonic-gate		my ($r, $t) = @{$z->polar};
557*0Sstevel@tonic-gate		return (ref $z)->emake($r, -$t);
558*0Sstevel@tonic-gate	}
559*0Sstevel@tonic-gate	my ($re, $im) = @{$z->cartesian};
560*0Sstevel@tonic-gate	return (ref $z)->make($re, -$im);
561*0Sstevel@tonic-gate}
562*0Sstevel@tonic-gate
563*0Sstevel@tonic-gate#
564*0Sstevel@tonic-gate# (abs)
565*0Sstevel@tonic-gate#
566*0Sstevel@tonic-gate# Compute or set complex's norm (rho).
567*0Sstevel@tonic-gate#
568*0Sstevel@tonic-gatesub abs {
569*0Sstevel@tonic-gate	my ($z, $rho) = @_;
570*0Sstevel@tonic-gate	unless (ref $z) {
571*0Sstevel@tonic-gate	    if (@_ == 2) {
572*0Sstevel@tonic-gate		$_[0] = $_[1];
573*0Sstevel@tonic-gate	    } else {
574*0Sstevel@tonic-gate		return CORE::abs($z);
575*0Sstevel@tonic-gate	    }
576*0Sstevel@tonic-gate	}
577*0Sstevel@tonic-gate	if (defined $rho) {
578*0Sstevel@tonic-gate	    $z->{'polar'} = [ $rho, ${$z->polar}[1] ];
579*0Sstevel@tonic-gate	    $z->{p_dirty} = 0;
580*0Sstevel@tonic-gate	    $z->{c_dirty} = 1;
581*0Sstevel@tonic-gate	    return $rho;
582*0Sstevel@tonic-gate	} else {
583*0Sstevel@tonic-gate	    return ${$z->polar}[0];
584*0Sstevel@tonic-gate	}
585*0Sstevel@tonic-gate}
586*0Sstevel@tonic-gate
587*0Sstevel@tonic-gatesub _theta {
588*0Sstevel@tonic-gate    my $theta = $_[0];
589*0Sstevel@tonic-gate
590*0Sstevel@tonic-gate    if    ($$theta >   pi()) { $$theta -= pit2 }
591*0Sstevel@tonic-gate    elsif ($$theta <= -pi()) { $$theta += pit2 }
592*0Sstevel@tonic-gate}
593*0Sstevel@tonic-gate
594*0Sstevel@tonic-gate#
595*0Sstevel@tonic-gate# arg
596*0Sstevel@tonic-gate#
597*0Sstevel@tonic-gate# Compute or set complex's argument (theta).
598*0Sstevel@tonic-gate#
599*0Sstevel@tonic-gatesub arg {
600*0Sstevel@tonic-gate	my ($z, $theta) = @_;
601*0Sstevel@tonic-gate	return $z unless ref $z;
602*0Sstevel@tonic-gate	if (defined $theta) {
603*0Sstevel@tonic-gate	    _theta(\$theta);
604*0Sstevel@tonic-gate	    $z->{'polar'} = [ ${$z->polar}[0], $theta ];
605*0Sstevel@tonic-gate	    $z->{p_dirty} = 0;
606*0Sstevel@tonic-gate	    $z->{c_dirty} = 1;
607*0Sstevel@tonic-gate	} else {
608*0Sstevel@tonic-gate	    $theta = ${$z->polar}[1];
609*0Sstevel@tonic-gate	    _theta(\$theta);
610*0Sstevel@tonic-gate	}
611*0Sstevel@tonic-gate	return $theta;
612*0Sstevel@tonic-gate}
613*0Sstevel@tonic-gate
614*0Sstevel@tonic-gate#
615*0Sstevel@tonic-gate# (sqrt)
616*0Sstevel@tonic-gate#
617*0Sstevel@tonic-gate# Compute sqrt(z).
618*0Sstevel@tonic-gate#
619*0Sstevel@tonic-gate# It is quite tempting to use wantarray here so that in list context
620*0Sstevel@tonic-gate# sqrt() would return the two solutions.  This, however, would
621*0Sstevel@tonic-gate# break things like
622*0Sstevel@tonic-gate#
623*0Sstevel@tonic-gate#	print "sqrt(z) = ", sqrt($z), "\n";
624*0Sstevel@tonic-gate#
625*0Sstevel@tonic-gate# The two values would be printed side by side without no intervening
626*0Sstevel@tonic-gate# whitespace, quite confusing.
627*0Sstevel@tonic-gate# Therefore if you want the two solutions use the root().
628*0Sstevel@tonic-gate#
629*0Sstevel@tonic-gatesub sqrt {
630*0Sstevel@tonic-gate	my ($z) = @_;
631*0Sstevel@tonic-gate	my ($re, $im) = ref $z ? @{$z->cartesian} : ($z, 0);
632*0Sstevel@tonic-gate	return $re < 0 ? cplx(0, CORE::sqrt(-$re)) : CORE::sqrt($re)
633*0Sstevel@tonic-gate	    if $im == 0;
634*0Sstevel@tonic-gate	my ($r, $t) = @{$z->polar};
635*0Sstevel@tonic-gate	return (ref $z)->emake(CORE::sqrt($r), $t/2);
636*0Sstevel@tonic-gate}
637*0Sstevel@tonic-gate
638*0Sstevel@tonic-gate#
639*0Sstevel@tonic-gate# cbrt
640*0Sstevel@tonic-gate#
641*0Sstevel@tonic-gate# Compute cbrt(z) (cubic root).
642*0Sstevel@tonic-gate#
643*0Sstevel@tonic-gate# Why are we not returning three values?  The same answer as for sqrt().
644*0Sstevel@tonic-gate#
645*0Sstevel@tonic-gatesub cbrt {
646*0Sstevel@tonic-gate	my ($z) = @_;
647*0Sstevel@tonic-gate	return $z < 0 ?
648*0Sstevel@tonic-gate	    -CORE::exp(CORE::log(-$z)/3) :
649*0Sstevel@tonic-gate		($z > 0 ? CORE::exp(CORE::log($z)/3): 0)
650*0Sstevel@tonic-gate	    unless ref $z;
651*0Sstevel@tonic-gate	my ($r, $t) = @{$z->polar};
652*0Sstevel@tonic-gate	return 0 if $r == 0;
653*0Sstevel@tonic-gate	return (ref $z)->emake(CORE::exp(CORE::log($r)/3), $t/3);
654*0Sstevel@tonic-gate}
655*0Sstevel@tonic-gate
656*0Sstevel@tonic-gate#
657*0Sstevel@tonic-gate# _rootbad
658*0Sstevel@tonic-gate#
659*0Sstevel@tonic-gate# Die on bad root.
660*0Sstevel@tonic-gate#
661*0Sstevel@tonic-gatesub _rootbad {
662*0Sstevel@tonic-gate    my $mess = "Root $_[0] illegal, root rank must be positive integer.\n";
663*0Sstevel@tonic-gate
664*0Sstevel@tonic-gate    my @up = caller(1);
665*0Sstevel@tonic-gate
666*0Sstevel@tonic-gate    $mess .= "Died at $up[1] line $up[2].\n";
667*0Sstevel@tonic-gate
668*0Sstevel@tonic-gate    die $mess;
669*0Sstevel@tonic-gate}
670*0Sstevel@tonic-gate
671*0Sstevel@tonic-gate#
672*0Sstevel@tonic-gate# root
673*0Sstevel@tonic-gate#
674*0Sstevel@tonic-gate# Computes all nth root for z, returning an array whose size is n.
675*0Sstevel@tonic-gate# `n' must be a positive integer.
676*0Sstevel@tonic-gate#
677*0Sstevel@tonic-gate# The roots are given by (for k = 0..n-1):
678*0Sstevel@tonic-gate#
679*0Sstevel@tonic-gate# z^(1/n) = r^(1/n) (cos ((t+2 k pi)/n) + i sin ((t+2 k pi)/n))
680*0Sstevel@tonic-gate#
681*0Sstevel@tonic-gatesub root {
682*0Sstevel@tonic-gate	my ($z, $n) = @_;
683*0Sstevel@tonic-gate	_rootbad($n) if ($n < 1 or int($n) != $n);
684*0Sstevel@tonic-gate	my ($r, $t) = ref $z ?
685*0Sstevel@tonic-gate	    @{$z->polar} : (CORE::abs($z), $z >= 0 ? 0 : pi);
686*0Sstevel@tonic-gate	my @root;
687*0Sstevel@tonic-gate	my $k;
688*0Sstevel@tonic-gate	my $theta_inc = pit2 / $n;
689*0Sstevel@tonic-gate	my $rho = $r ** (1/$n);
690*0Sstevel@tonic-gate	my $theta;
691*0Sstevel@tonic-gate	my $cartesian = ref $z && $z->{c_dirty} == 0;
692*0Sstevel@tonic-gate	for ($k = 0, $theta = $t / $n; $k < $n; $k++, $theta += $theta_inc) {
693*0Sstevel@tonic-gate	    my $w = cplxe($rho, $theta);
694*0Sstevel@tonic-gate	    # Yes, $cartesian is loop invariant.
695*0Sstevel@tonic-gate	    push @root, $cartesian ? cplx(@{$w->cartesian}) : $w;
696*0Sstevel@tonic-gate	}
697*0Sstevel@tonic-gate	return @root;
698*0Sstevel@tonic-gate}
699*0Sstevel@tonic-gate
700*0Sstevel@tonic-gate#
701*0Sstevel@tonic-gate# Re
702*0Sstevel@tonic-gate#
703*0Sstevel@tonic-gate# Return or set Re(z).
704*0Sstevel@tonic-gate#
705*0Sstevel@tonic-gatesub Re {
706*0Sstevel@tonic-gate	my ($z, $Re) = @_;
707*0Sstevel@tonic-gate	return $z unless ref $z;
708*0Sstevel@tonic-gate	if (defined $Re) {
709*0Sstevel@tonic-gate	    $z->{'cartesian'} = [ $Re, ${$z->cartesian}[1] ];
710*0Sstevel@tonic-gate	    $z->{c_dirty} = 0;
711*0Sstevel@tonic-gate	    $z->{p_dirty} = 1;
712*0Sstevel@tonic-gate	} else {
713*0Sstevel@tonic-gate	    return ${$z->cartesian}[0];
714*0Sstevel@tonic-gate	}
715*0Sstevel@tonic-gate}
716*0Sstevel@tonic-gate
717*0Sstevel@tonic-gate#
718*0Sstevel@tonic-gate# Im
719*0Sstevel@tonic-gate#
720*0Sstevel@tonic-gate# Return or set Im(z).
721*0Sstevel@tonic-gate#
722*0Sstevel@tonic-gatesub Im {
723*0Sstevel@tonic-gate	my ($z, $Im) = @_;
724*0Sstevel@tonic-gate	return 0 unless ref $z;
725*0Sstevel@tonic-gate	if (defined $Im) {
726*0Sstevel@tonic-gate	    $z->{'cartesian'} = [ ${$z->cartesian}[0], $Im ];
727*0Sstevel@tonic-gate	    $z->{c_dirty} = 0;
728*0Sstevel@tonic-gate	    $z->{p_dirty} = 1;
729*0Sstevel@tonic-gate	} else {
730*0Sstevel@tonic-gate	    return ${$z->cartesian}[1];
731*0Sstevel@tonic-gate	}
732*0Sstevel@tonic-gate}
733*0Sstevel@tonic-gate
734*0Sstevel@tonic-gate#
735*0Sstevel@tonic-gate# rho
736*0Sstevel@tonic-gate#
737*0Sstevel@tonic-gate# Return or set rho(w).
738*0Sstevel@tonic-gate#
739*0Sstevel@tonic-gatesub rho {
740*0Sstevel@tonic-gate    Math::Complex::abs(@_);
741*0Sstevel@tonic-gate}
742*0Sstevel@tonic-gate
743*0Sstevel@tonic-gate#
744*0Sstevel@tonic-gate# theta
745*0Sstevel@tonic-gate#
746*0Sstevel@tonic-gate# Return or set theta(w).
747*0Sstevel@tonic-gate#
748*0Sstevel@tonic-gatesub theta {
749*0Sstevel@tonic-gate    Math::Complex::arg(@_);
750*0Sstevel@tonic-gate}
751*0Sstevel@tonic-gate
752*0Sstevel@tonic-gate#
753*0Sstevel@tonic-gate# (exp)
754*0Sstevel@tonic-gate#
755*0Sstevel@tonic-gate# Computes exp(z).
756*0Sstevel@tonic-gate#
757*0Sstevel@tonic-gatesub exp {
758*0Sstevel@tonic-gate	my ($z) = @_;
759*0Sstevel@tonic-gate	my ($x, $y) = @{$z->cartesian};
760*0Sstevel@tonic-gate	return (ref $z)->emake(CORE::exp($x), $y);
761*0Sstevel@tonic-gate}
762*0Sstevel@tonic-gate
763*0Sstevel@tonic-gate#
764*0Sstevel@tonic-gate# _logofzero
765*0Sstevel@tonic-gate#
766*0Sstevel@tonic-gate# Die on logarithm of zero.
767*0Sstevel@tonic-gate#
768*0Sstevel@tonic-gatesub _logofzero {
769*0Sstevel@tonic-gate    my $mess = "$_[0]: Logarithm of zero.\n";
770*0Sstevel@tonic-gate
771*0Sstevel@tonic-gate    if (defined $_[1]) {
772*0Sstevel@tonic-gate	$mess .= "(Because in the definition of $_[0], the argument ";
773*0Sstevel@tonic-gate	$mess .= "$_[1] " unless ($_[1] eq '0');
774*0Sstevel@tonic-gate	$mess .= "is 0)\n";
775*0Sstevel@tonic-gate    }
776*0Sstevel@tonic-gate
777*0Sstevel@tonic-gate    my @up = caller(1);
778*0Sstevel@tonic-gate
779*0Sstevel@tonic-gate    $mess .= "Died at $up[1] line $up[2].\n";
780*0Sstevel@tonic-gate
781*0Sstevel@tonic-gate    die $mess;
782*0Sstevel@tonic-gate}
783*0Sstevel@tonic-gate
784*0Sstevel@tonic-gate#
785*0Sstevel@tonic-gate# (log)
786*0Sstevel@tonic-gate#
787*0Sstevel@tonic-gate# Compute log(z).
788*0Sstevel@tonic-gate#
789*0Sstevel@tonic-gatesub log {
790*0Sstevel@tonic-gate	my ($z) = @_;
791*0Sstevel@tonic-gate	unless (ref $z) {
792*0Sstevel@tonic-gate	    _logofzero("log") if $z == 0;
793*0Sstevel@tonic-gate	    return $z > 0 ? CORE::log($z) : cplx(CORE::log(-$z), pi);
794*0Sstevel@tonic-gate	}
795*0Sstevel@tonic-gate	my ($r, $t) = @{$z->polar};
796*0Sstevel@tonic-gate	_logofzero("log") if $r == 0;
797*0Sstevel@tonic-gate	if    ($t >   pi()) { $t -= pit2 }
798*0Sstevel@tonic-gate	elsif ($t <= -pi()) { $t += pit2 }
799*0Sstevel@tonic-gate	return (ref $z)->make(CORE::log($r), $t);
800*0Sstevel@tonic-gate}
801*0Sstevel@tonic-gate
802*0Sstevel@tonic-gate#
803*0Sstevel@tonic-gate# ln
804*0Sstevel@tonic-gate#
805*0Sstevel@tonic-gate# Alias for log().
806*0Sstevel@tonic-gate#
807*0Sstevel@tonic-gatesub ln { Math::Complex::log(@_) }
808*0Sstevel@tonic-gate
809*0Sstevel@tonic-gate#
810*0Sstevel@tonic-gate# log10
811*0Sstevel@tonic-gate#
812*0Sstevel@tonic-gate# Compute log10(z).
813*0Sstevel@tonic-gate#
814*0Sstevel@tonic-gate
815*0Sstevel@tonic-gatesub log10 {
816*0Sstevel@tonic-gate	return Math::Complex::log($_[0]) * uplog10;
817*0Sstevel@tonic-gate}
818*0Sstevel@tonic-gate
819*0Sstevel@tonic-gate#
820*0Sstevel@tonic-gate# logn
821*0Sstevel@tonic-gate#
822*0Sstevel@tonic-gate# Compute logn(z,n) = log(z) / log(n)
823*0Sstevel@tonic-gate#
824*0Sstevel@tonic-gatesub logn {
825*0Sstevel@tonic-gate	my ($z, $n) = @_;
826*0Sstevel@tonic-gate	$z = cplx($z, 0) unless ref $z;
827*0Sstevel@tonic-gate	my $logn = $LOGN{$n};
828*0Sstevel@tonic-gate	$logn = $LOGN{$n} = CORE::log($n) unless defined $logn;	# Cache log(n)
829*0Sstevel@tonic-gate	return &log($z) / $logn;
830*0Sstevel@tonic-gate}
831*0Sstevel@tonic-gate
832*0Sstevel@tonic-gate#
833*0Sstevel@tonic-gate# (cos)
834*0Sstevel@tonic-gate#
835*0Sstevel@tonic-gate# Compute cos(z) = (exp(iz) + exp(-iz))/2.
836*0Sstevel@tonic-gate#
837*0Sstevel@tonic-gatesub cos {
838*0Sstevel@tonic-gate	my ($z) = @_;
839*0Sstevel@tonic-gate	return CORE::cos($z) unless ref $z;
840*0Sstevel@tonic-gate	my ($x, $y) = @{$z->cartesian};
841*0Sstevel@tonic-gate	my $ey = CORE::exp($y);
842*0Sstevel@tonic-gate	my $sx = CORE::sin($x);
843*0Sstevel@tonic-gate	my $cx = CORE::cos($x);
844*0Sstevel@tonic-gate	my $ey_1 = $ey ? 1 / $ey : $Inf;
845*0Sstevel@tonic-gate	return (ref $z)->make($cx * ($ey + $ey_1)/2,
846*0Sstevel@tonic-gate			      $sx * ($ey_1 - $ey)/2);
847*0Sstevel@tonic-gate}
848*0Sstevel@tonic-gate
849*0Sstevel@tonic-gate#
850*0Sstevel@tonic-gate# (sin)
851*0Sstevel@tonic-gate#
852*0Sstevel@tonic-gate# Compute sin(z) = (exp(iz) - exp(-iz))/2.
853*0Sstevel@tonic-gate#
854*0Sstevel@tonic-gatesub sin {
855*0Sstevel@tonic-gate	my ($z) = @_;
856*0Sstevel@tonic-gate	return CORE::sin($z) unless ref $z;
857*0Sstevel@tonic-gate	my ($x, $y) = @{$z->cartesian};
858*0Sstevel@tonic-gate	my $ey = CORE::exp($y);
859*0Sstevel@tonic-gate	my $sx = CORE::sin($x);
860*0Sstevel@tonic-gate	my $cx = CORE::cos($x);
861*0Sstevel@tonic-gate	my $ey_1 = $ey ? 1 / $ey : $Inf;
862*0Sstevel@tonic-gate	return (ref $z)->make($sx * ($ey + $ey_1)/2,
863*0Sstevel@tonic-gate			      $cx * ($ey - $ey_1)/2);
864*0Sstevel@tonic-gate}
865*0Sstevel@tonic-gate
866*0Sstevel@tonic-gate#
867*0Sstevel@tonic-gate# tan
868*0Sstevel@tonic-gate#
869*0Sstevel@tonic-gate# Compute tan(z) = sin(z) / cos(z).
870*0Sstevel@tonic-gate#
871*0Sstevel@tonic-gatesub tan {
872*0Sstevel@tonic-gate	my ($z) = @_;
873*0Sstevel@tonic-gate	my $cz = &cos($z);
874*0Sstevel@tonic-gate	_divbyzero "tan($z)", "cos($z)" if $cz == 0;
875*0Sstevel@tonic-gate	return &sin($z) / $cz;
876*0Sstevel@tonic-gate}
877*0Sstevel@tonic-gate
878*0Sstevel@tonic-gate#
879*0Sstevel@tonic-gate# sec
880*0Sstevel@tonic-gate#
881*0Sstevel@tonic-gate# Computes the secant sec(z) = 1 / cos(z).
882*0Sstevel@tonic-gate#
883*0Sstevel@tonic-gatesub sec {
884*0Sstevel@tonic-gate	my ($z) = @_;
885*0Sstevel@tonic-gate	my $cz = &cos($z);
886*0Sstevel@tonic-gate	_divbyzero "sec($z)", "cos($z)" if ($cz == 0);
887*0Sstevel@tonic-gate	return 1 / $cz;
888*0Sstevel@tonic-gate}
889*0Sstevel@tonic-gate
890*0Sstevel@tonic-gate#
891*0Sstevel@tonic-gate# csc
892*0Sstevel@tonic-gate#
893*0Sstevel@tonic-gate# Computes the cosecant csc(z) = 1 / sin(z).
894*0Sstevel@tonic-gate#
895*0Sstevel@tonic-gatesub csc {
896*0Sstevel@tonic-gate	my ($z) = @_;
897*0Sstevel@tonic-gate	my $sz = &sin($z);
898*0Sstevel@tonic-gate	_divbyzero "csc($z)", "sin($z)" if ($sz == 0);
899*0Sstevel@tonic-gate	return 1 / $sz;
900*0Sstevel@tonic-gate}
901*0Sstevel@tonic-gate
902*0Sstevel@tonic-gate#
903*0Sstevel@tonic-gate# cosec
904*0Sstevel@tonic-gate#
905*0Sstevel@tonic-gate# Alias for csc().
906*0Sstevel@tonic-gate#
907*0Sstevel@tonic-gatesub cosec { Math::Complex::csc(@_) }
908*0Sstevel@tonic-gate
909*0Sstevel@tonic-gate#
910*0Sstevel@tonic-gate# cot
911*0Sstevel@tonic-gate#
912*0Sstevel@tonic-gate# Computes cot(z) = cos(z) / sin(z).
913*0Sstevel@tonic-gate#
914*0Sstevel@tonic-gatesub cot {
915*0Sstevel@tonic-gate	my ($z) = @_;
916*0Sstevel@tonic-gate	my $sz = &sin($z);
917*0Sstevel@tonic-gate	_divbyzero "cot($z)", "sin($z)" if ($sz == 0);
918*0Sstevel@tonic-gate	return &cos($z) / $sz;
919*0Sstevel@tonic-gate}
920*0Sstevel@tonic-gate
921*0Sstevel@tonic-gate#
922*0Sstevel@tonic-gate# cotan
923*0Sstevel@tonic-gate#
924*0Sstevel@tonic-gate# Alias for cot().
925*0Sstevel@tonic-gate#
926*0Sstevel@tonic-gatesub cotan { Math::Complex::cot(@_) }
927*0Sstevel@tonic-gate
928*0Sstevel@tonic-gate#
929*0Sstevel@tonic-gate# acos
930*0Sstevel@tonic-gate#
931*0Sstevel@tonic-gate# Computes the arc cosine acos(z) = -i log(z + sqrt(z*z-1)).
932*0Sstevel@tonic-gate#
933*0Sstevel@tonic-gatesub acos {
934*0Sstevel@tonic-gate	my $z = $_[0];
935*0Sstevel@tonic-gate	return CORE::atan2(CORE::sqrt(1-$z*$z), $z)
936*0Sstevel@tonic-gate	    if (! ref $z) && CORE::abs($z) <= 1;
937*0Sstevel@tonic-gate	$z = cplx($z, 0) unless ref $z;
938*0Sstevel@tonic-gate	my ($x, $y) = @{$z->cartesian};
939*0Sstevel@tonic-gate	return 0 if $x == 1 && $y == 0;
940*0Sstevel@tonic-gate	my $t1 = CORE::sqrt(($x+1)*($x+1) + $y*$y);
941*0Sstevel@tonic-gate	my $t2 = CORE::sqrt(($x-1)*($x-1) + $y*$y);
942*0Sstevel@tonic-gate	my $alpha = ($t1 + $t2)/2;
943*0Sstevel@tonic-gate	my $beta  = ($t1 - $t2)/2;
944*0Sstevel@tonic-gate	$alpha = 1 if $alpha < 1;
945*0Sstevel@tonic-gate	if    ($beta >  1) { $beta =  1 }
946*0Sstevel@tonic-gate	elsif ($beta < -1) { $beta = -1 }
947*0Sstevel@tonic-gate	my $u = CORE::atan2(CORE::sqrt(1-$beta*$beta), $beta);
948*0Sstevel@tonic-gate	my $v = CORE::log($alpha + CORE::sqrt($alpha*$alpha-1));
949*0Sstevel@tonic-gate	$v = -$v if $y > 0 || ($y == 0 && $x < -1);
950*0Sstevel@tonic-gate	return (ref $z)->make($u, $v);
951*0Sstevel@tonic-gate}
952*0Sstevel@tonic-gate
953*0Sstevel@tonic-gate#
954*0Sstevel@tonic-gate# asin
955*0Sstevel@tonic-gate#
956*0Sstevel@tonic-gate# Computes the arc sine asin(z) = -i log(iz + sqrt(1-z*z)).
957*0Sstevel@tonic-gate#
958*0Sstevel@tonic-gatesub asin {
959*0Sstevel@tonic-gate	my $z = $_[0];
960*0Sstevel@tonic-gate	return CORE::atan2($z, CORE::sqrt(1-$z*$z))
961*0Sstevel@tonic-gate	    if (! ref $z) && CORE::abs($z) <= 1;
962*0Sstevel@tonic-gate	$z = cplx($z, 0) unless ref $z;
963*0Sstevel@tonic-gate	my ($x, $y) = @{$z->cartesian};
964*0Sstevel@tonic-gate	return 0 if $x == 0 && $y == 0;
965*0Sstevel@tonic-gate	my $t1 = CORE::sqrt(($x+1)*($x+1) + $y*$y);
966*0Sstevel@tonic-gate	my $t2 = CORE::sqrt(($x-1)*($x-1) + $y*$y);
967*0Sstevel@tonic-gate	my $alpha = ($t1 + $t2)/2;
968*0Sstevel@tonic-gate	my $beta  = ($t1 - $t2)/2;
969*0Sstevel@tonic-gate	$alpha = 1 if $alpha < 1;
970*0Sstevel@tonic-gate	if    ($beta >  1) { $beta =  1 }
971*0Sstevel@tonic-gate	elsif ($beta < -1) { $beta = -1 }
972*0Sstevel@tonic-gate	my $u =  CORE::atan2($beta, CORE::sqrt(1-$beta*$beta));
973*0Sstevel@tonic-gate	my $v = -CORE::log($alpha + CORE::sqrt($alpha*$alpha-1));
974*0Sstevel@tonic-gate	$v = -$v if $y > 0 || ($y == 0 && $x < -1);
975*0Sstevel@tonic-gate	return (ref $z)->make($u, $v);
976*0Sstevel@tonic-gate}
977*0Sstevel@tonic-gate
978*0Sstevel@tonic-gate#
979*0Sstevel@tonic-gate# atan
980*0Sstevel@tonic-gate#
981*0Sstevel@tonic-gate# Computes the arc tangent atan(z) = i/2 log((i+z) / (i-z)).
982*0Sstevel@tonic-gate#
983*0Sstevel@tonic-gatesub atan {
984*0Sstevel@tonic-gate	my ($z) = @_;
985*0Sstevel@tonic-gate	return CORE::atan2($z, 1) unless ref $z;
986*0Sstevel@tonic-gate	my ($x, $y) = ref $z ? @{$z->cartesian} : ($z, 0);
987*0Sstevel@tonic-gate	return 0 if $x == 0 && $y == 0;
988*0Sstevel@tonic-gate	_divbyzero "atan(i)"  if ( $z == i);
989*0Sstevel@tonic-gate	_logofzero "atan(-i)" if (-$z == i); # -i is a bad file test...
990*0Sstevel@tonic-gate	my $log = &log((i + $z) / (i - $z));
991*0Sstevel@tonic-gate	return ip2 * $log;
992*0Sstevel@tonic-gate}
993*0Sstevel@tonic-gate
994*0Sstevel@tonic-gate#
995*0Sstevel@tonic-gate# asec
996*0Sstevel@tonic-gate#
997*0Sstevel@tonic-gate# Computes the arc secant asec(z) = acos(1 / z).
998*0Sstevel@tonic-gate#
999*0Sstevel@tonic-gatesub asec {
1000*0Sstevel@tonic-gate	my ($z) = @_;
1001*0Sstevel@tonic-gate	_divbyzero "asec($z)", $z if ($z == 0);
1002*0Sstevel@tonic-gate	return acos(1 / $z);
1003*0Sstevel@tonic-gate}
1004*0Sstevel@tonic-gate
1005*0Sstevel@tonic-gate#
1006*0Sstevel@tonic-gate# acsc
1007*0Sstevel@tonic-gate#
1008*0Sstevel@tonic-gate# Computes the arc cosecant acsc(z) = asin(1 / z).
1009*0Sstevel@tonic-gate#
1010*0Sstevel@tonic-gatesub acsc {
1011*0Sstevel@tonic-gate	my ($z) = @_;
1012*0Sstevel@tonic-gate	_divbyzero "acsc($z)", $z if ($z == 0);
1013*0Sstevel@tonic-gate	return asin(1 / $z);
1014*0Sstevel@tonic-gate}
1015*0Sstevel@tonic-gate
1016*0Sstevel@tonic-gate#
1017*0Sstevel@tonic-gate# acosec
1018*0Sstevel@tonic-gate#
1019*0Sstevel@tonic-gate# Alias for acsc().
1020*0Sstevel@tonic-gate#
1021*0Sstevel@tonic-gatesub acosec { Math::Complex::acsc(@_) }
1022*0Sstevel@tonic-gate
1023*0Sstevel@tonic-gate#
1024*0Sstevel@tonic-gate# acot
1025*0Sstevel@tonic-gate#
1026*0Sstevel@tonic-gate# Computes the arc cotangent acot(z) = atan(1 / z)
1027*0Sstevel@tonic-gate#
1028*0Sstevel@tonic-gatesub acot {
1029*0Sstevel@tonic-gate	my ($z) = @_;
1030*0Sstevel@tonic-gate	_divbyzero "acot(0)"  if $z == 0;
1031*0Sstevel@tonic-gate	return ($z >= 0) ? CORE::atan2(1, $z) : CORE::atan2(-1, -$z)
1032*0Sstevel@tonic-gate	    unless ref $z;
1033*0Sstevel@tonic-gate	_divbyzero "acot(i)"  if ($z - i == 0);
1034*0Sstevel@tonic-gate	_logofzero "acot(-i)" if ($z + i == 0);
1035*0Sstevel@tonic-gate	return atan(1 / $z);
1036*0Sstevel@tonic-gate}
1037*0Sstevel@tonic-gate
1038*0Sstevel@tonic-gate#
1039*0Sstevel@tonic-gate# acotan
1040*0Sstevel@tonic-gate#
1041*0Sstevel@tonic-gate# Alias for acot().
1042*0Sstevel@tonic-gate#
1043*0Sstevel@tonic-gatesub acotan { Math::Complex::acot(@_) }
1044*0Sstevel@tonic-gate
1045*0Sstevel@tonic-gate#
1046*0Sstevel@tonic-gate# cosh
1047*0Sstevel@tonic-gate#
1048*0Sstevel@tonic-gate# Computes the hyperbolic cosine cosh(z) = (exp(z) + exp(-z))/2.
1049*0Sstevel@tonic-gate#
1050*0Sstevel@tonic-gatesub cosh {
1051*0Sstevel@tonic-gate	my ($z) = @_;
1052*0Sstevel@tonic-gate	my $ex;
1053*0Sstevel@tonic-gate	unless (ref $z) {
1054*0Sstevel@tonic-gate	    $ex = CORE::exp($z);
1055*0Sstevel@tonic-gate	    return $ex ? ($ex + 1/$ex)/2 : $Inf;
1056*0Sstevel@tonic-gate	}
1057*0Sstevel@tonic-gate	my ($x, $y) = @{$z->cartesian};
1058*0Sstevel@tonic-gate	$ex = CORE::exp($x);
1059*0Sstevel@tonic-gate	my $ex_1 = $ex ? 1 / $ex : $Inf;
1060*0Sstevel@tonic-gate	return (ref $z)->make(CORE::cos($y) * ($ex + $ex_1)/2,
1061*0Sstevel@tonic-gate			      CORE::sin($y) * ($ex - $ex_1)/2);
1062*0Sstevel@tonic-gate}
1063*0Sstevel@tonic-gate
1064*0Sstevel@tonic-gate#
1065*0Sstevel@tonic-gate# sinh
1066*0Sstevel@tonic-gate#
1067*0Sstevel@tonic-gate# Computes the hyperbolic sine sinh(z) = (exp(z) - exp(-z))/2.
1068*0Sstevel@tonic-gate#
1069*0Sstevel@tonic-gatesub sinh {
1070*0Sstevel@tonic-gate	my ($z) = @_;
1071*0Sstevel@tonic-gate	my $ex;
1072*0Sstevel@tonic-gate	unless (ref $z) {
1073*0Sstevel@tonic-gate	    return 0 if $z == 0;
1074*0Sstevel@tonic-gate	    $ex = CORE::exp($z);
1075*0Sstevel@tonic-gate	    return $ex ? ($ex - 1/$ex)/2 : "-$Inf";
1076*0Sstevel@tonic-gate	}
1077*0Sstevel@tonic-gate	my ($x, $y) = @{$z->cartesian};
1078*0Sstevel@tonic-gate	my $cy = CORE::cos($y);
1079*0Sstevel@tonic-gate	my $sy = CORE::sin($y);
1080*0Sstevel@tonic-gate	$ex = CORE::exp($x);
1081*0Sstevel@tonic-gate	my $ex_1 = $ex ? 1 / $ex : $Inf;
1082*0Sstevel@tonic-gate	return (ref $z)->make(CORE::cos($y) * ($ex - $ex_1)/2,
1083*0Sstevel@tonic-gate			      CORE::sin($y) * ($ex + $ex_1)/2);
1084*0Sstevel@tonic-gate}
1085*0Sstevel@tonic-gate
1086*0Sstevel@tonic-gate#
1087*0Sstevel@tonic-gate# tanh
1088*0Sstevel@tonic-gate#
1089*0Sstevel@tonic-gate# Computes the hyperbolic tangent tanh(z) = sinh(z) / cosh(z).
1090*0Sstevel@tonic-gate#
1091*0Sstevel@tonic-gatesub tanh {
1092*0Sstevel@tonic-gate	my ($z) = @_;
1093*0Sstevel@tonic-gate	my $cz = cosh($z);
1094*0Sstevel@tonic-gate	_divbyzero "tanh($z)", "cosh($z)" if ($cz == 0);
1095*0Sstevel@tonic-gate	return sinh($z) / $cz;
1096*0Sstevel@tonic-gate}
1097*0Sstevel@tonic-gate
1098*0Sstevel@tonic-gate#
1099*0Sstevel@tonic-gate# sech
1100*0Sstevel@tonic-gate#
1101*0Sstevel@tonic-gate# Computes the hyperbolic secant sech(z) = 1 / cosh(z).
1102*0Sstevel@tonic-gate#
1103*0Sstevel@tonic-gatesub sech {
1104*0Sstevel@tonic-gate	my ($z) = @_;
1105*0Sstevel@tonic-gate	my $cz = cosh($z);
1106*0Sstevel@tonic-gate	_divbyzero "sech($z)", "cosh($z)" if ($cz == 0);
1107*0Sstevel@tonic-gate	return 1 / $cz;
1108*0Sstevel@tonic-gate}
1109*0Sstevel@tonic-gate
1110*0Sstevel@tonic-gate#
1111*0Sstevel@tonic-gate# csch
1112*0Sstevel@tonic-gate#
1113*0Sstevel@tonic-gate# Computes the hyperbolic cosecant csch(z) = 1 / sinh(z).
1114*0Sstevel@tonic-gate#
1115*0Sstevel@tonic-gatesub csch {
1116*0Sstevel@tonic-gate	my ($z) = @_;
1117*0Sstevel@tonic-gate	my $sz = sinh($z);
1118*0Sstevel@tonic-gate	_divbyzero "csch($z)", "sinh($z)" if ($sz == 0);
1119*0Sstevel@tonic-gate	return 1 / $sz;
1120*0Sstevel@tonic-gate}
1121*0Sstevel@tonic-gate
1122*0Sstevel@tonic-gate#
1123*0Sstevel@tonic-gate# cosech
1124*0Sstevel@tonic-gate#
1125*0Sstevel@tonic-gate# Alias for csch().
1126*0Sstevel@tonic-gate#
1127*0Sstevel@tonic-gatesub cosech { Math::Complex::csch(@_) }
1128*0Sstevel@tonic-gate
1129*0Sstevel@tonic-gate#
1130*0Sstevel@tonic-gate# coth
1131*0Sstevel@tonic-gate#
1132*0Sstevel@tonic-gate# Computes the hyperbolic cotangent coth(z) = cosh(z) / sinh(z).
1133*0Sstevel@tonic-gate#
1134*0Sstevel@tonic-gatesub coth {
1135*0Sstevel@tonic-gate	my ($z) = @_;
1136*0Sstevel@tonic-gate	my $sz = sinh($z);
1137*0Sstevel@tonic-gate	_divbyzero "coth($z)", "sinh($z)" if $sz == 0;
1138*0Sstevel@tonic-gate	return cosh($z) / $sz;
1139*0Sstevel@tonic-gate}
1140*0Sstevel@tonic-gate
1141*0Sstevel@tonic-gate#
1142*0Sstevel@tonic-gate# cotanh
1143*0Sstevel@tonic-gate#
1144*0Sstevel@tonic-gate# Alias for coth().
1145*0Sstevel@tonic-gate#
1146*0Sstevel@tonic-gatesub cotanh { Math::Complex::coth(@_) }
1147*0Sstevel@tonic-gate
1148*0Sstevel@tonic-gate#
1149*0Sstevel@tonic-gate# acosh
1150*0Sstevel@tonic-gate#
1151*0Sstevel@tonic-gate# Computes the arc hyperbolic cosine acosh(z) = log(z + sqrt(z*z-1)).
1152*0Sstevel@tonic-gate#
1153*0Sstevel@tonic-gatesub acosh {
1154*0Sstevel@tonic-gate	my ($z) = @_;
1155*0Sstevel@tonic-gate	unless (ref $z) {
1156*0Sstevel@tonic-gate	    $z = cplx($z, 0);
1157*0Sstevel@tonic-gate	}
1158*0Sstevel@tonic-gate	my ($re, $im) = @{$z->cartesian};
1159*0Sstevel@tonic-gate	if ($im == 0) {
1160*0Sstevel@tonic-gate	    return CORE::log($re + CORE::sqrt($re*$re - 1))
1161*0Sstevel@tonic-gate		if $re >= 1;
1162*0Sstevel@tonic-gate	    return cplx(0, CORE::atan2(CORE::sqrt(1 - $re*$re), $re))
1163*0Sstevel@tonic-gate		if CORE::abs($re) < 1;
1164*0Sstevel@tonic-gate	}
1165*0Sstevel@tonic-gate	my $t = &sqrt($z * $z - 1) + $z;
1166*0Sstevel@tonic-gate	# Try Taylor if looking bad (this usually means that
1167*0Sstevel@tonic-gate	# $z was large negative, therefore the sqrt is really
1168*0Sstevel@tonic-gate	# close to abs(z), summing that with z...)
1169*0Sstevel@tonic-gate	$t = 1/(2 * $z) - 1/(8 * $z**3) + 1/(16 * $z**5) - 5/(128 * $z**7)
1170*0Sstevel@tonic-gate	    if $t == 0;
1171*0Sstevel@tonic-gate	my $u = &log($t);
1172*0Sstevel@tonic-gate	$u->Im(-$u->Im) if $re < 0 && $im == 0;
1173*0Sstevel@tonic-gate	return $re < 0 ? -$u : $u;
1174*0Sstevel@tonic-gate}
1175*0Sstevel@tonic-gate
1176*0Sstevel@tonic-gate#
1177*0Sstevel@tonic-gate# asinh
1178*0Sstevel@tonic-gate#
1179*0Sstevel@tonic-gate# Computes the arc hyperbolic sine asinh(z) = log(z + sqrt(z*z+1))
1180*0Sstevel@tonic-gate#
1181*0Sstevel@tonic-gatesub asinh {
1182*0Sstevel@tonic-gate	my ($z) = @_;
1183*0Sstevel@tonic-gate	unless (ref $z) {
1184*0Sstevel@tonic-gate	    my $t = $z + CORE::sqrt($z*$z + 1);
1185*0Sstevel@tonic-gate	    return CORE::log($t) if $t;
1186*0Sstevel@tonic-gate	}
1187*0Sstevel@tonic-gate	my $t = &sqrt($z * $z + 1) + $z;
1188*0Sstevel@tonic-gate	# Try Taylor if looking bad (this usually means that
1189*0Sstevel@tonic-gate	# $z was large negative, therefore the sqrt is really
1190*0Sstevel@tonic-gate	# close to abs(z), summing that with z...)
1191*0Sstevel@tonic-gate	$t = 1/(2 * $z) - 1/(8 * $z**3) + 1/(16 * $z**5) - 5/(128 * $z**7)
1192*0Sstevel@tonic-gate	    if $t == 0;
1193*0Sstevel@tonic-gate	return &log($t);
1194*0Sstevel@tonic-gate}
1195*0Sstevel@tonic-gate
1196*0Sstevel@tonic-gate#
1197*0Sstevel@tonic-gate# atanh
1198*0Sstevel@tonic-gate#
1199*0Sstevel@tonic-gate# Computes the arc hyperbolic tangent atanh(z) = 1/2 log((1+z) / (1-z)).
1200*0Sstevel@tonic-gate#
1201*0Sstevel@tonic-gatesub atanh {
1202*0Sstevel@tonic-gate	my ($z) = @_;
1203*0Sstevel@tonic-gate	unless (ref $z) {
1204*0Sstevel@tonic-gate	    return CORE::log((1 + $z)/(1 - $z))/2 if CORE::abs($z) < 1;
1205*0Sstevel@tonic-gate	    $z = cplx($z, 0);
1206*0Sstevel@tonic-gate	}
1207*0Sstevel@tonic-gate	_divbyzero 'atanh(1)',  "1 - $z" if (1 - $z == 0);
1208*0Sstevel@tonic-gate	_logofzero 'atanh(-1)'           if (1 + $z == 0);
1209*0Sstevel@tonic-gate	return 0.5 * &log((1 + $z) / (1 - $z));
1210*0Sstevel@tonic-gate}
1211*0Sstevel@tonic-gate
1212*0Sstevel@tonic-gate#
1213*0Sstevel@tonic-gate# asech
1214*0Sstevel@tonic-gate#
1215*0Sstevel@tonic-gate# Computes the hyperbolic arc secant asech(z) = acosh(1 / z).
1216*0Sstevel@tonic-gate#
1217*0Sstevel@tonic-gatesub asech {
1218*0Sstevel@tonic-gate	my ($z) = @_;
1219*0Sstevel@tonic-gate	_divbyzero 'asech(0)', "$z" if ($z == 0);
1220*0Sstevel@tonic-gate	return acosh(1 / $z);
1221*0Sstevel@tonic-gate}
1222*0Sstevel@tonic-gate
1223*0Sstevel@tonic-gate#
1224*0Sstevel@tonic-gate# acsch
1225*0Sstevel@tonic-gate#
1226*0Sstevel@tonic-gate# Computes the hyperbolic arc cosecant acsch(z) = asinh(1 / z).
1227*0Sstevel@tonic-gate#
1228*0Sstevel@tonic-gatesub acsch {
1229*0Sstevel@tonic-gate	my ($z) = @_;
1230*0Sstevel@tonic-gate	_divbyzero 'acsch(0)', $z if ($z == 0);
1231*0Sstevel@tonic-gate	return asinh(1 / $z);
1232*0Sstevel@tonic-gate}
1233*0Sstevel@tonic-gate
1234*0Sstevel@tonic-gate#
1235*0Sstevel@tonic-gate# acosech
1236*0Sstevel@tonic-gate#
1237*0Sstevel@tonic-gate# Alias for acosh().
1238*0Sstevel@tonic-gate#
1239*0Sstevel@tonic-gatesub acosech { Math::Complex::acsch(@_) }
1240*0Sstevel@tonic-gate
1241*0Sstevel@tonic-gate#
1242*0Sstevel@tonic-gate# acoth
1243*0Sstevel@tonic-gate#
1244*0Sstevel@tonic-gate# Computes the arc hyperbolic cotangent acoth(z) = 1/2 log((1+z) / (z-1)).
1245*0Sstevel@tonic-gate#
1246*0Sstevel@tonic-gatesub acoth {
1247*0Sstevel@tonic-gate	my ($z) = @_;
1248*0Sstevel@tonic-gate	_divbyzero 'acoth(0)'            if ($z == 0);
1249*0Sstevel@tonic-gate	unless (ref $z) {
1250*0Sstevel@tonic-gate	    return CORE::log(($z + 1)/($z - 1))/2 if CORE::abs($z) > 1;
1251*0Sstevel@tonic-gate	    $z = cplx($z, 0);
1252*0Sstevel@tonic-gate	}
1253*0Sstevel@tonic-gate	_divbyzero 'acoth(1)',  "$z - 1" if ($z - 1 == 0);
1254*0Sstevel@tonic-gate	_logofzero 'acoth(-1)', "1 + $z" if (1 + $z == 0);
1255*0Sstevel@tonic-gate	return &log((1 + $z) / ($z - 1)) / 2;
1256*0Sstevel@tonic-gate}
1257*0Sstevel@tonic-gate
1258*0Sstevel@tonic-gate#
1259*0Sstevel@tonic-gate# acotanh
1260*0Sstevel@tonic-gate#
1261*0Sstevel@tonic-gate# Alias for acot().
1262*0Sstevel@tonic-gate#
1263*0Sstevel@tonic-gatesub acotanh { Math::Complex::acoth(@_) }
1264*0Sstevel@tonic-gate
1265*0Sstevel@tonic-gate#
1266*0Sstevel@tonic-gate# (atan2)
1267*0Sstevel@tonic-gate#
1268*0Sstevel@tonic-gate# Compute atan(z1/z2).
1269*0Sstevel@tonic-gate#
1270*0Sstevel@tonic-gatesub atan2 {
1271*0Sstevel@tonic-gate	my ($z1, $z2, $inverted) = @_;
1272*0Sstevel@tonic-gate	my ($re1, $im1, $re2, $im2);
1273*0Sstevel@tonic-gate	if ($inverted) {
1274*0Sstevel@tonic-gate	    ($re1, $im1) = ref $z2 ? @{$z2->cartesian} : ($z2, 0);
1275*0Sstevel@tonic-gate	    ($re2, $im2) = @{$z1->cartesian};
1276*0Sstevel@tonic-gate	} else {
1277*0Sstevel@tonic-gate	    ($re1, $im1) = @{$z1->cartesian};
1278*0Sstevel@tonic-gate	    ($re2, $im2) = ref $z2 ? @{$z2->cartesian} : ($z2, 0);
1279*0Sstevel@tonic-gate	}
1280*0Sstevel@tonic-gate	if ($im2 == 0) {
1281*0Sstevel@tonic-gate	    return CORE::atan2($re1, $re2) if $im1 == 0;
1282*0Sstevel@tonic-gate	    return ($im1<=>0) * pip2 if $re2 == 0;
1283*0Sstevel@tonic-gate	}
1284*0Sstevel@tonic-gate	my $w = atan($z1/$z2);
1285*0Sstevel@tonic-gate	my ($u, $v) = ref $w ? @{$w->cartesian} : ($w, 0);
1286*0Sstevel@tonic-gate	$u += pi   if $re2 < 0;
1287*0Sstevel@tonic-gate	$u -= pit2 if $u > pi;
1288*0Sstevel@tonic-gate	return cplx($u, $v);
1289*0Sstevel@tonic-gate}
1290*0Sstevel@tonic-gate
1291*0Sstevel@tonic-gate#
1292*0Sstevel@tonic-gate# display_format
1293*0Sstevel@tonic-gate# ->display_format
1294*0Sstevel@tonic-gate#
1295*0Sstevel@tonic-gate# Set (get if no argument) the display format for all complex numbers that
1296*0Sstevel@tonic-gate# don't happen to have overridden it via ->display_format
1297*0Sstevel@tonic-gate#
1298*0Sstevel@tonic-gate# When called as an object method, this actually sets the display format for
1299*0Sstevel@tonic-gate# the current object.
1300*0Sstevel@tonic-gate#
1301*0Sstevel@tonic-gate# Valid object formats are 'c' and 'p' for cartesian and polar. The first
1302*0Sstevel@tonic-gate# letter is used actually, so the type can be fully spelled out for clarity.
1303*0Sstevel@tonic-gate#
1304*0Sstevel@tonic-gatesub display_format {
1305*0Sstevel@tonic-gate	my $self  = shift;
1306*0Sstevel@tonic-gate	my %display_format = %DISPLAY_FORMAT;
1307*0Sstevel@tonic-gate
1308*0Sstevel@tonic-gate	if (ref $self) {			# Called as an object method
1309*0Sstevel@tonic-gate	    if (exists $self->{display_format}) {
1310*0Sstevel@tonic-gate		my %obj = %{$self->{display_format}};
1311*0Sstevel@tonic-gate		@display_format{keys %obj} = values %obj;
1312*0Sstevel@tonic-gate	    }
1313*0Sstevel@tonic-gate	}
1314*0Sstevel@tonic-gate	if (@_ == 1) {
1315*0Sstevel@tonic-gate	    $display_format{style} = shift;
1316*0Sstevel@tonic-gate	} else {
1317*0Sstevel@tonic-gate	    my %new = @_;
1318*0Sstevel@tonic-gate	    @display_format{keys %new} = values %new;
1319*0Sstevel@tonic-gate	}
1320*0Sstevel@tonic-gate
1321*0Sstevel@tonic-gate	if (ref $self) { # Called as an object method
1322*0Sstevel@tonic-gate	    $self->{display_format} = { %display_format };
1323*0Sstevel@tonic-gate	    return
1324*0Sstevel@tonic-gate		wantarray ?
1325*0Sstevel@tonic-gate		    %{$self->{display_format}} :
1326*0Sstevel@tonic-gate		    $self->{display_format}->{style};
1327*0Sstevel@tonic-gate	}
1328*0Sstevel@tonic-gate
1329*0Sstevel@tonic-gate        # Called as a class method
1330*0Sstevel@tonic-gate	%DISPLAY_FORMAT = %display_format;
1331*0Sstevel@tonic-gate	return
1332*0Sstevel@tonic-gate	    wantarray ?
1333*0Sstevel@tonic-gate		%DISPLAY_FORMAT :
1334*0Sstevel@tonic-gate		    $DISPLAY_FORMAT{style};
1335*0Sstevel@tonic-gate}
1336*0Sstevel@tonic-gate
1337*0Sstevel@tonic-gate#
1338*0Sstevel@tonic-gate# (stringify)
1339*0Sstevel@tonic-gate#
1340*0Sstevel@tonic-gate# Show nicely formatted complex number under its cartesian or polar form,
1341*0Sstevel@tonic-gate# depending on the current display format:
1342*0Sstevel@tonic-gate#
1343*0Sstevel@tonic-gate# . If a specific display format has been recorded for this object, use it.
1344*0Sstevel@tonic-gate# . Otherwise, use the generic current default for all complex numbers,
1345*0Sstevel@tonic-gate#   which is a package global variable.
1346*0Sstevel@tonic-gate#
1347*0Sstevel@tonic-gatesub stringify {
1348*0Sstevel@tonic-gate	my ($z) = shift;
1349*0Sstevel@tonic-gate
1350*0Sstevel@tonic-gate	my $style = $z->display_format;
1351*0Sstevel@tonic-gate
1352*0Sstevel@tonic-gate	$style = $DISPLAY_FORMAT{style} unless defined $style;
1353*0Sstevel@tonic-gate
1354*0Sstevel@tonic-gate	return $z->stringify_polar if $style =~ /^p/i;
1355*0Sstevel@tonic-gate	return $z->stringify_cartesian;
1356*0Sstevel@tonic-gate}
1357*0Sstevel@tonic-gate
1358*0Sstevel@tonic-gate#
1359*0Sstevel@tonic-gate# ->stringify_cartesian
1360*0Sstevel@tonic-gate#
1361*0Sstevel@tonic-gate# Stringify as a cartesian representation 'a+bi'.
1362*0Sstevel@tonic-gate#
1363*0Sstevel@tonic-gatesub stringify_cartesian {
1364*0Sstevel@tonic-gate	my $z  = shift;
1365*0Sstevel@tonic-gate	my ($x, $y) = @{$z->cartesian};
1366*0Sstevel@tonic-gate	my ($re, $im);
1367*0Sstevel@tonic-gate
1368*0Sstevel@tonic-gate	my %format = $z->display_format;
1369*0Sstevel@tonic-gate	my $format = $format{format};
1370*0Sstevel@tonic-gate
1371*0Sstevel@tonic-gate	if ($x) {
1372*0Sstevel@tonic-gate	    if ($x =~ /^NaN[QS]?$/i) {
1373*0Sstevel@tonic-gate		$re = $x;
1374*0Sstevel@tonic-gate	    } else {
1375*0Sstevel@tonic-gate		if ($x =~ /^-?$Inf$/oi) {
1376*0Sstevel@tonic-gate		    $re = $x;
1377*0Sstevel@tonic-gate		} else {
1378*0Sstevel@tonic-gate		    $re = defined $format ? sprintf($format, $x) : $x;
1379*0Sstevel@tonic-gate		}
1380*0Sstevel@tonic-gate	    }
1381*0Sstevel@tonic-gate	} else {
1382*0Sstevel@tonic-gate	    undef $re;
1383*0Sstevel@tonic-gate	}
1384*0Sstevel@tonic-gate
1385*0Sstevel@tonic-gate	if ($y) {
1386*0Sstevel@tonic-gate	    if ($y =~ /^(NaN[QS]?)$/i) {
1387*0Sstevel@tonic-gate		$im = $y;
1388*0Sstevel@tonic-gate	    } else {
1389*0Sstevel@tonic-gate		if ($y =~ /^-?$Inf$/oi) {
1390*0Sstevel@tonic-gate		    $im = $y;
1391*0Sstevel@tonic-gate		} else {
1392*0Sstevel@tonic-gate		    $im =
1393*0Sstevel@tonic-gate			defined $format ?
1394*0Sstevel@tonic-gate			    sprintf($format, $y) :
1395*0Sstevel@tonic-gate			    ($y == 1 ? "" : ($y == -1 ? "-" : $y));
1396*0Sstevel@tonic-gate		}
1397*0Sstevel@tonic-gate	    }
1398*0Sstevel@tonic-gate	    $im .= "i";
1399*0Sstevel@tonic-gate	} else {
1400*0Sstevel@tonic-gate	    undef $im;
1401*0Sstevel@tonic-gate	}
1402*0Sstevel@tonic-gate
1403*0Sstevel@tonic-gate	my $str = $re;
1404*0Sstevel@tonic-gate
1405*0Sstevel@tonic-gate	if (defined $im) {
1406*0Sstevel@tonic-gate	    if ($y < 0) {
1407*0Sstevel@tonic-gate		$str .= $im;
1408*0Sstevel@tonic-gate	    } elsif ($y > 0 || $im =~ /^NaN[QS]?i$/i)  {
1409*0Sstevel@tonic-gate		$str .= "+" if defined $re;
1410*0Sstevel@tonic-gate		$str .= $im;
1411*0Sstevel@tonic-gate	    }
1412*0Sstevel@tonic-gate	} elsif (!defined $re) {
1413*0Sstevel@tonic-gate	    $str = "0";
1414*0Sstevel@tonic-gate	}
1415*0Sstevel@tonic-gate
1416*0Sstevel@tonic-gate	return $str;
1417*0Sstevel@tonic-gate}
1418*0Sstevel@tonic-gate
1419*0Sstevel@tonic-gate
1420*0Sstevel@tonic-gate#
1421*0Sstevel@tonic-gate# ->stringify_polar
1422*0Sstevel@tonic-gate#
1423*0Sstevel@tonic-gate# Stringify as a polar representation '[r,t]'.
1424*0Sstevel@tonic-gate#
1425*0Sstevel@tonic-gatesub stringify_polar {
1426*0Sstevel@tonic-gate	my $z  = shift;
1427*0Sstevel@tonic-gate	my ($r, $t) = @{$z->polar};
1428*0Sstevel@tonic-gate	my $theta;
1429*0Sstevel@tonic-gate
1430*0Sstevel@tonic-gate	my %format = $z->display_format;
1431*0Sstevel@tonic-gate	my $format = $format{format};
1432*0Sstevel@tonic-gate
1433*0Sstevel@tonic-gate	if ($t =~ /^NaN[QS]?$/i || $t =~ /^-?$Inf$/oi) {
1434*0Sstevel@tonic-gate	    $theta = $t;
1435*0Sstevel@tonic-gate	} elsif ($t == pi) {
1436*0Sstevel@tonic-gate	    $theta = "pi";
1437*0Sstevel@tonic-gate	} elsif ($r == 0 || $t == 0) {
1438*0Sstevel@tonic-gate	    $theta = defined $format ? sprintf($format, $t) : $t;
1439*0Sstevel@tonic-gate	}
1440*0Sstevel@tonic-gate
1441*0Sstevel@tonic-gate	return "[$r,$theta]" if defined $theta;
1442*0Sstevel@tonic-gate
1443*0Sstevel@tonic-gate	#
1444*0Sstevel@tonic-gate	# Try to identify pi/n and friends.
1445*0Sstevel@tonic-gate	#
1446*0Sstevel@tonic-gate
1447*0Sstevel@tonic-gate	$t -= int(CORE::abs($t) / pit2) * pit2;
1448*0Sstevel@tonic-gate
1449*0Sstevel@tonic-gate	if ($format{polar_pretty_print} && $t) {
1450*0Sstevel@tonic-gate	    my ($a, $b);
1451*0Sstevel@tonic-gate	    for $a (2..9) {
1452*0Sstevel@tonic-gate		$b = $t * $a / pi;
1453*0Sstevel@tonic-gate		if ($b =~ /^-?\d+$/) {
1454*0Sstevel@tonic-gate		    $b = $b < 0 ? "-" : "" if CORE::abs($b) == 1;
1455*0Sstevel@tonic-gate		    $theta = "${b}pi/$a";
1456*0Sstevel@tonic-gate		    last;
1457*0Sstevel@tonic-gate		}
1458*0Sstevel@tonic-gate	    }
1459*0Sstevel@tonic-gate	}
1460*0Sstevel@tonic-gate
1461*0Sstevel@tonic-gate        if (defined $format) {
1462*0Sstevel@tonic-gate	    $r     = sprintf($format, $r);
1463*0Sstevel@tonic-gate	    $theta = sprintf($format, $theta) unless defined $theta;
1464*0Sstevel@tonic-gate	} else {
1465*0Sstevel@tonic-gate	    $theta = $t unless defined $theta;
1466*0Sstevel@tonic-gate	}
1467*0Sstevel@tonic-gate
1468*0Sstevel@tonic-gate	return "[$r,$theta]";
1469*0Sstevel@tonic-gate}
1470*0Sstevel@tonic-gate
1471*0Sstevel@tonic-gate1;
1472*0Sstevel@tonic-gate__END__
1473*0Sstevel@tonic-gate
1474*0Sstevel@tonic-gate=pod
1475*0Sstevel@tonic-gate
1476*0Sstevel@tonic-gate=head1 NAME
1477*0Sstevel@tonic-gate
1478*0Sstevel@tonic-gateMath::Complex - complex numbers and associated mathematical functions
1479*0Sstevel@tonic-gate
1480*0Sstevel@tonic-gate=head1 SYNOPSIS
1481*0Sstevel@tonic-gate
1482*0Sstevel@tonic-gate	use Math::Complex;
1483*0Sstevel@tonic-gate
1484*0Sstevel@tonic-gate	$z = Math::Complex->make(5, 6);
1485*0Sstevel@tonic-gate	$t = 4 - 3*i + $z;
1486*0Sstevel@tonic-gate	$j = cplxe(1, 2*pi/3);
1487*0Sstevel@tonic-gate
1488*0Sstevel@tonic-gate=head1 DESCRIPTION
1489*0Sstevel@tonic-gate
1490*0Sstevel@tonic-gateThis package lets you create and manipulate complex numbers. By default,
1491*0Sstevel@tonic-gateI<Perl> limits itself to real numbers, but an extra C<use> statement brings
1492*0Sstevel@tonic-gatefull complex support, along with a full set of mathematical functions
1493*0Sstevel@tonic-gatetypically associated with and/or extended to complex numbers.
1494*0Sstevel@tonic-gate
1495*0Sstevel@tonic-gateIf you wonder what complex numbers are, they were invented to be able to solve
1496*0Sstevel@tonic-gatethe following equation:
1497*0Sstevel@tonic-gate
1498*0Sstevel@tonic-gate	x*x = -1
1499*0Sstevel@tonic-gate
1500*0Sstevel@tonic-gateand by definition, the solution is noted I<i> (engineers use I<j> instead since
1501*0Sstevel@tonic-gateI<i> usually denotes an intensity, but the name does not matter). The number
1502*0Sstevel@tonic-gateI<i> is a pure I<imaginary> number.
1503*0Sstevel@tonic-gate
1504*0Sstevel@tonic-gateThe arithmetics with pure imaginary numbers works just like you would expect
1505*0Sstevel@tonic-gateit with real numbers... you just have to remember that
1506*0Sstevel@tonic-gate
1507*0Sstevel@tonic-gate	i*i = -1
1508*0Sstevel@tonic-gate
1509*0Sstevel@tonic-gateso you have:
1510*0Sstevel@tonic-gate
1511*0Sstevel@tonic-gate	5i + 7i = i * (5 + 7) = 12i
1512*0Sstevel@tonic-gate	4i - 3i = i * (4 - 3) = i
1513*0Sstevel@tonic-gate	4i * 2i = -8
1514*0Sstevel@tonic-gate	6i / 2i = 3
1515*0Sstevel@tonic-gate	1 / i = -i
1516*0Sstevel@tonic-gate
1517*0Sstevel@tonic-gateComplex numbers are numbers that have both a real part and an imaginary
1518*0Sstevel@tonic-gatepart, and are usually noted:
1519*0Sstevel@tonic-gate
1520*0Sstevel@tonic-gate	a + bi
1521*0Sstevel@tonic-gate
1522*0Sstevel@tonic-gatewhere C<a> is the I<real> part and C<b> is the I<imaginary> part. The
1523*0Sstevel@tonic-gatearithmetic with complex numbers is straightforward. You have to
1524*0Sstevel@tonic-gatekeep track of the real and the imaginary parts, but otherwise the
1525*0Sstevel@tonic-gaterules used for real numbers just apply:
1526*0Sstevel@tonic-gate
1527*0Sstevel@tonic-gate	(4 + 3i) + (5 - 2i) = (4 + 5) + i(3 - 2) = 9 + i
1528*0Sstevel@tonic-gate	(2 + i) * (4 - i) = 2*4 + 4i -2i -i*i = 8 + 2i + 1 = 9 + 2i
1529*0Sstevel@tonic-gate
1530*0Sstevel@tonic-gateA graphical representation of complex numbers is possible in a plane
1531*0Sstevel@tonic-gate(also called the I<complex plane>, but it's really a 2D plane).
1532*0Sstevel@tonic-gateThe number
1533*0Sstevel@tonic-gate
1534*0Sstevel@tonic-gate	z = a + bi
1535*0Sstevel@tonic-gate
1536*0Sstevel@tonic-gateis the point whose coordinates are (a, b). Actually, it would
1537*0Sstevel@tonic-gatebe the vector originating from (0, 0) to (a, b). It follows that the addition
1538*0Sstevel@tonic-gateof two complex numbers is a vectorial addition.
1539*0Sstevel@tonic-gate
1540*0Sstevel@tonic-gateSince there is a bijection between a point in the 2D plane and a complex
1541*0Sstevel@tonic-gatenumber (i.e. the mapping is unique and reciprocal), a complex number
1542*0Sstevel@tonic-gatecan also be uniquely identified with polar coordinates:
1543*0Sstevel@tonic-gate
1544*0Sstevel@tonic-gate	[rho, theta]
1545*0Sstevel@tonic-gate
1546*0Sstevel@tonic-gatewhere C<rho> is the distance to the origin, and C<theta> the angle between
1547*0Sstevel@tonic-gatethe vector and the I<x> axis. There is a notation for this using the
1548*0Sstevel@tonic-gateexponential form, which is:
1549*0Sstevel@tonic-gate
1550*0Sstevel@tonic-gate	rho * exp(i * theta)
1551*0Sstevel@tonic-gate
1552*0Sstevel@tonic-gatewhere I<i> is the famous imaginary number introduced above. Conversion
1553*0Sstevel@tonic-gatebetween this form and the cartesian form C<a + bi> is immediate:
1554*0Sstevel@tonic-gate
1555*0Sstevel@tonic-gate	a = rho * cos(theta)
1556*0Sstevel@tonic-gate	b = rho * sin(theta)
1557*0Sstevel@tonic-gate
1558*0Sstevel@tonic-gatewhich is also expressed by this formula:
1559*0Sstevel@tonic-gate
1560*0Sstevel@tonic-gate	z = rho * exp(i * theta) = rho * (cos theta + i * sin theta)
1561*0Sstevel@tonic-gate
1562*0Sstevel@tonic-gateIn other words, it's the projection of the vector onto the I<x> and I<y>
1563*0Sstevel@tonic-gateaxes. Mathematicians call I<rho> the I<norm> or I<modulus> and I<theta>
1564*0Sstevel@tonic-gatethe I<argument> of the complex number. The I<norm> of C<z> will be
1565*0Sstevel@tonic-gatenoted C<abs(z)>.
1566*0Sstevel@tonic-gate
1567*0Sstevel@tonic-gateThe polar notation (also known as the trigonometric
1568*0Sstevel@tonic-gaterepresentation) is much more handy for performing multiplications and
1569*0Sstevel@tonic-gatedivisions of complex numbers, whilst the cartesian notation is better
1570*0Sstevel@tonic-gatesuited for additions and subtractions. Real numbers are on the I<x>
1571*0Sstevel@tonic-gateaxis, and therefore I<theta> is zero or I<pi>.
1572*0Sstevel@tonic-gate
1573*0Sstevel@tonic-gateAll the common operations that can be performed on a real number have
1574*0Sstevel@tonic-gatebeen defined to work on complex numbers as well, and are merely
1575*0Sstevel@tonic-gateI<extensions> of the operations defined on real numbers. This means
1576*0Sstevel@tonic-gatethey keep their natural meaning when there is no imaginary part, provided
1577*0Sstevel@tonic-gatethe number is within their definition set.
1578*0Sstevel@tonic-gate
1579*0Sstevel@tonic-gateFor instance, the C<sqrt> routine which computes the square root of
1580*0Sstevel@tonic-gateits argument is only defined for non-negative real numbers and yields a
1581*0Sstevel@tonic-gatenon-negative real number (it is an application from B<R+> to B<R+>).
1582*0Sstevel@tonic-gateIf we allow it to return a complex number, then it can be extended to
1583*0Sstevel@tonic-gatenegative real numbers to become an application from B<R> to B<C> (the
1584*0Sstevel@tonic-gateset of complex numbers):
1585*0Sstevel@tonic-gate
1586*0Sstevel@tonic-gate	sqrt(x) = x >= 0 ? sqrt(x) : sqrt(-x)*i
1587*0Sstevel@tonic-gate
1588*0Sstevel@tonic-gateIt can also be extended to be an application from B<C> to B<C>,
1589*0Sstevel@tonic-gatewhilst its restriction to B<R> behaves as defined above by using
1590*0Sstevel@tonic-gatethe following definition:
1591*0Sstevel@tonic-gate
1592*0Sstevel@tonic-gate	sqrt(z = [r,t]) = sqrt(r) * exp(i * t/2)
1593*0Sstevel@tonic-gate
1594*0Sstevel@tonic-gateIndeed, a negative real number can be noted C<[x,pi]> (the modulus
1595*0Sstevel@tonic-gateI<x> is always non-negative, so C<[x,pi]> is really C<-x>, a negative
1596*0Sstevel@tonic-gatenumber) and the above definition states that
1597*0Sstevel@tonic-gate
1598*0Sstevel@tonic-gate	sqrt([x,pi]) = sqrt(x) * exp(i*pi/2) = [sqrt(x),pi/2] = sqrt(x)*i
1599*0Sstevel@tonic-gate
1600*0Sstevel@tonic-gatewhich is exactly what we had defined for negative real numbers above.
1601*0Sstevel@tonic-gateThe C<sqrt> returns only one of the solutions: if you want the both,
1602*0Sstevel@tonic-gateuse the C<root> function.
1603*0Sstevel@tonic-gate
1604*0Sstevel@tonic-gateAll the common mathematical functions defined on real numbers that
1605*0Sstevel@tonic-gateare extended to complex numbers share that same property of working
1606*0Sstevel@tonic-gateI<as usual> when the imaginary part is zero (otherwise, it would not
1607*0Sstevel@tonic-gatebe called an extension, would it?).
1608*0Sstevel@tonic-gate
1609*0Sstevel@tonic-gateA I<new> operation possible on a complex number that is
1610*0Sstevel@tonic-gatethe identity for real numbers is called the I<conjugate>, and is noted
1611*0Sstevel@tonic-gatewith a horizontal bar above the number, or C<~z> here.
1612*0Sstevel@tonic-gate
1613*0Sstevel@tonic-gate	 z = a + bi
1614*0Sstevel@tonic-gate	~z = a - bi
1615*0Sstevel@tonic-gate
1616*0Sstevel@tonic-gateSimple... Now look:
1617*0Sstevel@tonic-gate
1618*0Sstevel@tonic-gate	z * ~z = (a + bi) * (a - bi) = a*a + b*b
1619*0Sstevel@tonic-gate
1620*0Sstevel@tonic-gateWe saw that the norm of C<z> was noted C<abs(z)> and was defined as the
1621*0Sstevel@tonic-gatedistance to the origin, also known as:
1622*0Sstevel@tonic-gate
1623*0Sstevel@tonic-gate	rho = abs(z) = sqrt(a*a + b*b)
1624*0Sstevel@tonic-gate
1625*0Sstevel@tonic-gateso
1626*0Sstevel@tonic-gate
1627*0Sstevel@tonic-gate	z * ~z = abs(z) ** 2
1628*0Sstevel@tonic-gate
1629*0Sstevel@tonic-gateIf z is a pure real number (i.e. C<b == 0>), then the above yields:
1630*0Sstevel@tonic-gate
1631*0Sstevel@tonic-gate	a * a = abs(a) ** 2
1632*0Sstevel@tonic-gate
1633*0Sstevel@tonic-gatewhich is true (C<abs> has the regular meaning for real number, i.e. stands
1634*0Sstevel@tonic-gatefor the absolute value). This example explains why the norm of C<z> is
1635*0Sstevel@tonic-gatenoted C<abs(z)>: it extends the C<abs> function to complex numbers, yet
1636*0Sstevel@tonic-gateis the regular C<abs> we know when the complex number actually has no
1637*0Sstevel@tonic-gateimaginary part... This justifies I<a posteriori> our use of the C<abs>
1638*0Sstevel@tonic-gatenotation for the norm.
1639*0Sstevel@tonic-gate
1640*0Sstevel@tonic-gate=head1 OPERATIONS
1641*0Sstevel@tonic-gate
1642*0Sstevel@tonic-gateGiven the following notations:
1643*0Sstevel@tonic-gate
1644*0Sstevel@tonic-gate	z1 = a + bi = r1 * exp(i * t1)
1645*0Sstevel@tonic-gate	z2 = c + di = r2 * exp(i * t2)
1646*0Sstevel@tonic-gate	z = <any complex or real number>
1647*0Sstevel@tonic-gate
1648*0Sstevel@tonic-gatethe following (overloaded) operations are supported on complex numbers:
1649*0Sstevel@tonic-gate
1650*0Sstevel@tonic-gate	z1 + z2 = (a + c) + i(b + d)
1651*0Sstevel@tonic-gate	z1 - z2 = (a - c) + i(b - d)
1652*0Sstevel@tonic-gate	z1 * z2 = (r1 * r2) * exp(i * (t1 + t2))
1653*0Sstevel@tonic-gate	z1 / z2 = (r1 / r2) * exp(i * (t1 - t2))
1654*0Sstevel@tonic-gate	z1 ** z2 = exp(z2 * log z1)
1655*0Sstevel@tonic-gate	~z = a - bi
1656*0Sstevel@tonic-gate	abs(z) = r1 = sqrt(a*a + b*b)
1657*0Sstevel@tonic-gate	sqrt(z) = sqrt(r1) * exp(i * t/2)
1658*0Sstevel@tonic-gate	exp(z) = exp(a) * exp(i * b)
1659*0Sstevel@tonic-gate	log(z) = log(r1) + i*t
1660*0Sstevel@tonic-gate	sin(z) = 1/2i (exp(i * z1) - exp(-i * z))
1661*0Sstevel@tonic-gate	cos(z) = 1/2 (exp(i * z1) + exp(-i * z))
1662*0Sstevel@tonic-gate	atan2(z1, z2) = atan(z1/z2)
1663*0Sstevel@tonic-gate
1664*0Sstevel@tonic-gateThe following extra operations are supported on both real and complex
1665*0Sstevel@tonic-gatenumbers:
1666*0Sstevel@tonic-gate
1667*0Sstevel@tonic-gate	Re(z) = a
1668*0Sstevel@tonic-gate	Im(z) = b
1669*0Sstevel@tonic-gate	arg(z) = t
1670*0Sstevel@tonic-gate	abs(z) = r
1671*0Sstevel@tonic-gate
1672*0Sstevel@tonic-gate	cbrt(z) = z ** (1/3)
1673*0Sstevel@tonic-gate	log10(z) = log(z) / log(10)
1674*0Sstevel@tonic-gate	logn(z, n) = log(z) / log(n)
1675*0Sstevel@tonic-gate
1676*0Sstevel@tonic-gate	tan(z) = sin(z) / cos(z)
1677*0Sstevel@tonic-gate
1678*0Sstevel@tonic-gate	csc(z) = 1 / sin(z)
1679*0Sstevel@tonic-gate	sec(z) = 1 / cos(z)
1680*0Sstevel@tonic-gate	cot(z) = 1 / tan(z)
1681*0Sstevel@tonic-gate
1682*0Sstevel@tonic-gate	asin(z) = -i * log(i*z + sqrt(1-z*z))
1683*0Sstevel@tonic-gate	acos(z) = -i * log(z + i*sqrt(1-z*z))
1684*0Sstevel@tonic-gate	atan(z) = i/2 * log((i+z) / (i-z))
1685*0Sstevel@tonic-gate
1686*0Sstevel@tonic-gate	acsc(z) = asin(1 / z)
1687*0Sstevel@tonic-gate	asec(z) = acos(1 / z)
1688*0Sstevel@tonic-gate	acot(z) = atan(1 / z) = -i/2 * log((i+z) / (z-i))
1689*0Sstevel@tonic-gate
1690*0Sstevel@tonic-gate	sinh(z) = 1/2 (exp(z) - exp(-z))
1691*0Sstevel@tonic-gate	cosh(z) = 1/2 (exp(z) + exp(-z))
1692*0Sstevel@tonic-gate	tanh(z) = sinh(z) / cosh(z) = (exp(z) - exp(-z)) / (exp(z) + exp(-z))
1693*0Sstevel@tonic-gate
1694*0Sstevel@tonic-gate	csch(z) = 1 / sinh(z)
1695*0Sstevel@tonic-gate	sech(z) = 1 / cosh(z)
1696*0Sstevel@tonic-gate	coth(z) = 1 / tanh(z)
1697*0Sstevel@tonic-gate
1698*0Sstevel@tonic-gate	asinh(z) = log(z + sqrt(z*z+1))
1699*0Sstevel@tonic-gate	acosh(z) = log(z + sqrt(z*z-1))
1700*0Sstevel@tonic-gate	atanh(z) = 1/2 * log((1+z) / (1-z))
1701*0Sstevel@tonic-gate
1702*0Sstevel@tonic-gate	acsch(z) = asinh(1 / z)
1703*0Sstevel@tonic-gate	asech(z) = acosh(1 / z)
1704*0Sstevel@tonic-gate	acoth(z) = atanh(1 / z) = 1/2 * log((1+z) / (z-1))
1705*0Sstevel@tonic-gate
1706*0Sstevel@tonic-gateI<arg>, I<abs>, I<log>, I<csc>, I<cot>, I<acsc>, I<acot>, I<csch>,
1707*0Sstevel@tonic-gateI<coth>, I<acosech>, I<acotanh>, have aliases I<rho>, I<theta>, I<ln>,
1708*0Sstevel@tonic-gateI<cosec>, I<cotan>, I<acosec>, I<acotan>, I<cosech>, I<cotanh>,
1709*0Sstevel@tonic-gateI<acosech>, I<acotanh>, respectively.  C<Re>, C<Im>, C<arg>, C<abs>,
1710*0Sstevel@tonic-gateC<rho>, and C<theta> can be used also as mutators.  The C<cbrt>
1711*0Sstevel@tonic-gatereturns only one of the solutions: if you want all three, use the
1712*0Sstevel@tonic-gateC<root> function.
1713*0Sstevel@tonic-gate
1714*0Sstevel@tonic-gateThe I<root> function is available to compute all the I<n>
1715*0Sstevel@tonic-gateroots of some complex, where I<n> is a strictly positive integer.
1716*0Sstevel@tonic-gateThere are exactly I<n> such roots, returned as a list. Getting the
1717*0Sstevel@tonic-gatenumber mathematicians call C<j> such that:
1718*0Sstevel@tonic-gate
1719*0Sstevel@tonic-gate	1 + j + j*j = 0;
1720*0Sstevel@tonic-gate
1721*0Sstevel@tonic-gateis a simple matter of writing:
1722*0Sstevel@tonic-gate
1723*0Sstevel@tonic-gate	$j = ((root(1, 3))[1];
1724*0Sstevel@tonic-gate
1725*0Sstevel@tonic-gateThe I<k>th root for C<z = [r,t]> is given by:
1726*0Sstevel@tonic-gate
1727*0Sstevel@tonic-gate	(root(z, n))[k] = r**(1/n) * exp(i * (t + 2*k*pi)/n)
1728*0Sstevel@tonic-gate
1729*0Sstevel@tonic-gateThe I<spaceship> comparison operator, E<lt>=E<gt>, is also defined. In
1730*0Sstevel@tonic-gateorder to ensure its restriction to real numbers is conform to what you
1731*0Sstevel@tonic-gatewould expect, the comparison is run on the real part of the complex
1732*0Sstevel@tonic-gatenumber first, and imaginary parts are compared only when the real
1733*0Sstevel@tonic-gateparts match.
1734*0Sstevel@tonic-gate
1735*0Sstevel@tonic-gate=head1 CREATION
1736*0Sstevel@tonic-gate
1737*0Sstevel@tonic-gateTo create a complex number, use either:
1738*0Sstevel@tonic-gate
1739*0Sstevel@tonic-gate	$z = Math::Complex->make(3, 4);
1740*0Sstevel@tonic-gate	$z = cplx(3, 4);
1741*0Sstevel@tonic-gate
1742*0Sstevel@tonic-gateif you know the cartesian form of the number, or
1743*0Sstevel@tonic-gate
1744*0Sstevel@tonic-gate	$z = 3 + 4*i;
1745*0Sstevel@tonic-gate
1746*0Sstevel@tonic-gateif you like. To create a number using the polar form, use either:
1747*0Sstevel@tonic-gate
1748*0Sstevel@tonic-gate	$z = Math::Complex->emake(5, pi/3);
1749*0Sstevel@tonic-gate	$x = cplxe(5, pi/3);
1750*0Sstevel@tonic-gate
1751*0Sstevel@tonic-gateinstead. The first argument is the modulus, the second is the angle
1752*0Sstevel@tonic-gate(in radians, the full circle is 2*pi).  (Mnemonic: C<e> is used as a
1753*0Sstevel@tonic-gatenotation for complex numbers in the polar form).
1754*0Sstevel@tonic-gate
1755*0Sstevel@tonic-gateIt is possible to write:
1756*0Sstevel@tonic-gate
1757*0Sstevel@tonic-gate	$x = cplxe(-3, pi/4);
1758*0Sstevel@tonic-gate
1759*0Sstevel@tonic-gatebut that will be silently converted into C<[3,-3pi/4]>, since the
1760*0Sstevel@tonic-gatemodulus must be non-negative (it represents the distance to the origin
1761*0Sstevel@tonic-gatein the complex plane).
1762*0Sstevel@tonic-gate
1763*0Sstevel@tonic-gateIt is also possible to have a complex number as either argument of the
1764*0Sstevel@tonic-gateC<make>, C<emake>, C<cplx>, and C<cplxe>: the appropriate component of
1765*0Sstevel@tonic-gatethe argument will be used.
1766*0Sstevel@tonic-gate
1767*0Sstevel@tonic-gate	$z1 = cplx(-2,  1);
1768*0Sstevel@tonic-gate	$z2 = cplx($z1, 4);
1769*0Sstevel@tonic-gate
1770*0Sstevel@tonic-gateThe C<new>, C<make>, C<emake>, C<cplx>, and C<cplxe> will also
1771*0Sstevel@tonic-gateunderstand a single (string) argument of the forms
1772*0Sstevel@tonic-gate
1773*0Sstevel@tonic-gate    	2-3i
1774*0Sstevel@tonic-gate    	-3i
1775*0Sstevel@tonic-gate	[2,3]
1776*0Sstevel@tonic-gate	[2]
1777*0Sstevel@tonic-gate
1778*0Sstevel@tonic-gatein which case the appropriate cartesian and exponential components
1779*0Sstevel@tonic-gatewill be parsed from the string and used to create new complex numbers.
1780*0Sstevel@tonic-gateThe imaginary component and the theta, respectively, will default to zero.
1781*0Sstevel@tonic-gate
1782*0Sstevel@tonic-gate=head1 STRINGIFICATION
1783*0Sstevel@tonic-gate
1784*0Sstevel@tonic-gateWhen printed, a complex number is usually shown under its cartesian
1785*0Sstevel@tonic-gatestyle I<a+bi>, but there are legitimate cases where the polar style
1786*0Sstevel@tonic-gateI<[r,t]> is more appropriate.
1787*0Sstevel@tonic-gate
1788*0Sstevel@tonic-gateBy calling the class method C<Math::Complex::display_format> and
1789*0Sstevel@tonic-gatesupplying either C<"polar"> or C<"cartesian"> as an argument, you
1790*0Sstevel@tonic-gateoverride the default display style, which is C<"cartesian">. Not
1791*0Sstevel@tonic-gatesupplying any argument returns the current settings.
1792*0Sstevel@tonic-gate
1793*0Sstevel@tonic-gateThis default can be overridden on a per-number basis by calling the
1794*0Sstevel@tonic-gateC<display_format> method instead. As before, not supplying any argument
1795*0Sstevel@tonic-gatereturns the current display style for this number. Otherwise whatever you
1796*0Sstevel@tonic-gatespecify will be the new display style for I<this> particular number.
1797*0Sstevel@tonic-gate
1798*0Sstevel@tonic-gateFor instance:
1799*0Sstevel@tonic-gate
1800*0Sstevel@tonic-gate	use Math::Complex;
1801*0Sstevel@tonic-gate
1802*0Sstevel@tonic-gate	Math::Complex::display_format('polar');
1803*0Sstevel@tonic-gate	$j = (root(1, 3))[1];
1804*0Sstevel@tonic-gate	print "j = $j\n";		# Prints "j = [1,2pi/3]"
1805*0Sstevel@tonic-gate	$j->display_format('cartesian');
1806*0Sstevel@tonic-gate	print "j = $j\n";		# Prints "j = -0.5+0.866025403784439i"
1807*0Sstevel@tonic-gate
1808*0Sstevel@tonic-gateThe polar style attempts to emphasize arguments like I<k*pi/n>
1809*0Sstevel@tonic-gate(where I<n> is a positive integer and I<k> an integer within [-9, +9]),
1810*0Sstevel@tonic-gatethis is called I<polar pretty-printing>.
1811*0Sstevel@tonic-gate
1812*0Sstevel@tonic-gate=head2 CHANGED IN PERL 5.6
1813*0Sstevel@tonic-gate
1814*0Sstevel@tonic-gateThe C<display_format> class method and the corresponding
1815*0Sstevel@tonic-gateC<display_format> object method can now be called using
1816*0Sstevel@tonic-gatea parameter hash instead of just a one parameter.
1817*0Sstevel@tonic-gate
1818*0Sstevel@tonic-gateThe old display format style, which can have values C<"cartesian"> or
1819*0Sstevel@tonic-gateC<"polar">, can be changed using the C<"style"> parameter.
1820*0Sstevel@tonic-gate
1821*0Sstevel@tonic-gate	$j->display_format(style => "polar");
1822*0Sstevel@tonic-gate
1823*0Sstevel@tonic-gateThe one parameter calling convention also still works.
1824*0Sstevel@tonic-gate
1825*0Sstevel@tonic-gate	$j->display_format("polar");
1826*0Sstevel@tonic-gate
1827*0Sstevel@tonic-gateThere are two new display parameters.
1828*0Sstevel@tonic-gate
1829*0Sstevel@tonic-gateThe first one is C<"format">, which is a sprintf()-style format string
1830*0Sstevel@tonic-gateto be used for both numeric parts of the complex number(s).  The is
1831*0Sstevel@tonic-gatesomewhat system-dependent but most often it corresponds to C<"%.15g">.
1832*0Sstevel@tonic-gateYou can revert to the default by setting the C<format> to C<undef>.
1833*0Sstevel@tonic-gate
1834*0Sstevel@tonic-gate	# the $j from the above example
1835*0Sstevel@tonic-gate
1836*0Sstevel@tonic-gate	$j->display_format('format' => '%.5f');
1837*0Sstevel@tonic-gate	print "j = $j\n";		# Prints "j = -0.50000+0.86603i"
1838*0Sstevel@tonic-gate	$j->display_format('format' => undef);
1839*0Sstevel@tonic-gate	print "j = $j\n";		# Prints "j = -0.5+0.86603i"
1840*0Sstevel@tonic-gate
1841*0Sstevel@tonic-gateNotice that this affects also the return values of the
1842*0Sstevel@tonic-gateC<display_format> methods: in list context the whole parameter hash
1843*0Sstevel@tonic-gatewill be returned, as opposed to only the style parameter value.
1844*0Sstevel@tonic-gateThis is a potential incompatibility with earlier versions if you
1845*0Sstevel@tonic-gatehave been calling the C<display_format> method in list context.
1846*0Sstevel@tonic-gate
1847*0Sstevel@tonic-gateThe second new display parameter is C<"polar_pretty_print">, which can
1848*0Sstevel@tonic-gatebe set to true or false, the default being true.  See the previous
1849*0Sstevel@tonic-gatesection for what this means.
1850*0Sstevel@tonic-gate
1851*0Sstevel@tonic-gate=head1 USAGE
1852*0Sstevel@tonic-gate
1853*0Sstevel@tonic-gateThanks to overloading, the handling of arithmetics with complex numbers
1854*0Sstevel@tonic-gateis simple and almost transparent.
1855*0Sstevel@tonic-gate
1856*0Sstevel@tonic-gateHere are some examples:
1857*0Sstevel@tonic-gate
1858*0Sstevel@tonic-gate	use Math::Complex;
1859*0Sstevel@tonic-gate
1860*0Sstevel@tonic-gate	$j = cplxe(1, 2*pi/3);	# $j ** 3 == 1
1861*0Sstevel@tonic-gate	print "j = $j, j**3 = ", $j ** 3, "\n";
1862*0Sstevel@tonic-gate	print "1 + j + j**2 = ", 1 + $j + $j**2, "\n";
1863*0Sstevel@tonic-gate
1864*0Sstevel@tonic-gate	$z = -16 + 0*i;			# Force it to be a complex
1865*0Sstevel@tonic-gate	print "sqrt($z) = ", sqrt($z), "\n";
1866*0Sstevel@tonic-gate
1867*0Sstevel@tonic-gate	$k = exp(i * 2*pi/3);
1868*0Sstevel@tonic-gate	print "$j - $k = ", $j - $k, "\n";
1869*0Sstevel@tonic-gate
1870*0Sstevel@tonic-gate	$z->Re(3);			# Re, Im, arg, abs,
1871*0Sstevel@tonic-gate	$j->arg(2);			# (the last two aka rho, theta)
1872*0Sstevel@tonic-gate					# can be used also as mutators.
1873*0Sstevel@tonic-gate
1874*0Sstevel@tonic-gate=head1 ERRORS DUE TO DIVISION BY ZERO OR LOGARITHM OF ZERO
1875*0Sstevel@tonic-gate
1876*0Sstevel@tonic-gateThe division (/) and the following functions
1877*0Sstevel@tonic-gate
1878*0Sstevel@tonic-gate	log	ln	log10	logn
1879*0Sstevel@tonic-gate	tan	sec	csc	cot
1880*0Sstevel@tonic-gate	atan	asec	acsc	acot
1881*0Sstevel@tonic-gate	tanh	sech	csch	coth
1882*0Sstevel@tonic-gate	atanh	asech	acsch	acoth
1883*0Sstevel@tonic-gate
1884*0Sstevel@tonic-gatecannot be computed for all arguments because that would mean dividing
1885*0Sstevel@tonic-gateby zero or taking logarithm of zero. These situations cause fatal
1886*0Sstevel@tonic-gateruntime errors looking like this
1887*0Sstevel@tonic-gate
1888*0Sstevel@tonic-gate	cot(0): Division by zero.
1889*0Sstevel@tonic-gate	(Because in the definition of cot(0), the divisor sin(0) is 0)
1890*0Sstevel@tonic-gate	Died at ...
1891*0Sstevel@tonic-gate
1892*0Sstevel@tonic-gateor
1893*0Sstevel@tonic-gate
1894*0Sstevel@tonic-gate	atanh(-1): Logarithm of zero.
1895*0Sstevel@tonic-gate	Died at...
1896*0Sstevel@tonic-gate
1897*0Sstevel@tonic-gateFor the C<csc>, C<cot>, C<asec>, C<acsc>, C<acot>, C<csch>, C<coth>,
1898*0Sstevel@tonic-gateC<asech>, C<acsch>, the argument cannot be C<0> (zero).  For the
1899*0Sstevel@tonic-gatelogarithmic functions and the C<atanh>, C<acoth>, the argument cannot
1900*0Sstevel@tonic-gatebe C<1> (one).  For the C<atanh>, C<acoth>, the argument cannot be
1901*0Sstevel@tonic-gateC<-1> (minus one).  For the C<atan>, C<acot>, the argument cannot be
1902*0Sstevel@tonic-gateC<i> (the imaginary unit).  For the C<atan>, C<acoth>, the argument
1903*0Sstevel@tonic-gatecannot be C<-i> (the negative imaginary unit).  For the C<tan>,
1904*0Sstevel@tonic-gateC<sec>, C<tanh>, the argument cannot be I<pi/2 + k * pi>, where I<k>
1905*0Sstevel@tonic-gateis any integer.
1906*0Sstevel@tonic-gate
1907*0Sstevel@tonic-gateNote that because we are operating on approximations of real numbers,
1908*0Sstevel@tonic-gatethese errors can happen when merely `too close' to the singularities
1909*0Sstevel@tonic-gatelisted above.
1910*0Sstevel@tonic-gate
1911*0Sstevel@tonic-gate=head1 ERRORS DUE TO INDIGESTIBLE ARGUMENTS
1912*0Sstevel@tonic-gate
1913*0Sstevel@tonic-gateThe C<make> and C<emake> accept both real and complex arguments.
1914*0Sstevel@tonic-gateWhen they cannot recognize the arguments they will die with error
1915*0Sstevel@tonic-gatemessages like the following
1916*0Sstevel@tonic-gate
1917*0Sstevel@tonic-gate    Math::Complex::make: Cannot take real part of ...
1918*0Sstevel@tonic-gate    Math::Complex::make: Cannot take real part of ...
1919*0Sstevel@tonic-gate    Math::Complex::emake: Cannot take rho of ...
1920*0Sstevel@tonic-gate    Math::Complex::emake: Cannot take theta of ...
1921*0Sstevel@tonic-gate
1922*0Sstevel@tonic-gate=head1 BUGS
1923*0Sstevel@tonic-gate
1924*0Sstevel@tonic-gateSaying C<use Math::Complex;> exports many mathematical routines in the
1925*0Sstevel@tonic-gatecaller environment and even overrides some (C<sqrt>, C<log>).
1926*0Sstevel@tonic-gateThis is construed as a feature by the Authors, actually... ;-)
1927*0Sstevel@tonic-gate
1928*0Sstevel@tonic-gateAll routines expect to be given real or complex numbers. Don't attempt to
1929*0Sstevel@tonic-gateuse BigFloat, since Perl has currently no rule to disambiguate a '+'
1930*0Sstevel@tonic-gateoperation (for instance) between two overloaded entities.
1931*0Sstevel@tonic-gate
1932*0Sstevel@tonic-gateIn Cray UNICOS there is some strange numerical instability that results
1933*0Sstevel@tonic-gatein root(), cos(), sin(), cosh(), sinh(), losing accuracy fast.  Beware.
1934*0Sstevel@tonic-gateThe bug may be in UNICOS math libs, in UNICOS C compiler, in Math::Complex.
1935*0Sstevel@tonic-gateWhatever it is, it does not manifest itself anywhere else where Perl runs.
1936*0Sstevel@tonic-gate
1937*0Sstevel@tonic-gate=head1 AUTHORS
1938*0Sstevel@tonic-gate
1939*0Sstevel@tonic-gateDaniel S. Lewart <F<d-lewart@uiuc.edu>>
1940*0Sstevel@tonic-gate
1941*0Sstevel@tonic-gateOriginal authors Raphael Manfredi <F<Raphael_Manfredi@pobox.com>> and
1942*0Sstevel@tonic-gateJarkko Hietaniemi <F<jhi@iki.fi>>
1943*0Sstevel@tonic-gate
1944*0Sstevel@tonic-gate=cut
1945*0Sstevel@tonic-gate
1946*0Sstevel@tonic-gate1;
1947*0Sstevel@tonic-gate
1948*0Sstevel@tonic-gate# eof
1949