[inseparable changes from match from perl-5.003_97a to perl-5.003_97b]
[p5sagit/p5-mst-13.2.git] / lib / Math / Complex.pm
CommitLineData
66730be0 1# $RCSFile$
2#
3# Complex numbers and associated mathematical functions
0c721ce2 4# -- Raphael Manfredi, September 1996
5cd24f17 5# -- Jarkko Hietaniemi, March-April 1997
a0d0e21e 6
7require Exporter;
5aabfad6 8package Math::Complex;
a0d0e21e 9
0c721ce2 10use strict;
11
5aabfad6 12use vars qw($VERSION @ISA
13 @EXPORT %EXPORT_TAGS
14 $package $display
5cd24f17 15 $i $logn %logn);
0c721ce2 16
5aabfad6 17@ISA = qw(Exporter);
18
19$VERSION = 1.01;
20
21my @trig = qw(
22 pi
5cd24f17 23 sin cos tan
5aabfad6 24 csc cosec sec cot cotan
25 asin acos atan
26 acsc acosec asec acot acotan
27 sinh cosh tanh
28 csch cosech sech coth cotanh
29 asinh acosh atanh
30 acsch acosech asech acoth acotanh
31 );
32
33@EXPORT = (qw(
34 i Re Im arg
35 sqrt exp log ln
36 log10 logn cbrt root
37 cplx cplxe
38 ),
39 @trig);
40
41%EXPORT_TAGS = (
42 'trig' => [@trig],
66730be0 43);
a0d0e21e 44
a5f75d66 45use overload
0c721ce2 46 '+' => \&plus,
47 '-' => \&minus,
48 '*' => \&multiply,
49 '/' => \&divide,
66730be0 50 '**' => \&power,
51 '<=>' => \&spaceship,
52 'neg' => \&negate,
0c721ce2 53 '~' => \&conjugate,
66730be0 54 'abs' => \&abs,
55 'sqrt' => \&sqrt,
56 'exp' => \&exp,
57 'log' => \&log,
58 'sin' => \&sin,
59 'cos' => \&cos,
0c721ce2 60 'tan' => \&tan,
66730be0 61 'atan2' => \&atan2,
62 qw("" stringify);
63
64#
65# Package globals
66#
67
68$package = 'Math::Complex'; # Package name
69$display = 'cartesian'; # Default display format
70
71#
72# Object attributes (internal):
73# cartesian [real, imaginary] -- cartesian form
74# polar [rho, theta] -- polar form
75# c_dirty cartesian form not up-to-date
76# p_dirty polar form not up-to-date
77# display display format (package's global when not set)
78#
79
80#
81# ->make
82#
83# Create a new complex number (cartesian form)
84#
85sub make {
86 my $self = bless {}, shift;
87 my ($re, $im) = @_;
40da2db3 88 $self->{'cartesian'} = [$re, $im];
66730be0 89 $self->{c_dirty} = 0;
90 $self->{p_dirty} = 1;
91 return $self;
92}
93
94#
95# ->emake
96#
97# Create a new complex number (exponential form)
98#
99sub emake {
100 my $self = bless {}, shift;
101 my ($rho, $theta) = @_;
102 $theta += pi() if $rho < 0;
40da2db3 103 $self->{'polar'} = [abs($rho), $theta];
66730be0 104 $self->{p_dirty} = 0;
105 $self->{c_dirty} = 1;
106 return $self;
107}
108
109sub new { &make } # For backward compatibility only.
110
111#
112# cplx
113#
114# Creates a complex number from a (re, im) tuple.
115# This avoids the burden of writing Math::Complex->make(re, im).
116#
117sub cplx {
118 my ($re, $im) = @_;
0c721ce2 119 return $package->make($re, defined $im ? $im : 0);
66730be0 120}
121
122#
123# cplxe
124#
125# Creates a complex number from a (rho, theta) tuple.
126# This avoids the burden of writing Math::Complex->emake(rho, theta).
127#
128sub cplxe {
129 my ($rho, $theta) = @_;
0c721ce2 130 return $package->emake($rho, defined $theta ? $theta : 0);
66730be0 131}
132
133#
134# pi
135#
136# The number defined as 2 * pi = 360 degrees
137#
5cd24f17 138
139use constant pi => 4 * atan2(1, 1);
140
141#
142# log2inv
143#
144# Used in log10().
145#
146
147use constant log10inv => 1 / log(10);
66730be0 148
149#
150# i
151#
152# The number defined as i*i = -1;
153#
154sub i () {
5cd24f17 155 return $i if ($i);
156 $i = bless {};
40da2db3 157 $i->{'cartesian'} = [0, 1];
5cd24f17 158 $i->{'polar'} = [1, pi/2];
66730be0 159 $i->{c_dirty} = 0;
160 $i->{p_dirty} = 0;
161 return $i;
162}
163
164#
165# Attribute access/set routines
166#
167
0c721ce2 168sub cartesian {$_[0]->{c_dirty} ?
169 $_[0]->update_cartesian : $_[0]->{'cartesian'}}
170sub polar {$_[0]->{p_dirty} ?
171 $_[0]->update_polar : $_[0]->{'polar'}}
66730be0 172
40da2db3 173sub set_cartesian { $_[0]->{p_dirty}++; $_[0]->{'cartesian'} = $_[1] }
174sub set_polar { $_[0]->{c_dirty}++; $_[0]->{'polar'} = $_[1] }
66730be0 175
176#
177# ->update_cartesian
178#
179# Recompute and return the cartesian form, given accurate polar form.
180#
181sub update_cartesian {
182 my $self = shift;
40da2db3 183 my ($r, $t) = @{$self->{'polar'}};
66730be0 184 $self->{c_dirty} = 0;
40da2db3 185 return $self->{'cartesian'} = [$r * cos $t, $r * sin $t];
66730be0 186}
187
188#
189#
190# ->update_polar
191#
192# Recompute and return the polar form, given accurate cartesian form.
193#
194sub update_polar {
195 my $self = shift;
40da2db3 196 my ($x, $y) = @{$self->{'cartesian'}};
66730be0 197 $self->{p_dirty} = 0;
40da2db3 198 return $self->{'polar'} = [0, 0] if $x == 0 && $y == 0;
199 return $self->{'polar'} = [sqrt($x*$x + $y*$y), atan2($y, $x)];
66730be0 200}
201
202#
203# (plus)
204#
205# Computes z1+z2.
206#
207sub plus {
208 my ($z1, $z2, $regular) = @_;
209 my ($re1, $im1) = @{$z1->cartesian};
5cd24f17 210 my ($re2, $im2) = ref $z2 ? @{$z2->cartesian} : ($z2, 0);
66730be0 211 unless (defined $regular) {
212 $z1->set_cartesian([$re1 + $re2, $im1 + $im2]);
213 return $z1;
214 }
215 return (ref $z1)->make($re1 + $re2, $im1 + $im2);
216}
217
218#
219# (minus)
220#
221# Computes z1-z2.
222#
223sub minus {
224 my ($z1, $z2, $inverted) = @_;
225 my ($re1, $im1) = @{$z1->cartesian};
5cd24f17 226 my ($re2, $im2) = ref $z2 ? @{$z2->cartesian} : ($z2, 0);
66730be0 227 unless (defined $inverted) {
228 $z1->set_cartesian([$re1 - $re2, $im1 - $im2]);
229 return $z1;
230 }
231 return $inverted ?
232 (ref $z1)->make($re2 - $re1, $im2 - $im1) :
233 (ref $z1)->make($re1 - $re2, $im1 - $im2);
234}
235
236#
237# (multiply)
238#
239# Computes z1*z2.
240#
241sub multiply {
242 my ($z1, $z2, $regular) = @_;
243 my ($r1, $t1) = @{$z1->polar};
0c721ce2 244 my ($r2, $t2) = ref $z2 ?
245 @{$z2->polar} : (abs($z2), $z2 >= 0 ? 0 : pi);
66730be0 246 unless (defined $regular) {
247 $z1->set_polar([$r1 * $r2, $t1 + $t2]);
248 return $z1;
249 }
250 return (ref $z1)->emake($r1 * $r2, $t1 + $t2);
251}
252
253#
0c721ce2 254# divbyzero
255#
256# Die on division by zero.
257#
258sub divbyzero {
5cd24f17 259 my $mess = "$_[0]: Division by zero.\n";
260
261 if (defined $_[1]) {
262 $mess .= "(Because in the definition of $_[0], the divisor ";
263 $mess .= "$_[1] " unless ($_[1] eq '0');
264 $mess .= "is 0)\n";
265 }
266
0c721ce2 267 my @up = caller(1);
5cd24f17 268
269 $mess .= "Died at $up[1] line $up[2].\n";
270
271 die $mess;
0c721ce2 272}
273
274#
66730be0 275# (divide)
276#
277# Computes z1/z2.
278#
279sub divide {
280 my ($z1, $z2, $inverted) = @_;
281 my ($r1, $t1) = @{$z1->polar};
0c721ce2 282 my ($r2, $t2) = ref $z2 ?
283 @{$z2->polar} : (abs($z2), $z2 >= 0 ? 0 : pi);
66730be0 284 unless (defined $inverted) {
0c721ce2 285 divbyzero "$z1/0" if ($r2 == 0);
66730be0 286 $z1->set_polar([$r1 / $r2, $t1 - $t2]);
287 return $z1;
288 }
0c721ce2 289 if ($inverted) {
290 divbyzero "$z2/0" if ($r1 == 0);
291 return (ref $z1)->emake($r2 / $r1, $t2 - $t1);
292 } else {
293 divbyzero "$z1/0" if ($r2 == 0);
294 return (ref $z1)->emake($r1 / $r2, $t1 - $t2);
295 }
66730be0 296}
297
298#
299# (power)
300#
301# Computes z1**z2 = exp(z2 * log z1)).
302#
303sub power {
304 my ($z1, $z2, $inverted) = @_;
305 return exp($z1 * log $z2) if defined $inverted && $inverted;
306 return exp($z2 * log $z1);
307}
308
309#
310# (spaceship)
311#
312# Computes z1 <=> z2.
313# Sorts on the real part first, then on the imaginary part. Thus 2-4i > 3+8i.
314#
315sub spaceship {
316 my ($z1, $z2, $inverted) = @_;
5cd24f17 317 my ($re1, $im1) = ref $z1 ? @{$z1->cartesian} : ($z1, 0);
318 my ($re2, $im2) = ref $z2 ? @{$z2->cartesian} : ($z2, 0);
66730be0 319 my $sgn = $inverted ? -1 : 1;
320 return $sgn * ($re1 <=> $re2) if $re1 != $re2;
321 return $sgn * ($im1 <=> $im2);
322}
323
324#
325# (negate)
326#
327# Computes -z.
328#
329sub negate {
330 my ($z) = @_;
331 if ($z->{c_dirty}) {
332 my ($r, $t) = @{$z->polar};
333 return (ref $z)->emake($r, pi + $t);
334 }
335 my ($re, $im) = @{$z->cartesian};
336 return (ref $z)->make(-$re, -$im);
337}
338
339#
340# (conjugate)
341#
342# Compute complex's conjugate.
343#
344sub conjugate {
345 my ($z) = @_;
346 if ($z->{c_dirty}) {
347 my ($r, $t) = @{$z->polar};
348 return (ref $z)->emake($r, -$t);
349 }
350 my ($re, $im) = @{$z->cartesian};
351 return (ref $z)->make($re, -$im);
352}
353
354#
355# (abs)
356#
357# Compute complex's norm (rho).
358#
359sub abs {
360 my ($z) = @_;
0c721ce2 361 return abs($z) unless ref $z;
66730be0 362 my ($r, $t) = @{$z->polar};
363 return abs($r);
364}
365
366#
367# arg
368#
369# Compute complex's argument (theta).
370#
371sub arg {
372 my ($z) = @_;
0c721ce2 373 return ($z < 0 ? pi : 0) unless ref $z;
66730be0 374 my ($r, $t) = @{$z->polar};
375 return $t;
376}
377
378#
379# (sqrt)
380#
0c721ce2 381# Compute sqrt(z).
66730be0 382#
383sub sqrt {
384 my ($z) = @_;
0c721ce2 385 $z = cplx($z, 0) unless ref $z;
66730be0 386 my ($r, $t) = @{$z->polar};
387 return (ref $z)->emake(sqrt($r), $t/2);
388}
389
390#
391# cbrt
392#
0c721ce2 393# Compute cbrt(z) (cubic root).
66730be0 394#
395sub cbrt {
396 my ($z) = @_;
0c721ce2 397 return cplx($z, 0) ** (1/3) unless ref $z;
66730be0 398 my ($r, $t) = @{$z->polar};
399 return (ref $z)->emake($r**(1/3), $t/3);
400}
401
402#
403# root
404#
405# Computes all nth root for z, returning an array whose size is n.
406# `n' must be a positive integer.
407#
408# The roots are given by (for k = 0..n-1):
409#
410# z^(1/n) = r^(1/n) (cos ((t+2 k pi)/n) + i sin ((t+2 k pi)/n))
411#
412sub root {
413 my ($z, $n) = @_;
414 $n = int($n + 0.5);
415 return undef unless $n > 0;
416 my ($r, $t) = ref $z ? @{$z->polar} : (abs($z), $z >= 0 ? 0 : pi);
417 my @root;
418 my $k;
419 my $theta_inc = 2 * pi / $n;
420 my $rho = $r ** (1/$n);
421 my $theta;
422 my $complex = ref($z) || $package;
423 for ($k = 0, $theta = $t / $n; $k < $n; $k++, $theta += $theta_inc) {
424 push(@root, $complex->emake($rho, $theta));
a0d0e21e 425 }
66730be0 426 return @root;
a0d0e21e 427}
428
66730be0 429#
430# Re
431#
432# Return Re(z).
433#
a0d0e21e 434sub Re {
66730be0 435 my ($z) = @_;
436 return $z unless ref $z;
437 my ($re, $im) = @{$z->cartesian};
438 return $re;
a0d0e21e 439}
440
66730be0 441#
442# Im
443#
444# Return Im(z).
445#
a0d0e21e 446sub Im {
66730be0 447 my ($z) = @_;
448 return 0 unless ref $z;
449 my ($re, $im) = @{$z->cartesian};
450 return $im;
a0d0e21e 451}
452
66730be0 453#
454# (exp)
455#
456# Computes exp(z).
457#
458sub exp {
459 my ($z) = @_;
0c721ce2 460 $z = cplx($z, 0) unless ref $z;
66730be0 461 my ($x, $y) = @{$z->cartesian};
462 return (ref $z)->emake(exp($x), $y);
463}
464
465#
466# (log)
467#
468# Compute log(z).
469#
470sub log {
471 my ($z) = @_;
0c721ce2 472 $z = cplx($z, 0) unless ref $z;
0c721ce2 473 my ($x, $y) = @{$z->cartesian};
5cd24f17 474 my ($r, $t) = @{$z->polar};
0c721ce2 475 $t -= 2 * pi if ($t > pi() and $x < 0);
476 $t += 2 * pi if ($t < -pi() and $x < 0);
66730be0 477 return (ref $z)->make(log($r), $t);
478}
479
480#
0c721ce2 481# ln
482#
483# Alias for log().
484#
485sub ln { Math::Complex::log(@_) }
486
487#
66730be0 488# log10
489#
490# Compute log10(z).
491#
5cd24f17 492
66730be0 493sub log10 {
494 my ($z) = @_;
5cd24f17 495
496 return log(cplx($z, 0)) * log10inv unless ref $z;
66730be0 497 my ($r, $t) = @{$z->polar};
5cd24f17 498 return (ref $z)->make(log($r) * log10inv, $t * log10inv);
66730be0 499}
500
501#
502# logn
503#
504# Compute logn(z,n) = log(z) / log(n)
505#
506sub logn {
507 my ($z, $n) = @_;
0c721ce2 508 $z = cplx($z, 0) unless ref $z;
66730be0 509 my $logn = $logn{$n};
510 $logn = $logn{$n} = log($n) unless defined $logn; # Cache log(n)
0c721ce2 511 return log($z) / $logn;
66730be0 512}
513
514#
515# (cos)
516#
517# Compute cos(z) = (exp(iz) + exp(-iz))/2.
518#
519sub cos {
520 my ($z) = @_;
5cd24f17 521 $z = cplx($z, 0) unless ref $z;
66730be0 522 my ($x, $y) = @{$z->cartesian};
523 my $ey = exp($y);
524 my $ey_1 = 1 / $ey;
0c721ce2 525 return (ref $z)->make(cos($x) * ($ey + $ey_1)/2,
526 sin($x) * ($ey_1 - $ey)/2);
66730be0 527}
528
529#
530# (sin)
531#
532# Compute sin(z) = (exp(iz) - exp(-iz))/2.
533#
534sub sin {
535 my ($z) = @_;
5cd24f17 536 $z = cplx($z, 0) unless ref $z;
66730be0 537 my ($x, $y) = @{$z->cartesian};
538 my $ey = exp($y);
539 my $ey_1 = 1 / $ey;
0c721ce2 540 return (ref $z)->make(sin($x) * ($ey + $ey_1)/2,
541 cos($x) * ($ey - $ey_1)/2);
66730be0 542}
543
544#
545# tan
546#
547# Compute tan(z) = sin(z) / cos(z).
548#
549sub tan {
550 my ($z) = @_;
0c721ce2 551 my $cz = cos($z);
552 divbyzero "tan($z)", "cos($z)" if ($cz == 0);
553 return sin($z) / $cz;
66730be0 554}
555
556#
0c721ce2 557# sec
558#
559# Computes the secant sec(z) = 1 / cos(z).
560#
561sub sec {
562 my ($z) = @_;
563 my $cz = cos($z);
564 divbyzero "sec($z)", "cos($z)" if ($cz == 0);
565 return 1 / $cz;
566}
567
568#
569# csc
570#
571# Computes the cosecant csc(z) = 1 / sin(z).
572#
573sub csc {
574 my ($z) = @_;
575 my $sz = sin($z);
576 divbyzero "csc($z)", "sin($z)" if ($sz == 0);
577 return 1 / $sz;
578}
579
66730be0 580#
0c721ce2 581# cosec
66730be0 582#
0c721ce2 583# Alias for csc().
584#
585sub cosec { Math::Complex::csc(@_) }
586
587#
588# cot
589#
590# Computes cot(z) = 1 / tan(z).
591#
592sub cot {
66730be0 593 my ($z) = @_;
0c721ce2 594 my $sz = sin($z);
595 divbyzero "cot($z)", "sin($z)" if ($sz == 0);
596 return cos($z) / $sz;
66730be0 597}
598
599#
0c721ce2 600# cotan
601#
602# Alias for cot().
603#
604sub cotan { Math::Complex::cot(@_) }
605
606#
66730be0 607# acos
608#
609# Computes the arc cosine acos(z) = -i log(z + sqrt(z*z-1)).
610#
611sub acos {
612 my ($z) = @_;
0c721ce2 613 $z = cplx($z, 0) unless ref $z;
614 return ~i * log($z + (Re($z) * Im($z) > 0 ? 1 : -1) * sqrt($z*$z - 1));
66730be0 615}
616
617#
618# asin
619#
620# Computes the arc sine asin(z) = -i log(iz + sqrt(1-z*z)).
621#
622sub asin {
623 my ($z) = @_;
0c721ce2 624 $z = cplx($z, 0) unless ref $z;
625 return ~i * log(i * $z + sqrt(1 - $z*$z));
66730be0 626}
627
628#
629# atan
630#
0c721ce2 631# Computes the arc tangent atan(z) = i/2 log((i+z) / (i-z)).
66730be0 632#
633sub atan {
634 my ($z) = @_;
5cd24f17 635 $z = cplx($z, 0) unless ref $z;
0c721ce2 636 divbyzero "atan($z)", "i - $z" if ($z == i);
637 return i/2*log((i + $z) / (i - $z));
a0d0e21e 638}
639
66730be0 640#
0c721ce2 641# asec
642#
643# Computes the arc secant asec(z) = acos(1 / z).
644#
645sub asec {
646 my ($z) = @_;
5cd24f17 647 divbyzero "asec($z)", $z if ($z == 0);
0c721ce2 648 return acos(1 / $z);
649}
650
651#
5cd24f17 652# acsc
0c721ce2 653#
654# Computes the arc cosecant sec(z) = asin(1 / z).
655#
5cd24f17 656sub acsc {
0c721ce2 657 my ($z) = @_;
5cd24f17 658 divbyzero "acsc($z)", $z if ($z == 0);
0c721ce2 659 return asin(1 / $z);
660}
661
662#
5cd24f17 663# acosec
66730be0 664#
5cd24f17 665# Alias for acsc().
0c721ce2 666#
5cd24f17 667sub acosec { Math::Complex::acsc(@_) }
0c721ce2 668
66730be0 669#
0c721ce2 670# acot
671#
672# Computes the arc cotangent acot(z) = -i/2 log((i+z) / (z-i))
673#
674sub acot {
66730be0 675 my ($z) = @_;
5cd24f17 676 $z = cplx($z, 0) unless ref $z;
0c721ce2 677 divbyzero "acot($z)", "$z - i" if ($z == i);
66730be0 678 return i/-2 * log((i + $z) / ($z - i));
679}
680
681#
0c721ce2 682# acotan
683#
684# Alias for acot().
685#
686sub acotan { Math::Complex::acot(@_) }
687
688#
66730be0 689# cosh
690#
691# Computes the hyperbolic cosine cosh(z) = (exp(z) + exp(-z))/2.
692#
693sub cosh {
694 my ($z) = @_;
5cd24f17 695 my ($x, $y) = ref $z ? @{$z->cartesian} : ($z, 0);
66730be0 696 my $ex = exp($x);
697 my $ex_1 = 1 / $ex;
698 return ($ex + $ex_1)/2 unless ref $z;
0c721ce2 699 return (ref $z)->make(cos($y) * ($ex + $ex_1)/2,
700 sin($y) * ($ex - $ex_1)/2);
66730be0 701}
702
703#
704# sinh
705#
706# Computes the hyperbolic sine sinh(z) = (exp(z) - exp(-z))/2.
707#
708sub sinh {
709 my ($z) = @_;
5cd24f17 710 my ($x, $y) = ref $z ? @{$z->cartesian} : ($z, 0);
66730be0 711 my $ex = exp($x);
712 my $ex_1 = 1 / $ex;
713 return ($ex - $ex_1)/2 unless ref $z;
0c721ce2 714 return (ref $z)->make(cos($y) * ($ex - $ex_1)/2,
715 sin($y) * ($ex + $ex_1)/2);
66730be0 716}
717
718#
719# tanh
720#
721# Computes the hyperbolic tangent tanh(z) = sinh(z) / cosh(z).
722#
723sub tanh {
724 my ($z) = @_;
0c721ce2 725 my $cz = cosh($z);
726 divbyzero "tanh($z)", "cosh($z)" if ($cz == 0);
727 return sinh($z) / $cz;
66730be0 728}
729
730#
0c721ce2 731# sech
732#
733# Computes the hyperbolic secant sech(z) = 1 / cosh(z).
734#
735sub sech {
736 my ($z) = @_;
737 my $cz = cosh($z);
738 divbyzero "sech($z)", "cosh($z)" if ($cz == 0);
739 return 1 / $cz;
740}
741
742#
743# csch
744#
745# Computes the hyperbolic cosecant csch(z) = 1 / sinh(z).
66730be0 746#
0c721ce2 747sub csch {
748 my ($z) = @_;
749 my $sz = sinh($z);
750 divbyzero "csch($z)", "sinh($z)" if ($sz == 0);
751 return 1 / $sz;
752}
753
754#
755# cosech
756#
757# Alias for csch().
758#
759sub cosech { Math::Complex::csch(@_) }
760
66730be0 761#
0c721ce2 762# coth
763#
764# Computes the hyperbolic cotangent coth(z) = cosh(z) / sinh(z).
765#
766sub coth {
66730be0 767 my ($z) = @_;
0c721ce2 768 my $sz = sinh($z);
769 divbyzero "coth($z)", "sinh($z)" if ($sz == 0);
770 return cosh($z) / $sz;
66730be0 771}
772
773#
0c721ce2 774# cotanh
775#
776# Alias for coth().
777#
778sub cotanh { Math::Complex::coth(@_) }
779
780#
66730be0 781# acosh
782#
783# Computes the arc hyperbolic cosine acosh(z) = log(z + sqrt(z*z-1)).
784#
785sub acosh {
786 my ($z) = @_;
5cd24f17 787 $z = cplx($z, 0) unless ref $z;
0c721ce2 788 return log($z + sqrt($z*$z - 1));
66730be0 789}
790
791#
792# asinh
793#
794# Computes the arc hyperbolic sine asinh(z) = log(z + sqrt(z*z-1))
795#
796sub asinh {
797 my ($z) = @_;
5cd24f17 798 $z = cplx($z, 0) unless ref $z;
0c721ce2 799 return log($z + sqrt($z*$z + 1));
66730be0 800}
801
802#
803# atanh
804#
805# Computes the arc hyperbolic tangent atanh(z) = 1/2 log((1+z) / (1-z)).
806#
807sub atanh {
808 my ($z) = @_;
0c721ce2 809 divbyzero 'atanh(1)', "1 - $z" if ($z == 1);
5cd24f17 810 $z = cplx($z, 0) unless ref $z;
66730be0 811 my $cz = (1 + $z) / (1 - $z);
66730be0 812 return log($cz) / 2;
813}
814
815#
0c721ce2 816# asech
817#
818# Computes the hyperbolic arc secant asech(z) = acosh(1 / z).
819#
820sub asech {
821 my ($z) = @_;
822 divbyzero 'asech(0)', $z if ($z == 0);
823 return acosh(1 / $z);
824}
825
826#
827# acsch
66730be0 828#
0c721ce2 829# Computes the hyperbolic arc cosecant acsch(z) = asinh(1 / z).
66730be0 830#
0c721ce2 831sub acsch {
66730be0 832 my ($z) = @_;
0c721ce2 833 divbyzero 'acsch(0)', $z if ($z == 0);
834 return asinh(1 / $z);
835}
836
837#
838# acosech
839#
840# Alias for acosh().
841#
842sub acosech { Math::Complex::acsch(@_) }
843
844#
845# acoth
846#
847# Computes the arc hyperbolic cotangent acoth(z) = 1/2 log((1+z) / (z-1)).
848#
849sub acoth {
850 my ($z) = @_;
0c721ce2 851 divbyzero 'acoth(1)', "$z - 1" if ($z == 1);
5cd24f17 852 $z = cplx($z, 0) unless ref $z;
66730be0 853 my $cz = (1 + $z) / ($z - 1);
66730be0 854 return log($cz) / 2;
855}
856
857#
0c721ce2 858# acotanh
859#
860# Alias for acot().
861#
862sub acotanh { Math::Complex::acoth(@_) }
863
864#
66730be0 865# (atan2)
866#
867# Compute atan(z1/z2).
868#
869sub atan2 {
870 my ($z1, $z2, $inverted) = @_;
5cd24f17 871 my ($re1, $im1) = ref $z1 ? @{$z1->cartesian} : ($z1, 0);
872 my ($re2, $im2) = ref $z2 ? @{$z2->cartesian} : ($z2, 0);
66730be0 873 my $tan;
874 if (defined $inverted && $inverted) { # atan(z2/z1)
875 return pi * ($re2 > 0 ? 1 : -1) if $re1 == 0 && $im1 == 0;
876 $tan = $z2 / $z1;
877 } else {
878 return pi * ($re1 > 0 ? 1 : -1) if $re2 == 0 && $im2 == 0;
879 $tan = $z1 / $z2;
880 }
881 return atan($tan);
882}
883
884#
885# display_format
886# ->display_format
887#
888# Set (fetch if no argument) display format for all complex numbers that
889# don't happen to have overrriden it via ->display_format
890#
891# When called as a method, this actually sets the display format for
892# the current object.
893#
894# Valid object formats are 'c' and 'p' for cartesian and polar. The first
895# letter is used actually, so the type can be fully spelled out for clarity.
896#
897sub display_format {
898 my $self = shift;
899 my $format = undef;
900
901 if (ref $self) { # Called as a method
902 $format = shift;
0c721ce2 903 } else { # Regular procedure call
66730be0 904 $format = $self;
905 undef $self;
906 }
907
908 if (defined $self) {
909 return defined $self->{display} ? $self->{display} : $display
910 unless defined $format;
911 return $self->{display} = $format;
912 }
913
914 return $display unless defined $format;
915 return $display = $format;
916}
917
918#
919# (stringify)
920#
921# Show nicely formatted complex number under its cartesian or polar form,
922# depending on the current display format:
923#
924# . If a specific display format has been recorded for this object, use it.
925# . Otherwise, use the generic current default for all complex numbers,
926# which is a package global variable.
927#
a0d0e21e 928sub stringify {
66730be0 929 my ($z) = shift;
930 my $format;
931
932 $format = $display;
933 $format = $z->{display} if defined $z->{display};
934
935 return $z->stringify_polar if $format =~ /^p/i;
936 return $z->stringify_cartesian;
937}
938
939#
940# ->stringify_cartesian
941#
942# Stringify as a cartesian representation 'a+bi'.
943#
944sub stringify_cartesian {
945 my $z = shift;
946 my ($x, $y) = @{$z->cartesian};
947 my ($re, $im);
948
55497cff 949 $x = int($x + ($x < 0 ? -1 : 1) * 1e-14)
950 if int(abs($x)) != int(abs($x) + 1e-14);
951 $y = int($y + ($y < 0 ? -1 : 1) * 1e-14)
952 if int(abs($y)) != int(abs($y) + 1e-14);
953
66730be0 954 $re = "$x" if abs($x) >= 1e-14;
955 if ($y == 1) { $im = 'i' }
956 elsif ($y == -1) { $im = '-i' }
40da2db3 957 elsif (abs($y) >= 1e-14) { $im = $y . "i" }
66730be0 958
0c721ce2 959 my $str = '';
66730be0 960 $str = $re if defined $re;
961 $str .= "+$im" if defined $im;
962 $str =~ s/\+-/-/;
963 $str =~ s/^\+//;
964 $str = '0' unless $str;
965
966 return $str;
967}
968
969#
970# ->stringify_polar
971#
972# Stringify as a polar representation '[r,t]'.
973#
974sub stringify_polar {
975 my $z = shift;
976 my ($r, $t) = @{$z->polar};
977 my $theta;
0c721ce2 978 my $eps = 1e-14;
66730be0 979
0c721ce2 980 return '[0,0]' if $r <= $eps;
a0d0e21e 981
66730be0 982 my $tpi = 2 * pi;
983 my $nt = $t / $tpi;
984 $nt = ($nt - int($nt)) * $tpi;
985 $nt += $tpi if $nt < 0; # Range [0, 2pi]
a0d0e21e 986
0c721ce2 987 if (abs($nt) <= $eps) { $theta = 0 }
988 elsif (abs(pi-$nt) <= $eps) { $theta = 'pi' }
66730be0 989
55497cff 990 if (defined $theta) {
0c721ce2 991 $r = int($r + ($r < 0 ? -1 : 1) * $eps)
992 if int(abs($r)) != int(abs($r) + $eps);
993 $theta = int($theta + ($theta < 0 ? -1 : 1) * $eps)
994 if ($theta ne 'pi' and
995 int(abs($theta)) != int(abs($theta) + $eps));
55497cff 996 return "\[$r,$theta\]";
997 }
66730be0 998
999 #
1000 # Okay, number is not a real. Try to identify pi/n and friends...
1001 #
1002
1003 $nt -= $tpi if $nt > pi;
1004 my ($n, $k, $kpi);
1005
1006 for ($k = 1, $kpi = pi; $k < 10; $k++, $kpi += pi) {
1007 $n = int($kpi / $nt + ($nt > 0 ? 1 : -1) * 0.5);
0c721ce2 1008 if (abs($kpi/$n - $nt) <= $eps) {
1009 $theta = ($nt < 0 ? '-':'').
1010 ($k == 1 ? 'pi':"${k}pi").'/'.abs($n);
66730be0 1011 last;
1012 }
1013 }
1014
1015 $theta = $nt unless defined $theta;
1016
0c721ce2 1017 $r = int($r + ($r < 0 ? -1 : 1) * $eps)
1018 if int(abs($r)) != int(abs($r) + $eps);
1019 $theta = int($theta + ($theta < 0 ? -1 : 1) * $eps)
1020 if ($theta !~ m(^-?\d*pi/\d+$) and
1021 int(abs($theta)) != int(abs($theta) + $eps));
55497cff 1022
66730be0 1023 return "\[$r,$theta\]";
a0d0e21e 1024}
a5f75d66 1025
10261;
1027__END__
1028
1029=head1 NAME
1030
66730be0 1031Math::Complex - complex numbers and associated mathematical functions
a5f75d66 1032
1033=head1 SYNOPSIS
1034
66730be0 1035 use Math::Complex;
5aabfad6 1036
66730be0 1037 $z = Math::Complex->make(5, 6);
1038 $t = 4 - 3*i + $z;
1039 $j = cplxe(1, 2*pi/3);
a5f75d66 1040
1041=head1 DESCRIPTION
1042
66730be0 1043This package lets you create and manipulate complex numbers. By default,
1044I<Perl> limits itself to real numbers, but an extra C<use> statement brings
1045full complex support, along with a full set of mathematical functions
1046typically associated with and/or extended to complex numbers.
1047
1048If you wonder what complex numbers are, they were invented to be able to solve
1049the following equation:
1050
1051 x*x = -1
1052
1053and by definition, the solution is noted I<i> (engineers use I<j> instead since
1054I<i> usually denotes an intensity, but the name does not matter). The number
1055I<i> is a pure I<imaginary> number.
1056
1057The arithmetics with pure imaginary numbers works just like you would expect
1058it with real numbers... you just have to remember that
1059
1060 i*i = -1
1061
1062so you have:
1063
1064 5i + 7i = i * (5 + 7) = 12i
1065 4i - 3i = i * (4 - 3) = i
1066 4i * 2i = -8
1067 6i / 2i = 3
1068 1 / i = -i
1069
1070Complex numbers are numbers that have both a real part and an imaginary
1071part, and are usually noted:
1072
1073 a + bi
1074
1075where C<a> is the I<real> part and C<b> is the I<imaginary> part. The
1076arithmetic with complex numbers is straightforward. You have to
1077keep track of the real and the imaginary parts, but otherwise the
1078rules used for real numbers just apply:
1079
1080 (4 + 3i) + (5 - 2i) = (4 + 5) + i(3 - 2) = 9 + i
1081 (2 + i) * (4 - i) = 2*4 + 4i -2i -i*i = 8 + 2i + 1 = 9 + 2i
1082
1083A graphical representation of complex numbers is possible in a plane
1084(also called the I<complex plane>, but it's really a 2D plane).
1085The number
1086
1087 z = a + bi
1088
1089is the point whose coordinates are (a, b). Actually, it would
1090be the vector originating from (0, 0) to (a, b). It follows that the addition
1091of two complex numbers is a vectorial addition.
1092
1093Since there is a bijection between a point in the 2D plane and a complex
1094number (i.e. the mapping is unique and reciprocal), a complex number
1095can also be uniquely identified with polar coordinates:
1096
1097 [rho, theta]
1098
1099where C<rho> is the distance to the origin, and C<theta> the angle between
1100the vector and the I<x> axis. There is a notation for this using the
1101exponential form, which is:
1102
1103 rho * exp(i * theta)
1104
1105where I<i> is the famous imaginary number introduced above. Conversion
1106between this form and the cartesian form C<a + bi> is immediate:
1107
1108 a = rho * cos(theta)
1109 b = rho * sin(theta)
1110
1111which is also expressed by this formula:
1112
1113 z = rho * exp(i * theta) = rho * (cos theta + i * sin theta)
1114
1115In other words, it's the projection of the vector onto the I<x> and I<y>
1116axes. Mathematicians call I<rho> the I<norm> or I<modulus> and I<theta>
1117the I<argument> of the complex number. The I<norm> of C<z> will be
1118noted C<abs(z)>.
1119
1120The polar notation (also known as the trigonometric
1121representation) is much more handy for performing multiplications and
1122divisions of complex numbers, whilst the cartesian notation is better
1123suited for additions and substractions. Real numbers are on the I<x>
1124axis, and therefore I<theta> is zero.
1125
1126All the common operations that can be performed on a real number have
1127been defined to work on complex numbers as well, and are merely
1128I<extensions> of the operations defined on real numbers. This means
1129they keep their natural meaning when there is no imaginary part, provided
1130the number is within their definition set.
1131
1132For instance, the C<sqrt> routine which computes the square root of
1133its argument is only defined for positive real numbers and yields a
1134positive real number (it is an application from B<R+> to B<R+>).
1135If we allow it to return a complex number, then it can be extended to
1136negative real numbers to become an application from B<R> to B<C> (the
1137set of complex numbers):
1138
1139 sqrt(x) = x >= 0 ? sqrt(x) : sqrt(-x)*i
1140
1141It can also be extended to be an application from B<C> to B<C>,
1142whilst its restriction to B<R> behaves as defined above by using
1143the following definition:
1144
1145 sqrt(z = [r,t]) = sqrt(r) * exp(i * t/2)
1146
1147Indeed, a negative real number can be noted C<[x,pi]>
1148(the modulus I<x> is always positive, so C<[x,pi]> is really C<-x>, a
1149negative number)
1150and the above definition states that
1151
1152 sqrt([x,pi]) = sqrt(x) * exp(i*pi/2) = [sqrt(x),pi/2] = sqrt(x)*i
1153
1154which is exactly what we had defined for negative real numbers above.
a5f75d66 1155
66730be0 1156All the common mathematical functions defined on real numbers that
1157are extended to complex numbers share that same property of working
1158I<as usual> when the imaginary part is zero (otherwise, it would not
1159be called an extension, would it?).
a5f75d66 1160
66730be0 1161A I<new> operation possible on a complex number that is
1162the identity for real numbers is called the I<conjugate>, and is noted
1163with an horizontal bar above the number, or C<~z> here.
a5f75d66 1164
66730be0 1165 z = a + bi
1166 ~z = a - bi
a5f75d66 1167
66730be0 1168Simple... Now look:
a5f75d66 1169
66730be0 1170 z * ~z = (a + bi) * (a - bi) = a*a + b*b
a5f75d66 1171
66730be0 1172We saw that the norm of C<z> was noted C<abs(z)> and was defined as the
1173distance to the origin, also known as:
a5f75d66 1174
66730be0 1175 rho = abs(z) = sqrt(a*a + b*b)
a5f75d66 1176
66730be0 1177so
1178
1179 z * ~z = abs(z) ** 2
1180
1181If z is a pure real number (i.e. C<b == 0>), then the above yields:
1182
1183 a * a = abs(a) ** 2
1184
1185which is true (C<abs> has the regular meaning for real number, i.e. stands
1186for the absolute value). This example explains why the norm of C<z> is
1187noted C<abs(z)>: it extends the C<abs> function to complex numbers, yet
1188is the regular C<abs> we know when the complex number actually has no
1189imaginary part... This justifies I<a posteriori> our use of the C<abs>
1190notation for the norm.
1191
1192=head1 OPERATIONS
1193
1194Given the following notations:
1195
1196 z1 = a + bi = r1 * exp(i * t1)
1197 z2 = c + di = r2 * exp(i * t2)
1198 z = <any complex or real number>
1199
1200the following (overloaded) operations are supported on complex numbers:
1201
1202 z1 + z2 = (a + c) + i(b + d)
1203 z1 - z2 = (a - c) + i(b - d)
1204 z1 * z2 = (r1 * r2) * exp(i * (t1 + t2))
1205 z1 / z2 = (r1 / r2) * exp(i * (t1 - t2))
1206 z1 ** z2 = exp(z2 * log z1)
1207 ~z1 = a - bi
1208 abs(z1) = r1 = sqrt(a*a + b*b)
1209 sqrt(z1) = sqrt(r1) * exp(i * t1/2)
1210 exp(z1) = exp(a) * exp(i * b)
1211 log(z1) = log(r1) + i*t1
1212 sin(z1) = 1/2i (exp(i * z1) - exp(-i * z1))
1213 cos(z1) = 1/2 (exp(i * z1) + exp(-i * z1))
1214 abs(z1) = r1
1215 atan2(z1, z2) = atan(z1/z2)
1216
1217The following extra operations are supported on both real and complex
1218numbers:
1219
1220 Re(z) = a
1221 Im(z) = b
1222 arg(z) = t
1223
1224 cbrt(z) = z ** (1/3)
1225 log10(z) = log(z) / log(10)
1226 logn(z, n) = log(z) / log(n)
1227
1228 tan(z) = sin(z) / cos(z)
0c721ce2 1229
5aabfad6 1230 csc(z) = 1 / sin(z)
1231 sec(z) = 1 / cos(z)
0c721ce2 1232 cot(z) = 1 / tan(z)
66730be0 1233
1234 asin(z) = -i * log(i*z + sqrt(1-z*z))
1235 acos(z) = -i * log(z + sqrt(z*z-1))
1236 atan(z) = i/2 * log((i+z) / (i-z))
0c721ce2 1237
5aabfad6 1238 acsc(z) = asin(1 / z)
1239 asec(z) = acos(1 / z)
0c721ce2 1240 acot(z) = -i/2 * log((i+z) / (z-i))
66730be0 1241
1242 sinh(z) = 1/2 (exp(z) - exp(-z))
1243 cosh(z) = 1/2 (exp(z) + exp(-z))
0c721ce2 1244 tanh(z) = sinh(z) / cosh(z) = (exp(z) - exp(-z)) / (exp(z) + exp(-z))
1245
5aabfad6 1246 csch(z) = 1 / sinh(z)
1247 sech(z) = 1 / cosh(z)
0c721ce2 1248 coth(z) = 1 / tanh(z)
66730be0 1249
1250 asinh(z) = log(z + sqrt(z*z+1))
1251 acosh(z) = log(z + sqrt(z*z-1))
1252 atanh(z) = 1/2 * log((1+z) / (1-z))
66730be0 1253
5aabfad6 1254 acsch(z) = asinh(1 / z)
1255 asech(z) = acosh(1 / z)
0c721ce2 1256 acoth(z) = atanh(1 / z) = 1/2 * log((1+z) / (z-1))
1257
1258I<log>, I<csc>, I<cot>, I<acsc>, I<acot>, I<csch>, I<coth>,
1259I<acosech>, I<acotanh>, have aliases I<ln>, I<cosec>, I<cotan>,
1260I<acosec>, I<acotan>, I<cosech>, I<cotanh>, I<acosech>, I<acotanh>,
1261respectively.
1262
1263The I<root> function is available to compute all the I<n>
66730be0 1264roots of some complex, where I<n> is a strictly positive integer.
1265There are exactly I<n> such roots, returned as a list. Getting the
1266number mathematicians call C<j> such that:
1267
1268 1 + j + j*j = 0;
1269
1270is a simple matter of writing:
1271
1272 $j = ((root(1, 3))[1];
1273
1274The I<k>th root for C<z = [r,t]> is given by:
1275
1276 (root(z, n))[k] = r**(1/n) * exp(i * (t + 2*k*pi)/n)
1277
0c721ce2 1278The I<spaceship> comparison operator is also defined. In order to
1279ensure its restriction to real numbers is conform to what you would
1280expect, the comparison is run on the real part of the complex number
1281first, and imaginary parts are compared only when the real parts
1282match.
66730be0 1283
1284=head1 CREATION
1285
1286To create a complex number, use either:
1287
1288 $z = Math::Complex->make(3, 4);
1289 $z = cplx(3, 4);
1290
1291if you know the cartesian form of the number, or
1292
1293 $z = 3 + 4*i;
1294
1295if you like. To create a number using the trigonometric form, use either:
1296
1297 $z = Math::Complex->emake(5, pi/3);
1298 $x = cplxe(5, pi/3);
1299
0c721ce2 1300instead. The first argument is the modulus, the second is the angle
1301(in radians, the full circle is 2*pi). (Mnmemonic: C<e> is used as a
1302notation for complex numbers in the trigonometric form).
66730be0 1303
1304It is possible to write:
1305
1306 $x = cplxe(-3, pi/4);
1307
1308but that will be silently converted into C<[3,-3pi/4]>, since the modulus
1309must be positive (it represents the distance to the origin in the complex
1310plane).
1311
1312=head1 STRINGIFICATION
1313
1314When printed, a complex number is usually shown under its cartesian
1315form I<a+bi>, but there are legitimate cases where the polar format
1316I<[r,t]> is more appropriate.
1317
1318By calling the routine C<Math::Complex::display_format> and supplying either
1319C<"polar"> or C<"cartesian">, you override the default display format,
1320which is C<"cartesian">. Not supplying any argument returns the current
1321setting.
1322
1323This default can be overridden on a per-number basis by calling the
1324C<display_format> method instead. As before, not supplying any argument
1325returns the current display format for this number. Otherwise whatever you
1326specify will be the new display format for I<this> particular number.
1327
1328For instance:
1329
1330 use Math::Complex;
1331
1332 Math::Complex::display_format('polar');
1333 $j = ((root(1, 3))[1];
1334 print "j = $j\n"; # Prints "j = [1,2pi/3]
1335 $j->display_format('cartesian');
1336 print "j = $j\n"; # Prints "j = -0.5+0.866025403784439i"
1337
1338The polar format attempts to emphasize arguments like I<k*pi/n>
1339(where I<n> is a positive integer and I<k> an integer within [-9,+9]).
1340
1341=head1 USAGE
1342
1343Thanks to overloading, the handling of arithmetics with complex numbers
1344is simple and almost transparent.
1345
1346Here are some examples:
1347
1348 use Math::Complex;
1349
1350 $j = cplxe(1, 2*pi/3); # $j ** 3 == 1
1351 print "j = $j, j**3 = ", $j ** 3, "\n";
1352 print "1 + j + j**2 = ", 1 + $j + $j**2, "\n";
1353
1354 $z = -16 + 0*i; # Force it to be a complex
1355 print "sqrt($z) = ", sqrt($z), "\n";
1356
1357 $k = exp(i * 2*pi/3);
1358 print "$j - $k = ", $j - $k, "\n";
a5f75d66 1359
5cd24f17 1360=head1 ERRORS DUE TO DIVISION BY ZERO
5aabfad6 1361
1362The division (/) and the following functions
1363
1364 tan
1365 sec
1366 csc
1367 cot
5cd24f17 1368 asec
1369 acsc
5aabfad6 1370 atan
1371 acot
1372 tanh
1373 sech
1374 csch
1375 coth
1376 atanh
1377 asech
1378 acsch
1379 acoth
1380
1381cannot be computed for all arguments because that would mean dividing
1382by zero. These situations cause fatal runtime errors looking like this
1383
1384 cot(0): Division by zero.
5cd24f17 1385 (Because in the definition of cot(0), the divisor sin(0) is 0)
5aabfad6 1386 Died at ...
1387
5cd24f17 1388For the C<csc>, C<cot>, C<asec>, C<acsc>, C<csch>, C<coth>, C<asech>,
1389C<acsch>, the argument cannot be C<0> (zero). For the C<atanh>,
1390C<acoth>, the argument cannot be C<1> (one). For the C<atan>, C<acot>,
1391the argument cannot be C<i> (the imaginary unit). For the C<tan>,
1392C<sec>, C<tanh>, C<sech>, the argument cannot be I<pi/2 + k * pi>, where
1393I<k> is any integer.
1394
a5f75d66 1395=head1 BUGS
1396
5cd24f17 1397Saying C<use Math::Complex;> exports many mathematical routines in the
1398caller environment and even overrides some (C<sin>, C<cos>, C<sqrt>,
1399C<log>, C<exp>). This is construed as a feature by the Authors,
1400actually... ;-)
66730be0 1401
1402The code is not optimized for speed, although we try to use the cartesian
1403form for addition-like operators and the trigonometric form for all
1404multiplication-like operators.
1405
1406The arg() routine does not ensure the angle is within the range [-pi,+pi]
1407(a side effect caused by multiplication and division using the trigonometric
1408representation).
a5f75d66 1409
66730be0 1410All routines expect to be given real or complex numbers. Don't attempt to
1411use BigFloat, since Perl has currently no rule to disambiguate a '+'
1412operation (for instance) between two overloaded entities.
a5f75d66 1413
0c721ce2 1414=head1 AUTHORS
a5f75d66 1415
0c721ce2 1416 Raphael Manfredi <F<Raphael_Manfredi@grenoble.hp.com>>
1417 Jarkko Hietaniemi <F<jhi@iki.fi>>
5cd24f17 1418
1419=cut
1420
1421# eof