Annotation of loncom/xml/LCMathComplex.pm, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>