=pod

=head1 DESCRIPTION

   This module defines the "ball" type and functions.
   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 Rmpcb_* functions are generally functions
   that simply wrap the mpc library's matching mpcb_* function.
   The one exception is Rmpcb_retrieve, for which the mpc library does
   not provide a counterpart.

   The ball type (mpcb_t) is defined by
   typedef struct {
    mpc_t  c;
    mpcr_t r;
   }

   where the 'mpcr_t' is the radius type. See the Math::MPC::Radius
   documentation. The components should only be accessed through
   the provided functions.

   To understand functions on balls, one needs to consider the balls
   passed as arguments as sets of complex values, to which a mathematical
   function is applied; the function 'rounds up' in the sense that it
   returns a ball containing all possible values of the function in all the
   possible input values.  Reasonable effort is made to return small balls,
   but again there is no guarantee that the result is the smallest possible
   one.  In the current implementation, the centre of a ball returned as a
   value is obtained by applying the function to the centres of the balls
   passed as arguments, and rounding.  While this is a natural approach, it
   is not the only possible one; however, it also simplifies the error
   analysis as already carried out for functions with regular complex
   arguments.  Whenever the centre of a complex ball has a non-finite real
   or imaginary part (positive or negative infinity or NaN) the radius is
   set to infinity; this can be interpreted as the 'useless ball',
   representing the whole complex plane, whatever the value of the centre
   is.

   Unlike for variables of 'mpc_t' type, where the precision needs to be
   set explicitly at initialisation, variables of type 'mpcb_t' handle
   their precision dynamically.  Ball centres always have the same
   precision for their real and their imaginary parts (again this is a
   choice of the implementation; if they are of very different sizes, one
   could theoretically reduce the precision of the part that is smaller in
   absolute value, which is more strongly affected by the common error
   coded in the radius).  When setting a complex ball from a value of a
   different type, an additional precision parameter is passed, which
   determines the precision of the centre.  Functions on complex balls set
   the precision of their result depending on the input.  In the current
   implementation, this is the minimum of the argument precisions, so if
   all balls are initially set to the same precision, this is preserved
   throughout the computations.  (Notice that the exponent of the radius
   encodes roughly the number of correct binary digits of the ball centre;
   so it would also make sense to reduce the precision if the radius
   becomes larger.)

   The following functions on complex balls are currently available; the
   eclectic collection is motivated by the desire to provide an
   implementation of the arithmetic-geometric mean of complex numbers
   through the use of ball arithmetic.  As for functions taking complex
   arguments, there may be arbitrary overlaps between variables
   representing arguments and results; for instance 'mpcb_mul (Z, Z, Z)'
   is an allowed way of replacing the ball Z by its square.

=head1 FUNCTIONS

   In this documentation:
    Arguments "$op" and "$rop" denote Math::MPC::Ball (mpc_t) objects,
    with "$op" being an argument, and "$rop" being the object
    that receives the value, returned by the function
   "$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.
   "$re" is a perl unsigned scalar UV, relating to the "real" component.
   "$im" is a perl unsigned scalar UV, relating to the "imaginary"
         component.
   "$prec" is a perl unsigned scalar UV, relating to precision.
   "$mpc" is a Math::MPC object (mpc_t)
   "$mpcr" is an mpcr_t (Radius) type.

   $rop = Rmpcb_init();
   $rop = Rmpcb_init_nobless();
    Create a Math::MPC::Ball object. Both the real and imaginary
    components of the encapsulated mpc_t object have unfixed precision
    and values of NaN. The value of the encapsulated Radius (mpcr_t)
    object is set to Inf.
    Creating the object using the "nobless" variant results in an object
    that has not been blessed into the Math::MPC::Ball package. This is
    generally NOT what is wanted as it puts the burden of freeing
    allocated memory onto the user by calling Rmpcb_clear($rop) at the
    appropriate time.

   $uv = Rmpcb_get_prec ($op);
     Return the (common) precision of the real and the complex parts of
     the centre of $op.

   Rmpcb_set ($rop, $op);
     Set $rop to $op, preserving the precision of the centre.

   Rmpcb_set_inf ($rop);
     Set $rop to the whole complex plane.  This is intended to be used
     much in the spirit of an assertion: When a precondition is not
     satisfied inside a function, it can set its result to this value,
      which willpropagate through further computations.

   Rmpcb_set_c ($rop, $mpc, $prec, $re, $im);
    Set $rop to a ball with centre $mpc at precision $prec. If $prec
    is at least the maximum of the precisions of the real and the
    imaginary parts of $mpc and $re (real error) and $im (imaginary
    error) are 0, then the resulting ball is exact with radius zero.
    Using a larger value for $prec makes sense if $mpc is considered
    exact and a larger target precision for the result is desired, or
    some leeway for the working precision is to be taken into account.
    If $prec is less than the precision of $mpc, then usually some
    rounding error occurs when setting the centre, which is taken
    into account in the radius.

    If $re (real error) and $im (imaginary error) are non-zero, the
    argument $mpc is considered as an inexact complex number, with a
    bound on the absolute error of its real part given in $re as a
    multiple of 1/2 ulp of the real part of $mpc, and a bound on the
    absolute error of its imaginary part given in $im as a multiple of
    1/2 ulp of the imaginary part of $mpc. (Notice that if the parts
    of $mp have different precisions or exponents, the absolute values
    of their ulp differ.)  Then $rop is created as a ball with centre
    $mpc and a radius taking these errors $mpc as well as the
    potential additional rounding error for the centre into account.
    If the real part of $mpc is 0, then $re must be 0, since ulp of
    0 makes no sense; otherwise the radius is set to infinity.
    The same remark holds for the imaginary part.

    Using $re and $im different from 0 is particularly useful in
    two settings: If $mpc is itself the result of a call to an 'Rmpc_'
    function with exact input and rounding mode 'MPC_RNDNN' of both
    parts to nearest, then its parts are known with errors of at most
    1/2 ulp, and setting $re and $im to 1 yields a ball which is
    known to contain the exact result (this motivates the strange unit
    of 1/2 ulp); if directed rounding was used, $re and $im can
    be set to 2 instead.

    And if $mpc is the result of a sequence of calls to 'Rmpc_'
    functions for which some error analysis has been carried out (as
    is frequently the case internally when implementing complex
    functions), again the resulting ball $rop is known to contain the
    exact result when using appropriate values for $re and $im.

   Rmpcb_set_ui_ui ($rop, $re, $im, $prec);
    Set $rop to a ball with centre $re + (i * $im) at precision $prec
    or the bitsize of an 'unsigned long int' (ie $Config{longsize} * 8),
    whichever is larger.
    If $Config{ivsize} > $Config{longsize}, you may need to use
    Rmpcb_set_c instead to meet your intention.

   Rmpcb_neg ($rop, $op);
   Rmpcb_add ($rop, $op1, $op2);
   Rmpcb_mul ($rop, $op1, $op2);
   Rmpcb_sqr ($rop, $op);
   Rmpcb_pow_ui ($rop, $op, $ui);
   Rmpcb_sqrt ($rop, $op);
   Rmpcb_div ($rop, $op1, $op2);
   Rmpcb_div_2ui ($rop, $op, $ui);
    These are the exact counterparts of the corresponding functions
    'Rmpc_neg', 'Rmpc_add' and so on, but on complex balls instead of
    complex numbers.

   int Rmpcb_can_round ($op, $prec_re, $prec_im,
                       $rnd); # $rnd is a Math::MPC rounding value
    If the function returns 'true' (a non-zero number), then rounding
    any of the complex numbers in the ball to a complex number with
    precision $prec_re of its real and precision $prec_im of its
    imaginary part and rounding mode $rnd yields the same result and
    rounding direction value'.
    If the function returns 'false' (that is, 0), then it could not
    conclude, or there are two numbers in the ball which would be
    rounded to a different complex number or in a different direction.
    Notice that the function works in a best effort mode and errs on
    the side of caution by potentially returning 'false' on a
    roundable ball; this is consistent with computational functions
    not necessarily returning the smallest enclosing ball.

    If $op contains the result of evaluating some mathematical function
    through a sequence of calls to 'Rmpcb' functions, starting with
    exact complex numbers, that is, balls of radius 0, then a return
    value of 'true' indicates that rounding any value in the ball (its
    centre is readily available) in direction $rnd yields the correct
    result of the function and the correct rounding direction value
    with the usual MPC semantics.

    Notice that when the precision of $op is larger than $prec_re or
    $prec_im, the centre need not be representable at the desired
    precision, and in fact the ball need not contain a representable
    number at all to be 'roundable'.  Even worse, when $rnd is a
    directed rounding mode for the real or the imaginary part and the
    ball of non-zero radius contains a representable number, the return
    value is necessarily 'false'.  Even worse, when the rounding mode
    for one part is to nearest, the corresponding part of the centre of
    the ball is representable and the ball has a non-zero radius, then
    the return value is also necessarily 'false', since even if
    rounding may be possible, the rounding direction value cannot be
    determined.

   int Rmpcb_round ($mpc, $op, $rnd); # $rnd is a Math::MPC
                                      # rounding value.
    Set $mpc to the centre of $op, rounded in direction $rnd, and return
    the corresponding rounding direction value.  If 'Rmpcb_can_round',
    called with $op, the precisions of $mpc and the rounding mode $rnd
    returns 'true', then this function does what is expected, it
    'correctly rounds the ball' and returns a rounding direction value
    that is valid for all of the ball.  As explained above, the result
    is then not necessarily (in the presence of directed rounding with
    radius different from 0, it is rather necessarily not) an element
    of the ball.

   Rmpcb_retrieve($mpc, $mpcr, $op);
   @parts = Rmpc_split($op)
    Rmpcb_retrieve sets the mpc_t encapsulated in $op to $mpc, and sets
    the mpcr_t encapsulated in $op to $mpcr.
    Rmpcb_split goes a bit further:
     $parts[0] is a Math::MPFR object that holds the value of the Real
       part of $mpc;
     $parts[1] is a Math::MPFR object that holds the value of the
       Imaginary part of $mpc;
     $parts[2] is the same Radius object ($mpcr) set in Rmpcb_retrieve.

    Note: $parts[2] can be further split into its 'mantissa' and
          'exponent' parts by calling Rmpcr_split($parts[2]). See the
          'Rmpcr_split' documentation in the Math::MPC::Radius docs.

   Rmpcb_clear($op);
    Free memory associated with $op.
    It's normally unnecessary to call this function unless $op was
    created using Rmpcb_init_nobless().

=head1 LICENSE

    This program is free software; you may redistribute it and/or
    modify it under the same terms as Perl itself.
    Copyright 2022 Sisyphus

=head1 AUTHOR

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

=cut
