From 3eac21f49bc763a6c0044b4afbc0c7ece760144f Mon Sep 17 00:00:00 2001
From: markm <markm@FreeBSD.org>
Date: Sat, 16 Mar 2002 20:14:30 +0000
Subject: Vendor import Perl 5.6.1

---
 contrib/perl5/lib/Math/BigFloat.pm |  84 ++++++--
 contrib/perl5/lib/Math/BigInt.pm   |  27 +++
 contrib/perl5/lib/Math/Complex.pm  | 429 +++++++++++++++++++++----------------
 contrib/perl5/lib/Math/Trig.pm     |  43 ++--
 4 files changed, 361 insertions(+), 222 deletions(-)

(limited to 'contrib/perl5/lib/Math')

diff --git a/contrib/perl5/lib/Math/BigFloat.pm b/contrib/perl5/lib/Math/BigFloat.pm
index d8d643c..1eefac2 100644
--- a/contrib/perl5/lib/Math/BigFloat.pm
+++ b/contrib/perl5/lib/Math/BigFloat.pm
@@ -4,6 +4,7 @@ use Math::BigInt;
 
 use Exporter;  # just for use to be happy
 @ISA = (Exporter);
+$VERSION = '0.02';
 
 use overload
 '+'	=>	sub {new Math::BigFloat &fadd},
@@ -12,9 +13,12 @@ use overload
 '<=>'	=>	sub {$_[2]? fcmp($_[1],${$_[0]}) : fcmp(${$_[0]},$_[1])},
 'cmp'	=>	sub {$_[2]? ($_[1] cmp ${$_[0]}) : (${$_[0]} cmp $_[1])},
 '*'	=>	sub {new Math::BigFloat &fmul},
-'/'	=>	sub {new Math::BigFloat 
+'/'	=>	sub {new Math::BigFloat
 		       $_[2]? scalar fdiv($_[1],${$_[0]}) :
 			 scalar fdiv(${$_[0]},$_[1])},
+'%'	=>	sub {new Math::BigFloat
+		       $_[2]? scalar fmod($_[1],${$_[0]}) :
+			 scalar fmod(${$_[0]},$_[1])},
 'neg'	=>	sub {new Math::BigFloat &fneg},
 'abs'	=>	sub {new Math::BigFloat &fabs},
 
@@ -43,12 +47,15 @@ sub stringify {
     my $e = $1;
     my $ln = length($n);
 
-    if ($e > 0) {
-	$n .= "0" x $e . '.';
-    } elsif (abs($e) < $ln) {
-	substr($n, $ln + $e, 0) = '.';
-    } else {
-	$n = '.' . ("0" x (abs($e) - $ln)) . $n;
+    if ( defined $e )
+    {
+        if ($e > 0) {
+        $n .= "0" x $e . '.';
+        } elsif (abs($e) < $ln) {
+        substr($n, $ln + $e, 0) = '.';
+        } else {
+        $n = '.' . ("0" x (abs($e) - $ln)) . $n;
+        }
     }
     $n = "-$n" if $minus;
 
@@ -85,6 +92,7 @@ sub fnorm { #(string) return fnum_str
 # normalize number -- for internal use
 sub norm { #(mantissa, exponent) return fnum_str
     local($_, $exp) = @_;
+	$exp = 0 unless defined $exp;
     if ($_ eq 'NaN') {
 	'NaN';
     } else {
@@ -140,7 +148,7 @@ sub fadd { #(fnum_str, fnum_str) return fnum_str
 
 # subtraction
 sub fsub { #(fnum_str, fnum_str) return fnum_str
-    fadd($_[$[],fneg($_[$[+1]));    
+    fadd($_[$[],fneg($_[$[+1]));
 }
 
 # division
@@ -164,6 +172,27 @@ sub fdiv #(fnum_str, fnum_str[,scale]) return fnum_str
     }
 }
 
+# modular division
+#   args are dividend, divisor
+sub fmod #(fnum_str, fnum_str) return fnum_str
+{
+    local($x,$y) = (fnorm($_[$[]),fnorm($_[$[+1]));
+    if ($x eq 'NaN' || $y eq 'NaN' || $y eq '+0E+0') {
+	'NaN';
+    } else {
+	local($xm,$xe) = split('E',$x);
+	local($ym,$ye) = split('E',$y);
+	if ( $xe < $ye )
+	{
+		$ym .= ('0' x ($ye-$xe));
+	}
+	else
+	{
+		$xm .= ('0' x ($xe-$ye));
+	}
+	&norm(Math::BigInt::bmod($xm,$ym));
+    }
+}
 # round int $q based on fraction $r/$base using $rnd_mode
 sub round { #(int_str, int_str, int_str) return int_str
     local($q,$r,$base) = @_;
@@ -174,12 +203,14 @@ sub round { #(int_str, int_str, int_str) return int_str
     } else {
 	local($cmp) = Math::BigInt::bcmp(Math::BigInt::bmul($r,'+2'),$base);
 	if ( $cmp < 0 ||
-		 ($cmp == 0 &&
-		  ( $rnd_mode eq 'zero'                             ||
+		 ($cmp == 0 &&                                          (
+		   ($rnd_mode eq 'zero'                            ) ||
 		   ($rnd_mode eq '-inf' && (substr($q,$[,1) eq '+')) ||
 		   ($rnd_mode eq '+inf' && (substr($q,$[,1) eq '-')) ||
-		   ($rnd_mode eq 'even' && $q =~ /[24680]$/)        ||
-		   ($rnd_mode eq 'odd'  && $q =~ /[13579]$/)        )) ) {
+		   ($rnd_mode eq 'even' && $q =~ /[24680]$/        ) ||
+		   ($rnd_mode eq 'odd'  && $q =~ /[13579]$/        )    )
+		  )
+		) {
 	    $q;                     # round down
 	} else {
 	    Math::BigInt::badd($q, ((substr($q,$[,1) eq '-') ? '-1' : '+1'));
@@ -199,7 +230,7 @@ sub fround { #(fnum_str, scale) return fnum_str
 	    $x;
 	} else {
 	    &norm(&round(substr($xm,$[,$scale+1),
-			 "+0".substr($xm,$[+$scale+1,1),"+10"),
+			 "+0".substr($xm,$[+$scale+1),"+1"."0" x length(substr($xm,$[+$scale+1))),
 		  $xe+length($xm)-$scale-1);
 	}
     }
@@ -223,15 +254,17 @@ sub ffround { #(fnum_str, scale) return fnum_str
 		# normalized "-0" to &round when rounding -0.006 (for
 		# example), purely so &round won't lose the sign.
 		&norm(&round(substr($xm,$[,1).'0',
-		      "+0".substr($xm,$[+1,1),"+10"), $scale);
+		      "+0".substr($xm,$[+1),
+		      "+1"."0" x length(substr($xm,$[+1))), $scale);
 	    } else {
 		&norm(&round(substr($xm,$[,$xe),
-		      "+0".substr($xm,$[+$xe,1),"+10"), $scale);
+		      "+0".substr($xm,$[+$xe),
+		      "+1"."0" x length(substr($xm,$[+$xe))), $scale);
 	    }
 	}
     }
 }
-    
+
 # compare 2 values returns one of undef, <0, =0, >0
 #   returns undef if either or both input value are not numbers
 sub fcmp #(fnum_str, fnum_str) return cond_code
@@ -244,9 +277,17 @@ sub fcmp #(fnum_str, fnum_str) return cond_code
 	if ($xm eq '+0' || $ym eq '+0') {
 	    return $xm <=> $ym;
 	}
-	ord($y) <=> ord($x)
-	|| ($xe <=> $ye) * (substr($x,$[,1).'1')
-	|| Math::BigInt::cmp($xm,$ym);
+	if ( $xe < $ye )	# adjust the exponents to be equal
+	{
+		$ym .= '0' x ($ye - $xe);
+		$ye = $xe;
+	}
+	elsif ( $ye < $xe )	# same here
+	{
+		$xm .= '0' x ($xe - $ye);
+		$xe = $ye;
+	}
+	return Math::BigInt::cmp($xm,$ym);
     }
 }
 
@@ -286,6 +327,7 @@ Math::BigFloat - Arbitrary length float math package
   $f->fsub(NSTR) return NSTR            subtraction
   $f->fmul(NSTR) return NSTR            multiplication
   $f->fdiv(NSTR[,SCALE]) returns NSTR   division to SCALE places
+  $f->fmod(NSTR) returns NSTR           modular remainder
   $f->fneg() return NSTR                negation
   $f->fabs() return NSTR                absolute value
   $f->fcmp(NSTR) return CODE            compare undef,<0,=0,>0
@@ -313,7 +355,7 @@ have embedded whitespace.
 An input parameter was "Not a Number" or divide by zero or sqrt of
 negative number.
 
-=item Division is computed to 
+=item Division is computed to
 
 C<max($Math::BigFloat::div_scale,length(dividend)+length(divisor))>
 digits by default.
@@ -352,5 +394,5 @@ as follows:
 =head1 AUTHOR
 
 Mark Biggar
-
+Patches by John Peacock Apr 2001
 =cut
diff --git a/contrib/perl5/lib/Math/BigInt.pm b/contrib/perl5/lib/Math/BigInt.pm
index a43969c..066577d 100644
--- a/contrib/perl5/lib/Math/BigInt.pm
+++ b/contrib/perl5/lib/Math/BigInt.pm
@@ -1,4 +1,5 @@
 package Math::BigInt;
+$VERSION='0.01';
 
 use overload
 '+'	=>	sub {new Math::BigInt &badd},
@@ -51,6 +52,11 @@ sub import {
 
 $zero = 0;
 
+# overcome a floating point problem on certain osnames (posix-bc, os390)
+BEGIN {
+    my $x = 100000.0;
+    my $use_mult = int($x*1e-5)*1e5 == $x ? 1 : 0;
+}
 
 # normalize string form of number.   Strip leading zeros.  Strip any
 #   white space and add a sign, if missing.
@@ -227,8 +233,14 @@ sub mul { #(*int_num_array, *int_num_array) return int_num_array
       ($car, $cty) = (0, $[);
       for $y (@y) {
 	$prod = $x * $y + ($prod[$cty] || 0) + $car;
+        if ($use_mult) {
 	$prod[$cty++] =
 	  $prod - ($car = int($prod * 1e-5)) * 1e5;
+        }
+        else {
+	$prod[$cty++] =
+	  $prod - ($car = int($prod / 1e5)) * 1e5;
+        }
       }
       $prod[$cty] += $car if $car;
       $x = shift @prod;
@@ -253,12 +265,22 @@ sub bdiv { #(dividend: num_str, divisor: num_str) return num_str
     if (($dd = int(1e5/($y[$#y]+1))) != 1) {
 	for $x (@x) {
 	    $x = $x * $dd + $car;
+            if ($use_mult) {
 	    $x -= ($car = int($x * 1e-5)) * 1e5;
+            }
+            else {
+	    $x -= ($car = int($x / 1e5)) * 1e5;
+            }
 	}
 	push(@x, $car); $car = 0;
 	for $y (@y) {
 	    $y = $y * $dd + $car;
+            if ($use_mult) {
 	    $y -= ($car = int($y * 1e-5)) * 1e5;
+            }
+            else {
+	    $y -= ($car = int($y / 1e5)) * 1e5;
+            }
 	}
     }
     else {
@@ -275,7 +297,12 @@ sub bdiv { #(dividend: num_str, divisor: num_str) return num_str
 	    ($car, $bar) = (0,0);
 	    for ($y = $[, $x = $#x-$#y+$[-1; $y <= $#y; ++$y,++$x) {
 		$prd = $q * $y[$y] + $car;
+                if ($use_mult) {
 		$prd -= ($car = int($prd * 1e-5)) * 1e5;
+                }
+                else {
+		$prd -= ($car = int($prd / 1e5)) * 1e5;
+                }
 		$x[$x] += 1e5 if ($bar = (($x[$x] -= $prd + $bar) < 0));
 	    }
 	    if ($x[$#x] < $car + $bar) {
diff --git a/contrib/perl5/lib/Math/Complex.pm b/contrib/perl5/lib/Math/Complex.pm
index 1a47f4a..9812513 100644
--- a/contrib/perl5/lib/Math/Complex.pm
+++ b/contrib/perl5/lib/Math/Complex.pm
@@ -5,17 +5,39 @@
 # -- Daniel S. Lewart	Since Sep 1997
 #
 
-require Exporter;
 package Math::Complex;
 
-use 5.005_64;
-use strict;
+our($VERSION, @ISA, @EXPORT, %EXPORT_TAGS, $Inf);
+
+$VERSION = 1.31;
+
+BEGIN {
+    unless ($^O eq 'unicosmk') {
+        my $e = $!;
+	# We do want an arithmetic overflow, Inf INF inf Infinity:.
+        undef $Inf unless eval <<'EOE' and $Inf =~ /^inf(?:inity)?$/i;
+	  local $SIG{FPE} = sub {die};
+	  my $t = CORE::exp 30;
+	  $Inf = CORE::exp $t;
+EOE
+	if (!defined $Inf) {		# Try a different method
+	  undef $Inf unless eval <<'EOE' and $Inf =~ /^inf(?:inity)?$/i;
+	    local $SIG{FPE} = sub {die};
+	    my $t = 1;
+	    $Inf = $t + "1e99999999999999999999999999999999";
+EOE
+	}
+        $! = $e; # Clear ERANGE.
+    }
+    $Inf = "Inf" if !defined $Inf || !($Inf > 0); # Desperation.
+}
 
-our($VERSION, @ISA, @EXPORT, %EXPORT_TAGS);
+use strict;
 
-my ( $i, $ip2, %logn );
+my $i;
+my %LOGN;
 
-$VERSION = sprintf("%s", q$Id: Complex.pm,v 1.26 1998/11/01 00:00:00 dsl Exp $ =~ /(\d+\.\d+)/);
+require Exporter;
 
 @ISA = qw(Exporter);
 
@@ -49,6 +71,7 @@ use overload
 	'*'	=> \&multiply,
 	'/'	=> \&divide,
 	'**'	=> \&power,
+	'=='	=> \&numeq,
 	'<=>'	=> \&spaceship,
 	'neg'	=> \&negate,
 	'~'	=> \&conjugate,
@@ -66,7 +89,6 @@ use overload
 # Package "privates"
 #
 
-my $package        = 'Math::Complex';	# Package name
 my %DISPLAY_FORMAT = ('style' => 'cartesian',
 		      'polar_pretty_print' => 1);
 my $eps            = 1e-14;		# Epsilon
@@ -228,6 +250,13 @@ sub i () {
 }
 
 #
+# ip2
+#
+# Half of i.
+#
+sub ip2 () { i / 2 }
+
+#
 # Attribute access/set routines
 #
 
@@ -262,7 +291,8 @@ sub update_polar {
 	my ($x, $y) = @{$self->{'cartesian'}};
 	$self->{p_dirty} = 0;
 	return $self->{'polar'} = [0, 0] if $x == 0 && $y == 0;
-	return $self->{'polar'} = [CORE::sqrt($x*$x + $y*$y), CORE::atan2($y, $x)];
+	return $self->{'polar'} = [CORE::sqrt($x*$x + $y*$y),
+				   CORE::atan2($y, $x)];
 }
 
 #
@@ -342,7 +372,7 @@ sub _divbyzero {
 
     if (defined $_[1]) {
 	$mess .= "(Because in the definition of $_[0], the divisor ";
-	$mess .= "$_[1] " unless ($_[1] eq '0');
+	$mess .= "$_[1] " unless ("$_[1]" eq '0');
 	$mess .= "is 0)\n";
     }
 
@@ -416,8 +446,8 @@ sub power {
 	    return 1 if $z2 == 0 || $z1 == 1;
 	    return 0 if $z1 == 0 && Re($z2) > 0;
 	}
-	my $w = $inverted ? CORE::exp($z1 * CORE::log($z2))
-	                  : CORE::exp($z2 * CORE::log($z1));
+	my $w = $inverted ? &exp($z1 * &log($z2))
+	                  : &exp($z2 * &log($z1));
 	# If both arguments cartesian, return cartesian, else polar.
 	return $z1->{c_dirty} == 0 &&
 	       (not ref $z2 or $z2->{c_dirty} == 0) ?
@@ -440,6 +470,19 @@ sub spaceship {
 }
 
 #
+# (numeq)
+#
+# Computes z1 == z2.
+#
+# (Required in addition to spaceship() because of NaNs.)
+sub numeq {
+	my ($z1, $z2, $inverted) = @_;
+	my ($re1, $im1) = ref $z1 ? @{$z1->cartesian} : ($z1, 0);
+	my ($re2, $im2) = ref $z2 ? @{$z2->cartesian} : ($z2, 0);
+	return $re1 == $re2 && $im1 == $im2 ? 1 : 0;
+}
+
+#
 # (negate)
 #
 # Computes -z.
@@ -477,7 +520,13 @@ sub conjugate {
 #
 sub abs {
 	my ($z, $rho) = @_;
-	return $z unless ref $z;
+	unless (ref $z) {
+	    if (@_ == 2) {
+		$_[0] = $_[1];
+	    } else {
+		return CORE::abs($z);
+	    }
+	}
 	if (defined $rho) {
 	    $z->{'polar'} = [ $rho, ${$z->polar}[1] ];
 	    $z->{p_dirty} = 0;
@@ -533,7 +582,8 @@ sub arg {
 sub sqrt {
 	my ($z) = @_;
 	my ($re, $im) = ref $z ? @{$z->cartesian} : ($z, 0);
-	return $re < 0 ? cplx(0, CORE::sqrt(-$re)) : CORE::sqrt($re) if $im == 0;
+	return $re < 0 ? cplx(0, CORE::sqrt(-$re)) : CORE::sqrt($re)
+	    if $im == 0;
 	my ($r, $t) = @{$z->polar};
 	return (ref $z)->emake(CORE::sqrt($r), $t/2);
 }
@@ -547,9 +597,12 @@ sub sqrt {
 #
 sub cbrt {
 	my ($z) = @_;
-	return $z < 0 ? -CORE::exp(CORE::log(-$z)/3) : ($z > 0 ? CORE::exp(CORE::log($z)/3): 0)
+	return $z < 0 ?
+	    -CORE::exp(CORE::log(-$z)/3) :
+		($z > 0 ? CORE::exp(CORE::log($z)/3): 0)
 	    unless ref $z;
 	my ($r, $t) = @{$z->polar};
+	return 0 if $r == 0;
 	return (ref $z)->emake(CORE::exp(CORE::log($r)/3), $t/3);
 }
 
@@ -559,7 +612,7 @@ sub cbrt {
 # Die on bad root.
 #
 sub _rootbad {
-    my $mess = "Root $_[0] not defined, root must be positive integer.\n";
+    my $mess = "Root $_[0] illegal, root rank must be positive integer.\n";
 
     my @up = caller(1);
 
@@ -581,7 +634,8 @@ sub _rootbad {
 sub root {
 	my ($z, $n) = @_;
 	_rootbad($n) if ($n < 1 or int($n) != $n);
-	my ($r, $t) = ref $z ? @{$z->polar} : (CORE::abs($z), $z >= 0 ? 0 : pi);
+	my ($r, $t) = ref $z ?
+	    @{$z->polar} : (CORE::abs($z), $z >= 0 ? 0 : pi);
 	my @root;
 	my $k;
 	my $theta_inc = pit2 / $n;
@@ -620,7 +674,7 @@ sub Re {
 #
 sub Im {
 	my ($z, $Im) = @_;
-	return $z unless ref $z;
+	return 0 unless ref $z;
 	if (defined $Im) {
 	    $z->{'cartesian'} = [ ${$z->cartesian}[0], $Im ];
 	    $z->{c_dirty} = 0;
@@ -723,9 +777,9 @@ sub log10 {
 sub logn {
 	my ($z, $n) = @_;
 	$z = cplx($z, 0) unless ref $z;
-	my $logn = $logn{$n};
-	$logn = $logn{$n} = CORE::log($n) unless defined $logn;	# Cache log(n)
-	return CORE::log($z) / $logn;
+	my $logn = $LOGN{$n};
+	$logn = $LOGN{$n} = CORE::log($n) unless defined $logn;	# Cache log(n)
+	return &log($z) / $logn;
 }
 
 #
@@ -735,11 +789,14 @@ sub logn {
 #
 sub cos {
 	my ($z) = @_;
+	return CORE::cos($z) unless ref $z;
 	my ($x, $y) = @{$z->cartesian};
 	my $ey = CORE::exp($y);
-	my $ey_1 = 1 / $ey;
-	return (ref $z)->make(CORE::cos($x) * ($ey + $ey_1)/2,
-			      CORE::sin($x) * ($ey_1 - $ey)/2);
+	my $sx = CORE::sin($x);
+	my $cx = CORE::cos($x);
+	my $ey_1 = $ey ? 1 / $ey : $Inf;
+	return (ref $z)->make($cx * ($ey + $ey_1)/2,
+			      $sx * ($ey_1 - $ey)/2);
 }
 
 #
@@ -749,11 +806,14 @@ sub cos {
 #
 sub sin {
 	my ($z) = @_;
+	return CORE::sin($z) unless ref $z;
 	my ($x, $y) = @{$z->cartesian};
 	my $ey = CORE::exp($y);
-	my $ey_1 = 1 / $ey;
-	return (ref $z)->make(CORE::sin($x) * ($ey + $ey_1)/2,
-			      CORE::cos($x) * ($ey - $ey_1)/2);
+	my $sx = CORE::sin($x);
+	my $cx = CORE::cos($x);
+	my $ey_1 = $ey ? 1 / $ey : $Inf;
+	return (ref $z)->make($sx * ($ey + $ey_1)/2,
+			      $cx * ($ey - $ey_1)/2);
 }
 
 #
@@ -763,9 +823,9 @@ sub sin {
 #
 sub tan {
 	my ($z) = @_;
-	my $cz = CORE::cos($z);
-	_divbyzero "tan($z)", "cos($z)" if (CORE::abs($cz) < $eps);
-	return CORE::sin($z) / $cz;
+	my $cz = &cos($z);
+	_divbyzero "tan($z)", "cos($z)" if $cz == 0;
+	return &sin($z) / $cz;
 }
 
 #
@@ -775,7 +835,7 @@ sub tan {
 #
 sub sec {
 	my ($z) = @_;
-	my $cz = CORE::cos($z);
+	my $cz = &cos($z);
 	_divbyzero "sec($z)", "cos($z)" if ($cz == 0);
 	return 1 / $cz;
 }
@@ -787,7 +847,7 @@ sub sec {
 #
 sub csc {
 	my ($z) = @_;
-	my $sz = CORE::sin($z);
+	my $sz = &sin($z);
 	_divbyzero "csc($z)", "sin($z)" if ($sz == 0);
 	return 1 / $sz;
 }
@@ -806,9 +866,9 @@ sub cosec { Math::Complex::csc(@_) }
 #
 sub cot {
 	my ($z) = @_;
-	my $sz = CORE::sin($z);
+	my $sz = &sin($z);
 	_divbyzero "cot($z)", "sin($z)" if ($sz == 0);
-	return CORE::cos($z) / $sz;
+	return &cos($z) / $sz;
 }
 
 #
@@ -825,8 +885,11 @@ sub cotan { Math::Complex::cot(@_) }
 #
 sub acos {
 	my $z = $_[0];
-	return CORE::atan2(CORE::sqrt(1-$z*$z), $z) if (! ref $z) && CORE::abs($z) <= 1;
-	my ($x, $y) = ref $z ? @{$z->cartesian} : ($z, 0);
+	return CORE::atan2(CORE::sqrt(1-$z*$z), $z)
+	    if (! ref $z) && CORE::abs($z) <= 1;
+	$z = cplx($z, 0) unless ref $z;
+	my ($x, $y) = @{$z->cartesian};
+	return 0 if $x == 1 && $y == 0;
 	my $t1 = CORE::sqrt(($x+1)*($x+1) + $y*$y);
 	my $t2 = CORE::sqrt(($x-1)*($x-1) + $y*$y);
 	my $alpha = ($t1 + $t2)/2;
@@ -837,7 +900,7 @@ sub acos {
 	my $u = CORE::atan2(CORE::sqrt(1-$beta*$beta), $beta);
 	my $v = CORE::log($alpha + CORE::sqrt($alpha*$alpha-1));
 	$v = -$v if $y > 0 || ($y == 0 && $x < -1);
-	return __PACKAGE__->make($u, $v);
+	return (ref $z)->make($u, $v);
 }
 
 #
@@ -847,8 +910,11 @@ sub acos {
 #
 sub asin {
 	my $z = $_[0];
-	return CORE::atan2($z, CORE::sqrt(1-$z*$z)) if (! ref $z) && CORE::abs($z) <= 1;
-	my ($x, $y) = ref $z ? @{$z->cartesian} : ($z, 0);
+	return CORE::atan2($z, CORE::sqrt(1-$z*$z))
+	    if (! ref $z) && CORE::abs($z) <= 1;
+	$z = cplx($z, 0) unless ref $z;
+	my ($x, $y) = @{$z->cartesian};
+	return 0 if $x == 0 && $y == 0;
 	my $t1 = CORE::sqrt(($x+1)*($x+1) + $y*$y);
 	my $t2 = CORE::sqrt(($x-1)*($x-1) + $y*$y);
 	my $alpha = ($t1 + $t2)/2;
@@ -859,7 +925,7 @@ sub asin {
 	my $u =  CORE::atan2($beta, CORE::sqrt(1-$beta*$beta));
 	my $v = -CORE::log($alpha + CORE::sqrt($alpha*$alpha-1));
 	$v = -$v if $y > 0 || ($y == 0 && $x < -1);
-	return __PACKAGE__->make($u, $v);
+	return (ref $z)->make($u, $v);
 }
 
 #
@@ -870,11 +936,12 @@ sub asin {
 sub atan {
 	my ($z) = @_;
 	return CORE::atan2($z, 1) unless ref $z;
+	my ($x, $y) = ref $z ? @{$z->cartesian} : ($z, 0);
+	return 0 if $x == 0 && $y == 0;
 	_divbyzero "atan(i)"  if ( $z == i);
-	_divbyzero "atan(-i)" if (-$z == i);
-	my $log = CORE::log((i + $z) / (i - $z));
-	$ip2 = 0.5 * i unless defined $ip2;
-	return $ip2 * $log;
+	_logofzero "atan(-i)" if (-$z == i); # -i is a bad file test...
+	my $log = &log((i + $z) / (i - $z));
+	return ip2 * $log;
 }
 
 #
@@ -913,10 +980,11 @@ sub acosec { Math::Complex::acsc(@_) }
 #
 sub acot {
 	my ($z) = @_;
-	_divbyzero "acot(0)"  if (CORE::abs($z)     < $eps);
-	return ($z >= 0) ? CORE::atan2(1, $z) : CORE::atan2(-1, -$z) unless ref $z;
-	_divbyzero "acot(i)"  if (CORE::abs($z - i) < $eps);
-	_logofzero "acot(-i)" if (CORE::abs($z + i) < $eps);
+	_divbyzero "acot(0)"  if $z == 0;
+	return ($z >= 0) ? CORE::atan2(1, $z) : CORE::atan2(-1, -$z)
+	    unless ref $z;
+	_divbyzero "acot(i)"  if ($z - i == 0);
+	_logofzero "acot(-i)" if ($z + i == 0);
 	return atan(1 / $z);
 }
 
@@ -937,11 +1005,11 @@ sub cosh {
 	my $ex;
 	unless (ref $z) {
 	    $ex = CORE::exp($z);
-	    return ($ex + 1/$ex)/2;
+	    return $ex ? ($ex + 1/$ex)/2 : $Inf;
 	}
 	my ($x, $y) = @{$z->cartesian};
 	$ex = CORE::exp($x);
-	my $ex_1 = 1 / $ex;
+	my $ex_1 = $ex ? 1 / $ex : $Inf;
 	return (ref $z)->make(CORE::cos($y) * ($ex + $ex_1)/2,
 			      CORE::sin($y) * ($ex - $ex_1)/2);
 }
@@ -955,12 +1023,15 @@ sub sinh {
 	my ($z) = @_;
 	my $ex;
 	unless (ref $z) {
+	    return 0 if $z == 0;
 	    $ex = CORE::exp($z);
-	    return ($ex - 1/$ex)/2;
+	    return $ex ? ($ex - 1/$ex)/2 : "-$Inf";
 	}
 	my ($x, $y) = @{$z->cartesian};
+	my $cy = CORE::cos($y);
+	my $sy = CORE::sin($y);
 	$ex = CORE::exp($x);
-	my $ex_1 = 1 / $ex;
+	my $ex_1 = $ex ? 1 / $ex : $Inf;
 	return (ref $z)->make(CORE::cos($y) * ($ex - $ex_1)/2,
 			      CORE::sin($y) * ($ex + $ex_1)/2);
 }
@@ -1016,7 +1087,7 @@ sub cosech { Math::Complex::csch(@_) }
 sub coth {
 	my ($z) = @_;
 	my $sz = sinh($z);
-	_divbyzero "coth($z)", "sinh($z)" if ($sz == 0);
+	_divbyzero "coth($z)", "sinh($z)" if $sz == 0;
 	return cosh($z) / $sz;
 }
 
@@ -1035,25 +1106,44 @@ sub cotanh { Math::Complex::coth(@_) }
 sub acosh {
 	my ($z) = @_;
 	unless (ref $z) {
-	    return CORE::log($z + CORE::sqrt($z*$z-1)) if $z >= 1;
 	    $z = cplx($z, 0);
 	}
 	my ($re, $im) = @{$z->cartesian};
 	if ($im == 0) {
-	    return cplx(CORE::log($re + CORE::sqrt($re*$re - 1)), 0) if $re >= 1;
-	    return cplx(0, CORE::atan2(CORE::sqrt(1-$re*$re), $re)) if CORE::abs($re) <= 1;
+	    return CORE::log($re + CORE::sqrt($re*$re - 1))
+		if $re >= 1;
+	    return cplx(0, CORE::atan2(CORE::sqrt(1 - $re*$re), $re))
+		if CORE::abs($re) < 1;
 	}
-	return CORE::log($z + CORE::sqrt($z*$z - 1));
+	my $t = &sqrt($z * $z - 1) + $z;
+	# Try Taylor if looking bad (this usually means that
+	# $z was large negative, therefore the sqrt is really
+	# close to abs(z), summing that with z...)
+	$t = 1/(2 * $z) - 1/(8 * $z**3) + 1/(16 * $z**5) - 5/(128 * $z**7)
+	    if $t == 0;
+	my $u = &log($t);
+	$u->Im(-$u->Im) if $re < 0 && $im == 0;
+	return $re < 0 ? -$u : $u;
 }
 
 #
 # asinh
 #
-# Computes the arc hyperbolic sine asinh(z) = log(z + sqrt(z*z-1))
+# Computes the arc hyperbolic sine asinh(z) = log(z + sqrt(z*z+1))
 #
 sub asinh {
 	my ($z) = @_;
-	return CORE::log($z + CORE::sqrt($z*$z + 1));
+	unless (ref $z) {
+	    my $t = $z + CORE::sqrt($z*$z + 1);
+	    return CORE::log($t) if $t;
+	}
+	my $t = &sqrt($z * $z + 1) + $z;
+	# Try Taylor if looking bad (this usually means that
+	# $z was large negative, therefore the sqrt is really
+	# close to abs(z), summing that with z...)
+	$t = 1/(2 * $z) - 1/(8 * $z**3) + 1/(16 * $z**5) - 5/(128 * $z**7)
+	    if $t == 0;
+	return &log($t);
 }
 
 #
@@ -1067,9 +1157,9 @@ sub atanh {
 	    return CORE::log((1 + $z)/(1 - $z))/2 if CORE::abs($z) < 1;
 	    $z = cplx($z, 0);
 	}
-	_divbyzero 'atanh(1)',  "1 - $z" if ($z ==  1);
-	_logofzero 'atanh(-1)'           if ($z == -1);
-	return 0.5 * CORE::log((1 + $z) / (1 - $z));
+	_divbyzero 'atanh(1)',  "1 - $z" if (1 - $z == 0);
+	_logofzero 'atanh(-1)'           if (1 + $z == 0);
+	return 0.5 * &log((1 + $z) / (1 - $z));
 }
 
 #
@@ -1079,7 +1169,7 @@ sub atanh {
 #
 sub asech {
 	my ($z) = @_;
-	_divbyzero 'asech(0)', $z if ($z == 0);
+	_divbyzero 'asech(0)', "$z" if ($z == 0);
 	return acosh(1 / $z);
 }
 
@@ -1108,14 +1198,14 @@ sub acosech { Math::Complex::acsch(@_) }
 #
 sub acoth {
 	my ($z) = @_;
-	_divbyzero 'acoth(0)'            if (CORE::abs($z)     < $eps);
+	_divbyzero 'acoth(0)'            if ($z == 0);
 	unless (ref $z) {
 	    return CORE::log(($z + 1)/($z - 1))/2 if CORE::abs($z) > 1;
 	    $z = cplx($z, 0);
 	}
-	_divbyzero 'acoth(1)',  "$z - 1" if (CORE::abs($z - 1) < $eps);
-	_logofzero 'acoth(-1)', "1 / $z" if (CORE::abs($z + 1) < $eps);
-	return CORE::log((1 + $z) / ($z - 1)) / 2;
+	_divbyzero 'acoth(1)',  "$z - 1" if ($z - 1 == 0);
+	_logofzero 'acoth(-1)', "1 + $z" if (1 + $z == 0);
+	return &log((1 + $z) / ($z - 1)) / 2;
 }
 
 #
@@ -1141,8 +1231,8 @@ sub atan2 {
 	    ($re2, $im2) = ref $z2 ? @{$z2->cartesian} : ($z2, 0);
 	}
 	if ($im2 == 0) {
-	    return cplx(CORE::atan2($re1, $re2), 0) if $im1 == 0;
-	    return cplx(($im1<=>0) * pip2, 0) if $re2 == 0;
+	    return CORE::atan2($re1, $re2) if $im1 == 0;
+	    return ($im1<=>0) * pip2 if $re2 == 0;
 	}
 	my $w = atan($z1/$z2);
 	my ($u, $v) = ref $w ? @{$w->cartesian} : ($w, 0);
@@ -1173,23 +1263,15 @@ sub display_format {
 		my %obj = %{$self->{display_format}};
 		@display_format{keys %obj} = values %obj;
 	    }
-	    if (@_ == 1) {
-		$display_format{style} = shift;
-	    } else {
-		my %new = @_;
-		@display_format{keys %new} = values %new;
-	    }
-	} else {				# Called as a class method
-	    if (@_ = 1) {
-		$display_format{style} = $self;
-	    } else {
-		my %new = @_;
-		@display_format{keys %new} = values %new;
-	    }
-	    undef $self;
+	}
+	if (@_ == 1) {
+	    $display_format{style} = shift;
+	} else {
+	    my %new = @_;
+	    @display_format{keys %new} = values %new;
 	}
 
-	if (defined $self) {
+	if (ref $self) { # Called as an object method
 	    $self->{display_format} = { %display_format };
 	    return
 		wantarray ?
@@ -1197,6 +1279,7 @@ sub display_format {
 		    $self->{display_format}->{style};
 	}
 
+        # Called as a class method
 	%DISPLAY_FORMAT = %display_format;
 	return
 	    wantarray ?
@@ -1235,67 +1318,58 @@ sub stringify_cartesian {
 	my ($x, $y) = @{$z->cartesian};
 	my ($re, $im);
 
-	$x = int($x + ($x < 0 ? -1 : 1) * $eps)
-		if int(CORE::abs($x)) != int(CORE::abs($x) + $eps);
-	$y = int($y + ($y < 0 ? -1 : 1) * $eps)
-		if int(CORE::abs($y)) != int(CORE::abs($y) + $eps);
-
-	$re = "$x" if CORE::abs($x) >= $eps;
-
 	my %format = $z->display_format;
 	my $format = $format{format};
 
-	if ($y == 1)			       { $im = 'i' }
-	elsif ($y == -1)		       { $im = '-i' }
-	elsif (CORE::abs($y) >= $eps) {
-	    $im = (defined $format ? sprintf($format, $y) : $y) . "i";
+	if ($x) {
+	    if ($x =~ /^NaN[QS]?$/i) {
+		$re = $x;
+	    } else {
+		if ($x =~ /^-?$Inf$/oi) {
+		    $re = $x;
+		} else {
+		    $re = defined $format ? sprintf($format, $x) : $x;
+		}
+	    }
+	} else {
+	    undef $re;
 	}
 
-	my $str = '';
-	$str = defined $format ? sprintf($format, $re) : $re
-	    if defined $re;
+	if ($y) {
+	    if ($y =~ /^(NaN[QS]?)$/i) {
+		$im = $y;
+	    } else {
+		if ($y =~ /^-?$Inf$/oi) {
+		    $im = $y;
+		} else {
+		    $im =
+			defined $format ?
+			    sprintf($format, $y) :
+			    ($y == 1 ? "" : ($y == -1 ? "-" : $y));
+		}
+	    }
+	    $im .= "i";
+	} else {
+	    undef $im;
+	}
+
+	my $str = $re;
+
 	if (defined $im) {
 	    if ($y < 0) {
 		$str .= $im;
-	    } elsif ($y > 0)  {
+	    } elsif ($y > 0 || $im =~ /^NaN[QS]?i$/i)  {
 		$str .= "+" if defined $re;
 		$str .= $im;
 	    }
+	} elsif (!defined $re) {
+	    $str = "0";
 	}
 
 	return $str;
 }
 
 
-# Helper for stringify_polar, a Greatest Common Divisor with a memory.
-
-sub _gcd {
-    my ($a, $b) = @_;
-
-    use integer;
-
-    # Loops forever if given negative inputs.
-
-    if    ($b and $a > $b) { return gcd($a % $b, $b) }
-    elsif ($a and $b > $a) { return gcd($b % $a, $a) }
-    else                   { return $a ? $a : $b     }
-}
-
-my %gcd;
-
-sub gcd {
-    my ($a, $b) = @_;
-
-    my $id = "$a $b";
-
-    unless (exists $gcd{$id}) {
-	$gcd{$id} = _gcd($a, $b);
-	$gcd{"$b $a"} = $gcd{$id};
-    }
-
-    return $gcd{$id};
-}
-
 #
 # ->stringify_polar
 #
@@ -1306,74 +1380,52 @@ sub stringify_polar {
 	my ($r, $t) = @{$z->polar};
 	my $theta;
 
-	return '[0,0]' if $r <= $eps;
-
 	my %format = $z->display_format;
+	my $format = $format{format};
 
-	my $nt = $t / pit2;
-	$nt = ($nt - int($nt)) * pit2;
-	$nt += pit2 if $nt < 0;			# Range [0, 2pi]
-
-	if (CORE::abs($nt) <= $eps)		{ $theta = 0 }
-	elsif (CORE::abs(pi-$nt) <= $eps)	{ $theta = 'pi' }
-
-	if (defined $theta) {
-		$r = int($r + ($r < 0 ? -1 : 1) * $eps)
-			if int(CORE::abs($r)) != int(CORE::abs($r) + $eps);
-		$theta = int($theta + ($theta < 0 ? -1 : 1) * $eps)
-			if ($theta ne 'pi' and
-			    int(CORE::abs($theta)) != int(CORE::abs($theta) + $eps));
-		return "\[$r,$theta\]";
+	if ($t =~ /^NaN[QS]?$/i || $t =~ /^-?$Inf$/oi) {
+	    $theta = $t; 
+	} elsif ($t == pi) {
+	    $theta = "pi";
+	} elsif ($r == 0 || $t == 0) {
+	    $theta = defined $format ? sprintf($format, $t) : $t;
 	}
 
+	return "[$r,$theta]" if defined $theta;
+
 	#
-	# Okay, number is not a real. Try to identify pi/n and friends...
+	# Try to identify pi/n and friends.
 	#
 
-	$nt -= pit2 if $nt > pi;
-
-	if ($format{polar_pretty_print} && CORE::abs($nt) >= deg1) {
-	    my ($n, $k, $kpi);
-
-	    for ($k = 1, $kpi = pi; $k < 10; $k++, $kpi += pi) {
-		$n = int($kpi / $nt + ($nt > 0 ? 1 : -1) * 0.5);
-		if (CORE::abs($kpi/$n - $nt) <= $eps) {
-		    $n = CORE::abs($n);
-		    my $gcd = gcd($k, $n);
-		    if ($gcd > 1) {
-			$k /= $gcd;
-			$n /= $gcd;
-		    }
-		    next if $n > 360;
-		    $theta = ($nt < 0 ? '-':'').
-			     ($k == 1 ? 'pi':"${k}pi");
-		    $theta .= '/'.$n if $n > 1;
+	$t -= int(CORE::abs($t) / pit2) * pit2;
+
+	if ($format{polar_pretty_print} && $t) {
+	    my ($a, $b);
+	    for $a (2..9) {
+		$b = $t * $a / pi;
+		if ($b =~ /^-?\d+$/) {
+		    $b = $b < 0 ? "-" : "" if CORE::abs($b) == 1;
+		    $theta = "${b}pi/$a";
 		    last;
 		}
 	    }
 	}
 
-	$theta = $nt unless defined $theta;
-
-	$r = int($r + ($r < 0 ? -1 : 1) * $eps)
-		if int(CORE::abs($r)) != int(CORE::abs($r) + $eps);
-	$theta = int($theta + ($theta < 0 ? -1 : 1) * $eps)
-		if ($theta !~ m(^-?\d*pi/\d+$) and
-		    int(CORE::abs($theta)) != int(CORE::abs($theta) + $eps));
-
-	my $format = $format{format};
         if (defined $format) {
 	    $r     = sprintf($format, $r);
-	    $theta = sprintf($format, $theta);
+	    $theta = sprintf($format, $theta) unless defined $theta;
+	} else {
+	    $theta = $t unless defined $theta;
 	}
 
-	return "\[$r,$theta\]";
+	return "[$r,$theta]";
 }
 
 1;
 __END__
 
 =pod
+
 =head1 NAME
 
 Math::Complex - complex numbers and associated mathematical functions
@@ -1695,7 +1747,7 @@ For instance:
 	print "j = $j\n";		# Prints "j = -0.5+0.866025403784439i"
 
 The polar style attempts to emphasize arguments like I<k*pi/n>
-(where I<n> is a positive integer and I<k> an integer within [-9,+9]),
+(where I<n> is a positive integer and I<k> an integer within [-9, +9]),
 this is called I<polar pretty-printing>.
 
 =head2 CHANGED IN PERL 5.6
@@ -1705,29 +1757,33 @@ C<display_format> object method can now be called using
 a parameter hash instead of just a one parameter.
 
 The old display format style, which can have values C<"cartesian"> or
-C<"polar">, can be changed using the C<"style"> parameter.  (The one
-parameter calling convention also still works.)
+C<"polar">, can be changed using the C<"style"> parameter.
+
+	$j->display_format(style => "polar");
+
+The one parameter calling convention also still works.
+
+	$j->display_format("polar");
 
 There are two new display parameters.
 
-The first one is C<"format">, which is a sprintf()-style format
-string to be used for both parts of the complex number(s).  The
-default is C<undef>, which corresponds usually (this is somewhat
-system-dependent) to C<"%.15g">.  You can revert to the default by
-setting the format string to C<undef>.
+The first one is C<"format">, which is a sprintf()-style format string
+to be used for both numeric parts of the complex number(s).  The is
+somewhat system-dependent but most often it corresponds to C<"%.15g">.
+You can revert to the default by setting the C<format> to C<undef>.
 
 	# the $j from the above example
 
 	$j->display_format('format' => '%.5f');
 	print "j = $j\n";		# Prints "j = -0.50000+0.86603i"
-	$j->display_format('format' => '%.6f');
+	$j->display_format('format' => undef);
 	print "j = $j\n";		# Prints "j = -0.5+0.86603i"
 
 Notice that this affects also the return values of the
 C<display_format> methods: in list context the whole parameter hash
-will be returned, as opposed to only the style parameter value.  If
-you want to know the whole truth for a complex number, you must call
-both the class method and the object method:
+will be returned, as opposed to only the style parameter value.
+This is a potential incompatibility with earlier versions if you
+have been calling the C<display_format> method in list context.
 
 The second new display parameter is C<"polar_pretty_print">, which can
 be set to true or false, the default being true.  See the previous
@@ -1791,8 +1847,7 @@ is any integer.
 
 Note that because we are operating on approximations of real numbers,
 these errors can happen when merely `too close' to the singularities
-listed above.  For example C<tan(2*atan2(1,1)+1e-15)> will die of
-division by zero.
+listed above.
 
 =head1 ERRORS DUE TO INDIGESTIBLE ARGUMENTS
 
diff --git a/contrib/perl5/lib/Math/Trig.pm b/contrib/perl5/lib/Math/Trig.pm
index 492706c..b28f150 100644
--- a/contrib/perl5/lib/Math/Trig.pm
+++ b/contrib/perl5/lib/Math/Trig.pm
@@ -36,14 +36,15 @@ my @rdlcnv = qw(cartesian_to_cylindrical
 
 %EXPORT_TAGS = ('radial' => [ @rdlcnv ]);
 
-sub pi2 () { 2 * pi }		# use constant generates warning
-sub pip2 () { pi / 2 }		# use constant generates warning
-use constant DR   => pi2/360;
-use constant RD   => 360/pi2;
-use constant DG   => 400/360;
-use constant GD   => 360/400;
-use constant RG   => 400/pi2;
-use constant GR   => pi2/400;
+sub pi2  () { 2 * pi }
+sub pip2 () { pi / 2 }
+
+sub DR  () { pi2/360 }
+sub RD  () { 360/pi2 }
+sub DG  () { 400/360 }
+sub GD  () { 360/400 }
+sub RG  () { 400/pi2 }
+sub GR  () { pi2/400 }
 
 #
 # Truncating remainder.
@@ -58,17 +59,23 @@ sub remt ($$) {
 # Angle conversions.
 #
 
-sub rad2deg ($)  { remt(RD * $_[0], 360) }
+sub rad2rad($)     { remt($_[0], pi2) }
+
+sub deg2deg($)     { remt($_[0], 360) }
+
+sub grad2grad($)   { remt($_[0], 400) }
 
-sub deg2rad ($)  { remt(DR * $_[0], pi2) }
+sub rad2deg ($;$)  { my $d = RD * $_[0]; $_[1] ? $d : deg2deg($d) }
 
-sub grad2deg ($) { remt(GD * $_[0], 360) }
+sub deg2rad ($;$)  { my $d = DR * $_[0]; $_[1] ? $d : rad2rad($d) }
 
-sub deg2grad ($) { remt(DG * $_[0], 400) }
+sub grad2deg ($;$) { my $d = GD * $_[0]; $_[1] ? $d : deg2deg($d) }
 
-sub rad2grad ($) { remt(RG * $_[0], 400) }
+sub deg2grad ($;$) { my $d = DG * $_[0]; $_[1] ? $d : grad2grad($d) }
 
-sub grad2rad ($) { remt(GR * $_[0], pi2) }
+sub rad2grad ($;$) { my $d = RG * $_[0]; $_[1] ? $d : grad2grad($d) }
+
+sub grad2rad ($;$) { my $d = GR * $_[0]; $_[1] ? $d : rad2rad($d) }
 
 sub cartesian_to_spherical {
     my ( $x, $y, $z ) = @_;
@@ -280,6 +287,14 @@ and the imaginary part of approximately C<-1.317>.
 	$gradians = rad2grad($radians);
 
 The full circle is 2 I<pi> radians or I<360> degrees or I<400> gradians.
+The result is by default wrapped to be inside the [0, {2pi,360,400}[ circle.
+If you don't want this, supply a true second argument:
+
+	$zillions_of_radians  = deg2rad($zillions_of_degrees, 1);
+	$negative_degrees     = rad2deg($negative_radians, 1);
+
+You can also do the wrapping explicitly by rad2rad(), deg2deg(), and
+grad2grad().
 
 =head1 RADIAL COORDINATE CONVERSIONS
 
-- 
cgit v1.1