X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMath%2FComplex.pm;h=19d30b062e3ece2d6e193dbc0598c4b95de2f59e;hb=d1be9408a3c14848d30728674452e191ba5fffaa;hp=82872b7696ed46f76c91dc89911eaf1ec103cff7;hpb=806e78a957fcce8bc56cb2c211ffcbba23772d4c;p=p5sagit%2Fp5-mst-13.2.git diff --git a/lib/Math/Complex.pm b/lib/Math/Complex.pm index 82872b7..19d30b0 100644 --- a/lib/Math/Complex.pm +++ b/lib/Math/Complex.pm @@ -7,15 +7,28 @@ package Math::Complex; -$VERSION = "1.30"; - our($VERSION, @ISA, @EXPORT, %EXPORT_TAGS, $Inf); +$VERSION = 1.32; + BEGIN { - my $e = $!; - $Inf = CORE::exp(CORE::exp(30)); # We do want an arithmetic overflow. - $! = $e; # Clear ERANGE. - undef $Inf unless $Inf =~ /^inf(?:inity)?$/i; # Inf INF inf Infinity + 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. } @@ -661,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; @@ -874,7 +887,8 @@ 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); + $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); @@ -886,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); } # @@ -898,7 +912,8 @@ 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); + $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); @@ -910,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); } # @@ -1101,11 +1116,13 @@ sub acosh { if CORE::abs($re) < 1; } my $t = &sqrt($z * $z - 1) + $z; - # Try MacLaurin if looking bad. + # 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 $im == 0; + $u->Im(-$u->Im) if $re < 0 && $im == 0; return $re < 0 ? -$u : $u; } @@ -1121,7 +1138,9 @@ sub asinh { return CORE::log($t) if $t; } my $t = &sqrt($z * $z + 1) + $z; - # Try MacLaurin if looking bad. + # 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); @@ -1244,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 ? @@ -1268,6 +1279,7 @@ sub display_format { $self->{display_format}->{style}; } + # Called as a class method %DISPLAY_FORMAT = %display_format; return wantarray ? @@ -1324,15 +1336,16 @@ sub stringify_cartesian { } if ($y) { - if ($y == 1) { $im = "" } - elsif ($y == -1) { $im = "-" } - elsif ($y =~ /^(NaN[QS]?)$/i) { + if ($y =~ /^(NaN[QS]?)$/i) { $im = $y; } else { if ($y =~ /^-?$Inf$/oi) { $im = $y; } else { - $im = defined $format ? sprintf($format, $y) : $y; + $im = + defined $format ? + sprintf($format, $y) : + ($y == 1 ? "" : ($y == -1 ? "-" : $y)); } } $im .= "i"; @@ -1386,11 +1399,11 @@ sub stringify_polar { $t -= int(CORE::abs($t) / pit2) * pit2; - if ($format{polar_pretty_print}) { + if ($format{polar_pretty_print} && $t) { my ($a, $b); for $a (2..9) { $b = $t * $a / pi; - if (int($b) == $b) { + if ($b =~ /^-?\d+$/) { $b = $b < 0 ? "-" : "" if CORE::abs($b) == 1; $theta = "${b}pi/$a"; last; @@ -1411,6 +1424,8 @@ sub stringify_polar { 1; __END__ +=pod + =head1 NAME Math::Complex - complex numbers and associated mathematical functions @@ -1546,7 +1561,7 @@ be called an extension, would it?). A I operation possible on a complex number that is the identity for real numbers is called the I, and is noted -with an horizontal bar above the number, or C<~z> here. +with a horizontal bar above the number, or C<~z> here. z = a + bi ~z = a - bi @@ -1645,7 +1660,7 @@ I, I, I, I, I, I, I, I, I, I, I, have aliases I, I, I, I, I, I, I, I, I, I, I, respectively. C, C, C, C, -C, and C can be used also also mutators. The C +C, and C can be used also as mutators. The C returns only one of the solutions: if you want all three, use the C function. @@ -1742,29 +1757,33 @@ C 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, which corresponds usually (this is somewhat -system-dependent) to C<"%.15g">. You can revert to the default by -setting the format string to C. +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 to C. # 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 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 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 @@ -1817,7 +1836,7 @@ or Died at... For the C, C, C, C, C, C, C, -C, C, the argument cannot be C<0> (zero). For the the +C, C, the argument cannot be C<0> (zero). For the logarithmic functions and the C, C, the argument cannot be C<1> (one). For the C, C, the argument cannot be C<-1> (minus one). For the C, C, the argument cannot be @@ -1828,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 will die of -division by zero. +listed above. =head1 ERRORS DUE TO INDIGESTIBLE ARGUMENTS