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