NAME

Math::Ryu - perl interface to Ryu (sane NV-to-string conversion).

DEPENDENCIES

This module uses the Ryu C implementation,  which is included with
this module's source (in the Ryu_Library/ryu folder). It is therefore
unnecessary to download that Ryu code - but, should you wish to grab
it, it's also available at:
https://github.com/ulfjack/ryu/tree/master/ryu

PREAMBLE

NVs of type 'double', '__float128' and 'long double' (but not
DoubleDouble), are now supported, though the 'long double' and
'__float128' support requires that the underlying C compiler
provides the __uint128_t data type. This caveat probably rules out
'long double' and '__float128' support on old 32-bit builds of perl,
but not on the vast majority of modern 64-bit builds.

DESCRIPTION

Using functionality provided by the Ryu library, we convert an NV to
a decimal string, such that no information is lost, yet keeping the
string as short as possible.
Stringification of NVs provided by perl's print() fuction does not
always adhere to this principle - that is, the condition
( "$nv" == $nv ) is not always true.
For example:
 $nv = 1.4 / 10; # "$nv" != $nv

We can address this by using (s)printf. For example, on a perl whose
$Config{nvtype} is 'double', we could do sprintf("%.17g", $nv)
to provide the stringification. Then we will find that, except for
NaN, the condition ( sprintf("%.17g", $nv) == $nv ) is always true.
But this presents another problem in that "%.17g" formatting will
sometimes provide more significant decimal digits than are needed.
For example:
 printf("%.17g", 0.1); # prints '0.10000000000000001', even though
                       # the condition ("0.1" == 0.1) is also true.

This module provides the nv2s() function which returns a decimal
string representation of its (NV) argumennt. Unless $nv is NaN:
 1) the condition ( nv2s($nv) == $nv ) is always true;
   and
 2) the string returned by nv2s($nv) will contain the fewest number of
    siginificant decimal digits needed for that first condition to hold.

The aim is that the formatting of the string returned by nv2s() will
be the same as provided by python3's print() function.
(Please report any variances - especially substantive ones.)

SYNOPSIS

For this synopsis, we use nv2s() which first appears in version
1.0 of Math::Ryu. From version 1.0 on, nv2s() is the usual "goto"
function. Some (not-very-useful) functions from the earlier versions
have been removed as of version 1.0. See the "FUNCTIONS" documentation
below for a full list of current public functions.

use Math::Ryu qw(:all);

my $str = nv2s(1 / 10);
print $str;           # 0.1 (double|long double|__float28)

$str = nv2s(1.4 / 10);
print $str; # 0.13999999999999999 (double)
            # 0.14 (80-bit long double)
            # 0.13999999999999999999999999999999999 (__float128)

$str = nv2s(sqrt 2);
print $str; # 1.4142135623730951 (double)
            # 1.4142135623730950488 (80-bit long double)
            # 1.4142135623730950488016887242096982 (__float128)

FUNCTIONS

  $str = nv2s($nv);
   Treats the argument as an NV, even if it's not.
   You can check that the argument $nv is an NV by checking that the
   condition (!ryu_SvPOK($nv) && ryu_SvNOK($nv)) is TRUE.
   $str is a string in floating point format that accurately and
   succinctly represents the value held by $nv. When $str is correctly
   assigned to a perl number, that number will be equivalent to $nv.
   Also, $str will contain as few digits as possible, without
   compromising that accuracy.
   $str is formatted by fmtpy() - documented below. (The format is the
   same as provided by Python3's print() function for the same value.)
   There is no need for the caller to know the type (nvtype) of NV that
   $nv is - the nv2s() function handles that.


   Note: nv2s() spends some time reformatting the string that the ryu
         library returned. If you are happy enough with that original
         string, then save some time by avoiding the reformating and
         just run d2s() or ld2s() or q2s() - whichever is appropriate
         for your nvtype. (Or employ your own reformatting sub.)
         Run the script in the "benchmark" folder of Math-Ryu source
         distro (perl benchmark.p), for comparative timings of "with"
         and "without" reformatting.

  $str = n2s($sv);
   Use this function if the argument is to be evaluated in numeric context.
   Arguments that are perl references will throw an exception.
   Handles "integer", "floating point" and "string" values. If the
   argument is a floating point numeric value, then this function returns
   the same as nv2s(). Otherwise, it stringifies the numeric value of the
   given argument, according to whether that numeric value is an integer
   value (that fits into an IV or UV) or a floating point value.
   If the argument ($sv) is itself a string, then $str will reflect the
   value of $sv considered in numeric context. For example
   n2s('hello world') would return '0.0', not 'hello world'.

$str = d2s($nv);  # Use only when $Config{nvtype} is 'double'.
   Returns a decimal string representation of the value of $nv in the
   format 'mantissaEexponent' - eg '1E-1' (for 0.1) and
   '1.4142135623730951E0' (for square root of 2).

 $str = ld2s($nv); # Use only when $Config{nvtype} is 80-bit extended
                   # precision 'long double'.
   Returns a decimal string representation of the value of $nv in the
   format 'mantissaEexponent' - eg '1E-1' (for 0.1) and
  '1.4142135623730950488E0' (for square root of 2).

 $str = q2s($nv);  # Use only when $Config{nvtype} is either
                   # '__float128' or IEEE 754 'long double'.
   Returns a decimal string representation of the value of $nv
   in the format 'mantissaEexponent' - eg '1E-1' (for 0.1) and
   '1.4142135623730950488016887242096982E0' (for square root of 2).

 $str = fmtpy($s);
   ( Originally a pure perl sub - still accessible as fmtpy_pp(). )
   The argument $s is a string as returned by either d2s() or ld2s()
   or q2s(). We aim to reformat $s to be the same as the string that
   python3 would produce, and then return it as $str.
   NOTE: Doing 'fmtpy(d2s($nv))' or 'fmtpy(ld2s($nv))' or
         'fmtpy(q2s($nv))' is equivalent to doing 'nv2s($nv))'.

  $bool = ryu_lln($sv);
  This is an interface to the API function 'looks_like_number'.
  Returns 1 if $sv looks like a number, else returns 0.
  There's not really any reason to export this subroutine, but
  it's there to use if it's ever helpful.

  $bool = ryu_SvIOK($sv);
  $bool = ryu_SvNOK($sv);
   Return 1 if the IOK (respectively, NOK) flag of $sv is set.
   Else return 0.

 $nv = s2d($str); # string to double
  Available only to perls whose $Config{nvsize} is 8.
  If ryu_lln($str) returns a false value, then the s2d() call
  will die with an appropriate error message.
  Otherwise, it returns an NV (double) of the specified value.
  (This can be useful on pre-5.30.0 perls, where perl frequently
  assigns values incorrectly.)

PRINT FUNCTIONS

Just some shorthand ways of printing out values to STDOUT.

pnv($nv); # mnemonic: "print nv2s($nv)"
snv($nv); # mnemonic: "say nv2s($nv)"
 (nv2s is documented above in "FUNCTIONS".)
 prints nv2s($nv) to STDOUT
 and respectively:
 prints nv2s($nv)."\n" to STDOUT.

pn($sv); # mnemonic: "print n2s($sv)"
sn($sv); # mnemonic: "say n2s($sv)"
 (n2s is documented above in "FUNCTIONS".)
 prints n2s($sv) to STDOUT
 and respectively:
 prints n2s($sv)."\n" to STDOUT.

pany(@args); # "p"rint "any"
sany(@args); # "s"ay   "any"
 Both functions print out $arg if the perl API function
 looks_like_number($arg) returns true && either:
   a) the POK flag is set;
   or
   b) the IOK flag is set.

 If that looks_like_number($arg) returns true but both the POK and
 IOK flags are unset, then $arg must be an NV.
 If that NV fits into an IV, then cast it to an IV, and print out
 that (IV) value. Else print out nv2s($arg).

 For all other arguments (ie those for which looks_like_number($arg)
 has returned false), we simply print($arg).

 After sany() has printed the final arg, a terminating "\n" is printed.
 Otherwise sany() and pany() are identical.
 We should find that pany() and sany() produce  outputs aidentical to
 print() - except for those NV values that perl would misrepresent.
 The aim is that pany/sany alone will suffice, and there is no need
 for the user to ever call perl's print()/say() functions if
 Math::Ryu has been loaded.
 Of course, if you really do want to print out an NV as stringified
 by perl (as opposed to being stringified by nv2s) then you'll need
 to use print/say, not pany()/sany().
 Unlike "print" and "say", which are generally called without
 bracketed args, "pany()" and "sany()" should be called with their
 argument(s) enclosed in brackets.

SPRINTF FUNCTION

$str = spanyf(@args); # No "format" arg - not *really* a "sprintf"
 Return the string that pany(@args) would have printed.
 Note that the arguments given to spanyf() should be enclosed in
 brackets, just as with pany() and sany().

LICENSE

This perl module is free software; you may redistribute it
and/or modify it under the same terms as Perl itself.
However, the ".c" and ".h" files that ship with this distro
are Copyright 2018 Ulf Adams, and can only be used under the
the terms of version 2.0 the Apache License, or of version 1.0
of the Boost Software License.
A copy of the Apache License (Apache_License.txt) is included
with this distro.

The Apache License can also be found at:
http://www.apache.org/licenses/LICENSE-2.0

The Boost Software License can be found at:
https://www.boost.org/LICENSE_1_0.txt

This perl module is Copyright 2024 Sisyphus
=head1 AUTHOR

Sisyphus <sisyphus at(@) cpan dot (.) org>