Math-Ryu
view release on metacpan or search on metacpan
sub nv2s {
my $nv = shift;
return fmtpy( d2s($nv)) if MAX_DEC_DIG == 17;
return fmtpy(ld2s($nv)) if MAX_DEC_DIG == 21;
return fmtpy( q2s($nv));
}
sub n2s {
my $arg = shift;
die "The n2s() function does not accept ", ref($arg), " references"
if ref($arg);
if(!ryu_SvPOK($arg)) {
return $arg if ryu_SvIOK($arg);
return _from_NV($arg) if _NV_fits_IV($arg);
}
return nv2s($arg) if ryu_SvNOK($arg);
# When this sub is called by pany() or sany(), it
# will have returned before reaching here.
# $arg is neither integer nor float nor reference.
# If the numified $arg fits into an IV, return the
# stringification of that value.
# Else, return nv2s($arg), which will coerce $arg
# to an NV.
my $ret = $arg + 0;
return "$ret" if ryu_SvIOK($ret);
#return nv2s($ret) if ryu_SvNOK($ret);
return nv2s($arg);
}
sub fmtpy_pp {
# Pure perl rendition of the fmtpy function. Not exported.
# The given argument will be either 'Infinity', '-Infinity', 'NaN'
# or a finite value of the form "mantissaEexponent".
# The mantissa portion will include a decimal point (with that decimal
# point being the second character in the mantissa) unless the
# mantissa consists of only one decimal significant decimal digit,
# in which case there is no decimal point and the mantissa consists
# solely of that digit.
my $s = shift;
my $sign = '';
my $bitpos = 0;
$sign = '-' if $s =~ s/^\-//;
$bitpos = 1 if substr($s, 1, 1) eq '.'; # else there isn't a decimal point.
if($bitpos) {
# Mantissa's second character is the decimal point.
# Split into mantissa and exponent
my @parts = split /E/i, $s;
if($parts[1] > 0 && $parts[1] < MAX_DEC_DIG) {
# We want, eg, a value like 1.1E-3 to be returned as "0.0011".
my $zero_pad = $parts[1] - (length($parts[0]) - 2);
if($zero_pad >= 0 && ($zero_pad + length($parts[0])) < MAX_DEC_DIG + 1 ) {
substr($parts[0], 1, 1, '');
return $sign . $parts[0] . ('0' x $zero_pad) . '.0';
}
elsif($zero_pad < 0) {
# We want, eg, a value like 1.23625E2 to be returned as "123.625".
# relocate the decimal point
substr($parts[0], 1, 1, '');
substr($parts[0], $zero_pad, 0, '.');
return $sign . $parts[0];
}
}
# Return as is, except that we replace the 'E' with 'e', ensuring also
# that the exponent is preceded by a '+' or '-' sign, and that
# negative exponents consist of at least 2 digits.
$s =~ s/e/e\+/i if $parts[1] > 0;
if ($parts[1] < -4 || $parts[1] >= 0) {
$s =~ s/E0$//i;
substr($s, -1, 0, '0') if substr($s, -2, 1) eq '-'; # pad exponent with a leading '0'.
return $sign . lc($s);
}
# Return, eg 6.25E1 as "0.625"
substr($parts[0], 1, 1, ''); # remove decimal point.
return $sign . '0.' . ('0' x (abs($parts[1]) - 1)) . $parts[0] ;
}
else {
# Return '-inf', 'inf', or 'nan' if (and as) appropriate.
if($s =~ /n/i) {
if($Math::Ryu::PERL_INFNAN) {
return $Math::Ryu::nanvstr if $s =~ /a/i;
return $Math::Ryu::ninfstr if $sign;
return $Math::Ryu::pinfstr;
}
return $sign . lc(substr($s, 0, 3));
}
# Append '.0' to the mantissa and return it if the exponent is 0.
return $sign . $s . '.0' if $s =~ s/E0$//i;
my @parts = split /E/i, $s;
# Return as is, except that we replace the 'E' with 'e', ensuring also
# that the exponent is preceded by a '+' or '-' sign, and that
# negative exponents consist of at least 2 digits.
$s =~ s/e/e\+/i if $parts[1] > 0;
$s =~ s/e\-/e\-0/i if ($parts[1] < -4 && $parts[1] > -10);
return $sign . lc($s) if ($parts[1] < -4 || $parts[1] > MAX_DEC_DIG - 2);
if($parts[1] >= 0 ) { # $parts[1] is in the range 1..(MAX_DEC_DIG - 2)
return $sign . $parts[0] . (0 x $parts[1]) . '.0';
}
# Return, eg, 6E-3 as "0.006".
return $sign . '0.' . ('0' x (abs($parts[1]) - 1)) . $parts[0] ;
}
}
sub s2d {
die "s2d() is available only to perls whose NV is of type 'double'"
unless MAX_DEC_DIG == 17;
my $str = shift;
die("Strings passed to s2d() must \"look like a number\"")
unless ryu_lln($str);
# For _s2d, we need to remove all leading and trailing whitespace.
# If $str contained internal whitespace, then s2d has already died.
$str =~ s/\s//g;
( run in 2.298 seconds using v1.01-cache-2.11-cpan-71847e10f99 )