DESCRIPTION
This module defines the "radius" type and functions, for use
in Ball arithmetic. (See the Math::MPC::Ball documentation for
information on Ball arithmetic.)
It needs the mpc-1.3.0 library, or later.
If building against mpc-1.2.x (or earlier) this module will be
effectively ignored. There are no actions that need to be taken.
The following documentation is essentially a copy of the official
mpc documentation. The Rmpcr_* functions are generally functions
that simply wrap the mpc library's matching mpcr_* function.
However, there are some Rmpcr_* functions (eg Rmpcr_split) that
are functions "in their own right", without any "mpcr_*"
counterpart.
The radius type (mpcr_t) is defined by
struct {
int64_t mant;
int64_t exp;
}
It can contain the special values infinity or zero, or floating
point numbers encoded as mant * (2 ** exp) for a positive mant and an
arbitrary (usually negative) exponent exp. Normalised finite radii
use 31 bits for the mantissa - ie (2 ** 30) <= mant <= (2 ** 30) - 1.
The special values infinity and 0 are encoded through the sign of
m, but should be tested for and set using the dedicated functions.
Unless indicated otherwise, the following functions assume radius
arguments to be normalised, they return normalised results, and they
round their results up, not necessarily to the smallest representable
number, although reasonable effort is made to get a tight upper bound:
They only guarantee that their outputs are an upper bound on the true
results. (There may be a trade-off between tightness of the result
and speed of computation. For instance, when a 32-bit mantissa is
normalised, an even mantissa should be divided by 2, an odd mantissa
should be divided by 2 and 1 should be added, and then in both cases
the exponent must be increased by 1. It might be more efficient to
add 1 all the time instead of testing the last bit of the mantissa.)
FUNCTIONS
In this documentation:
Arguments "$op" and "$rop" denote Math::MPC::Radius (mpcr_ptr)
object, with "$op" being an argument, and "$rop" being the
object that receives the value, returned by the function.
"$fh" is a specified stream - eg stdout or sderr or a filehandle.
"$ui64" is a perl integer scalar that will be cast to uint64_t.
"$si64" is a perl integer scalar that will be cast to 'int64_t'.
"$i" is a perl integer type containing a 'signed int' value.
"$si" is a perl integer type containing a 'signed long int' value.
"$ui" is a perl integer type containing an 'unsigned long int' value.
"$iv" is a perl signed scalar IV.
"$uv" is a perl unsigned scalar UV.
"$str" is a string - ie a perl scalar PV.
$rop = Rmpcr_init();
$rop = Rmpcr_init_nobless();
Create a Math::MPC::Radius object with a value of zero.
Creating the object using the "nobless" variant results in an object
that has not been blessed into the Math::MPC::Radius package. This is
generally NOT what is wanted as it puts the burden of freeing
allocated memory onto the user by calling Rmpcr_clear($rop) at the
appropriate time.
Rmpcr_clear($rop);
Free the memory associated with $rop.
Use this only if $rop was initialized using Rmpcr_init_nobless().
If $rop was initialized with Rmpcr_init(), then perl will free the
memory as soon as is appropriate.
$i = Rmpcr_inf_p ($op);
$i = Rmpcr_zero_p ($op);
Test whether $op is infinity or zero, respectively, and return a
boolean.
$i = Rmpcr_lt_half_p ($op);
Return 'true' if $op < 1/2, and 'false' otherwise.
$i = Rmpcr_cmp ($op1, $op2);
Return +1, 0 or -1 depending on whether $op1 is larger than, equal to
or less than $op2, with the natural total order on the compactified
non-negative real axis letting 0 be smaller and letting infinity be
larger than any finite real number.
Rmpcr_set_inf ($rop);
Rmpcr_set_zero ($rop);
Rmpcr_set_one ($rop);
Rmpcr_set ($rop, $op);
Rmpcr_set_ui64_2si64 ($rop, $ui64, $si64);
Set $rop to infinity, zero, 1, $op or $ui64 * (2 ** $si64),
respectively.
Rmpcr_set_str_2str ($rop, $str1, $str2);
A replacement for Rmpcr_set_ui64_2si64 on perls whose IV size < 8.
The 64-bit values can be represented as Decimal integer strings,
with $rop being set to $str1 * (2 ** $str2).
Rmpcr_max ($rop, $op1, $op2);
Set $rop to the maximum of $op1 and $op2.
$iv = Rmpcr_get_exp ($op);
Assuming that $op is neither infinity nor 0, return its exponent
$iv, such that $op == m * (2 ** $iv), with 1/2 <= m < 1.
This function's behaviour is undefined when $op is either Inf or 0.
If perl's ivsize is less than 8 bytes and the returned value will
overflow the IV, then the function croaks with a message
recommending that Rmpcr_get_exp_mpfr (below) be used instead.
$mpfr = Rmpcr_get_exp_mpfr($op); # $mpfr is a 64-bit precision
# Math::MPFR object.
As for Rmpcr_get_exp (above), except that it returns the 64-bit
integer value as a 64-bit precision Math::MPFR object. This avoids
the problem of having 64-bit values overflow the 4-byte IV.
@parts = Rmpcr_split($op);
If $op is zero, @parts is a one-element array, containing the UV 0.
If $op is Inf, @parts is a one-element array, containing the string
"Inf".
Otherwise, @parts is a two-element array. The first element is a UV
holding the value of the mantissa of $op, and the second element is
an IV holding the value of the exponent of $op.
$op then represents the "radius" value $parts[0] * (2 ** $parts[1]).
This function will croak if perl's ivsize is 4 and the value of the
mantissa or the exponent overflows the 4-byte IV. In such a case,
the message recommends using Rmpcr_split_mpfr (below) instead.
@parts = Rmpcr_split_mpfr($op);
NOTE: Provided for the benefit of those perls whose ivsize is 4, but
can be used with all perls, irrespective of their IVSIZE.
The same as Rmpcr_split except that, where Rmpcr_split returns an IV
or UV, Rmpcr_split_mpfr returns the same value in the form of a
Math::MPFR object with 64-bit precision. This avoids the problem of
having 64-bit values overflow the 4-byte IV or UV.
Rmpcr_out_str ($fh, $op);
Rmpcr_print($op);
Rmpcr_say($op);
Rmpcr_out_str outputs $op on $fh, which may be 'stdout'.
Rmpcr_print and Rmpcr_say print to 'stdout', with Rmpcr_say adding
a newline - as with perl's say() function.
Caveat: These functions so far serve mainly for debugging purposes.
Their behaviour might change in the future.
Rmpcr_add ($rop, $op1, $op2);
Rmpcr_sub ($rop, $op1, $op2);
Rmpcr_mul ($rop, $op1, $op2);
Rmpcr_div ($rop, $op1, $op2);
Rmpcr_mul_2ui ($rop, $op, $ui);
Rmpcr_div_2ui ($rop, $op, $ui);
Rmpcr_sqr ($rop, $op);
Rmpcr_sqrt ($rop, $op);
Set rop to the sum, difference, product or quotient of $op1 and $op2,
or to $op * (2 ** $ui) or to $p / (2 ** $ui), or to the square or the
square root of $op. If any of the arguments is infinity, or if a
difference is negative, the result is infinity.
Rmpcr_sub_rnd ($rop, $op1, $op2, $round); # $round is a Math::MPFR
# rounding value
Set $op to the difference of $op1 and $op2, rounded according to
$round, which can be one of 'MPFR_RNDU' or 'MPFR_RNDD'. If one of
the arguments is infinity or the difference is negative, the result
is infinity. Calling the function with 'MPFR_RNDU' is equivalent to
calling 'Rmpcr_sub'.
This is one out of several functions taking a rounding parameter.
Rounding down may be useful to obtain an upper bound when dividing
by the result.
Rmpcr_c_abs_rnd ($rop, $mpc, $round); # $mpc is a Math::MPC object.
# $round is a Math::MPFR rounding
# value
Set $rop to the absolute value of the complex number $mpc, rounded
in the direction $round, which may be one of 'MPFR_RNDU' or
'MPFR_RNDD'.
Rmpcr_add_rounding_error ($rop, $uv, $round); # $round is a Math::MPFR
# rounding value
Set $rop to $rop + ((1 + $rop) * (2 ** - $uv)) if $round equals
'MPFR_RNDN', else to $rop + ((1 + $rop) * (2 ** (1- $uv))) . The idea is
that if a (potentially not representable) centre of an ideal complex
ball of radius $rop is rounded to a representable complex number at
precision $uv, this shifts the centre by up to 1/2 ulp (for rounding to
nearest) or 1ulp (for directed rounding of at least one of the real
or imaginary parts), which increases the radius accordingly. So this
function is typically called internally at the end of each operation
with complex balls to account for the error made by rounding the centre.
LICENSE
This program is free software; you may redistribute it and/or
modify it under the same terms as Perl itself.
Copyright 2022 Sisyphus
AUTHOR
Sisyphus <sisyphus at(@) cpan dot (.) org>