## This file generated by InlineX::C2XS (version 0.22) using Inline::C (version 0.5002)
package Math::LongDouble;
use warnings;
use strict;

require Exporter;
*import = \&Exporter::import;
require DynaLoader;

use overload
  '+'     => \&_overload_add,
  '*'     => \&_overload_mul,
  '-'     => \&_overload_sub,
  '/'     => \&_overload_div,
  '**'    => \&_overload_pow,
  '+='    => \&_overload_add_eq,
  '*='    => \&_overload_mul_eq,
  '-='    => \&_overload_sub_eq,
  '/='    => \&_overload_div_eq,
  '**='   => \&_overload_pow_eq,
  '=='    => \&_overload_equiv,
  '""'    => \&_overload_string,
  '!='    => \&_overload_not_equiv,
  'bool'  => \&_overload_true,
  '!'     => \&_overload_not,
  '='     => \&_overload_copy,
  '<'     => \&_overload_lt,
  '<='    => \&_overload_lte,
  '>'     => \&_overload_gt,
  '>='    => \&_overload_gte,
  '<=>'   => \&_overload_spaceship,
  'abs'   => \&_overload_abs,
  'int'   => \&_overload_int,
  'sqrt'  => \&_overload_sqrt,
  'log'   => \&_overload_log,
  'exp'   => \&_overload_exp,
  'sin'   => \&_overload_sin,
  'cos'   => \&_overload_cos,
  'atan2' => \&_overload_atan2,
  '++'    => \&_overload_inc,
  '--'    => \&_overload_dec,
;

our $VERSION = '0.03';
$VERSION = eval $VERSION;

DynaLoader::bootstrap Math::LongDouble $Math::LongDouble::VERSION;

@Math::LongDouble::EXPORT = ();
@Math::LongDouble::EXPORT_OK = qw(
    InfLD NaNLD ZeroLD UnityLD is_NaNLD is_InfLD is_ZeroLD STRtoLD LDtoSTR NVtoLD UVtoLD IVtoLD
    LDtoNV LDtoLD cmp_NV
    ld_set_prec ld_get_prec LDtoSTRP
    );

%Math::LongDouble::EXPORT_TAGS = (all => [qw(
    InfLD NaNLD ZeroLD UnityLD is_NaNLD is_InfLD is_ZeroLD STRtoLD LDtoSTR NVtoLD UVtoLD IVtoLD
    LDtoNV LDtoLD cmp_NV
    ld_set_prec ld_get_prec LDtoSTRP
    )]);

sub dl_load_flags {0} # Prevent DynaLoader from complaining and croaking

sub _overload_string {

    if(is_ZeroLD($_[0])) {
      return '-0' if is_ZeroLD($_[0]) < 0;
      return '0'; 
    }

    if(is_NaNLD($_[0])) {return 'NaN'}
    my $inf = is_InfLD($_[0]);
    return '-Inf' if $inf < 0;
    return 'Inf'  if $inf > 0;

    my @p = split /e/i, LDtoSTR($_[0]);
    while(substr($p[0], -1, 1) eq '0' && substr($p[0], -2, 1) ne '.') {
      chop $p[0];
    }
    return $p[0] . 'e' . $p[1];
}

sub new {

    # This function caters for 2 possibilities:
    # 1) that 'new' has been called OOP style - in which 
    #    case there will be a maximum of 2 args
    # 2) that 'new' has been called as a function - in
    #    which case there will be a maximum of 1 arg.
    # If there are no args, then we just want to return a
    # Math::LongDouble object that's a NaN.
    
    if(!@_) {return NaNLD(1)}
   
    if(@_ > 2) {die "More than 2 arguments supplied to new()"}

    # If 'new' has been called OOP style, the first arg is the string
    # "Math::LongDouble" which we don't need - so let's remove it. However,
    # if the first arg is a Math::LongDouble object (which is a possibility),
    # then we'll get a fatal error when we check it for equivalence to
    # the string "Math::LongDouble". So we first need to check that it's
    # not an object - which we'll do by using the ref() function:
    if(!ref($_[0]) && $_[0] eq "Math::LongDouble") {
      shift;
      if(!@_) {return NaNLD(1)}
      } 

    if(@_ > 1) {die "Too many arguments supplied to new() - expected no more than 1"}

    my $arg = shift;
    my $type = _itsa($arg);

    if($type == 3) { # NV
      if($arg == 0) {return STRtoLD($arg)}
      if($arg != $arg) { #NaN
        if($arg =~ /^\-/) {return NaNLD(-1)}
        return NaNLD(1);
      }
      if(($arg / $arg) != ($arg / $arg)) { # Inf
        if($arg < 0) {return InfLD(-1)}
        return InfLD(1);
      }
    }

    if(
       $type == 1 || #UV
       $type == 2 || #IV
       $type == 3 || #NV
       $type == 4    #PV
                   ) {
      return STRtoLD($arg);
    }

    if($type == 96) { # Math::LongDouble object
      return LDtoLD($arg);
    }

    die "Bad argument given to new";
}


1;

__END__

=head1 NAME

Math::LongDouble - perl interface to C's long double operations
 (for perls that don't already have that capability)


=head1 BUGS

  This module has bugs on perls built with a Microsoft compiler (eg
  ActivePerl) - even if the binaries installed onto the MSVC-built
  perl were built using MinGW on a MinGW-built perl such as Strawberry
  Perl (where no such problem exists).
  By some means that is still unclear, the 'long double' precision
  can apparently be reduced to 'double' precision whenever a 
  Math::LongDouble object is raised to a power (or a square root taken)
  on MSVC-built perls.
  This bug manifests itself in causing some test failures in t/cmp.t
  and t/pow.t.


=head1 DESCRIPTION

  If your perl's NV is a 'long double', then there's no point in using this
  module. But if your perl's NV is a 'double', then this module provides
  you with a way of performing arithmetic operations with long double
  precision.

   use Math::LongDouble qw(:all);

   my $arg = 32.1;
   my $ld1 = Math::LongDouble->new($arg);# Stringify $arg, then assign 
                                          # using C's strtold()
   my $ld2 = NVtoLD($arg); # Assign the NV 32.1 to $ld2.


=head1 OVERLOADING

   The following operations are overloaded:
    + - * / **
    += -= *= /= **=
    != == <= >= <=> < >
    ++ --
    =
    abs bool ! int print
    sqrt log exp
    sin cos atan2

    Arguments to the overloaded operations must be Math::LongDouble
    objects.

     $ld = $ld + 3.1; # currently an error. Do instead:

     $ld = $ld + Math::LongDouble->new('3.1');

=head1 ASSIGNMENT FUNCTIONS

   The following create and assign a new Math::LongDouble.

    $ld = Math::LongDouble->new($arg);
     Returns a Math::LongDouble object to which the numeric value of $arg
     has been assigned.
     If no arg is supplied then $ld will be NaN.

    $ld = UVtoLD($arg);
     Returns a Math::LongDouble object to which the numeric (unsigned
     integer) value of $arg has been assigned.

    $ld = IVtoLD($arg);
     Returns a Math::LongDouble object to which the numeric (signed
     integer) value of $arg has been assigned.

    $ld = NVtoLD($arg);
     Returns a Math::LongDouble object to which the numeric (floating
     point) value of $arg has been assigned.

    $ld2 = LDtoLD($ld1);
     Returns a Math::LongDouble object that is a copy of the
     Math::LongDouble object provided as the argument.
     Courtesy of overloading, this is in effect no different to doing:
     $ld2 = $ld1;

    $ld = STRtoLD($str);
     Returns a Math::LongDouble object that has the value of the string
     $str.


=head1 ASSIGNMENT OF INF, NAN, UNITY and ZERO

   $ld = InfLD($sign);
    If $sign < 0, returns a Math::LongDouble object set to
    negative infinity; else returns a Math::LongDouble object set
    to positive infinity.

   $ld = NaNLD($sign);
    If $sign < 0, returns a Math::longDouble object set to
    negative NaN; else returns a Math::LongDouble object set to
    positive NaN. It may be problematical as to whether a NaN
    with the correct sign has been returned ... but, either way,
    it should return a NaN.

   $ld = ZeroLD($sign);
    If $sign < 0, returns a Math::LongDouble object set to
    negative zero; else returns a Math::LongDouble object set to 
    zero.

   $ld = UnityLD($sign);
    If $sign < 0, returns a Math::LongDouble object set to
    negative one; else returns a Math::LongDouble object set to 
    one.

   ld_set_prec($precision);
    Sets the precision of stringified values to $precision decimal
    digits.

   $precision = ld_get_prec();
    Returns the precision (in decimal digits) that will be used
    when stringifying values (by printing them, or calling
    LDtoSTR).



=head1 RETRIEVAL FUNCTIONS

   The following functions provide ways of seeing the value of
   Math::LongDouble objects.

   $nv = LDtoNV($ld);
    This function returns the value of the Math::LongDouble object to
    a perl scalar (NV). It may not translate the value accurately.

   $string = LDtoSTR($ld);
    Returns the value of the Math::LongDouble object as a string.
    The returned string will contain the same as is displayed by
    "print $ld", except that print() will strip the trailing zeroes
    in the mantissa (significand) whereas LDtoSTR won't.
    By default, provides 18 decimal digits of precision. This can be
    altered by specifying the desired precision (in decimal digits)
    in a call to ld_set_prec.

   $string = LDtoSTRP($ld, $precision);
    Same as LDtoSTR, but takes an additional arg that specifies the
    precision (in decimal digits) of the stringified return value.


=head1 OTHER FUNCTIONS

   $bool = is_NaNLD($ld); 
    Returns 1 if $ld is a Math::LongDouble NaN.
    Else returns 0

   $int = is_InfLD($ld)
    If the Math::LongDouble object $ld is -inf, returns -1.
    If it is +inf, returns 1.
    Otherwise returns 0.

   $int = is_ZeroLD($ld);
    If the Math::LongDouble object $ld is -0, returns -1.
    If it is zero, returns 1.
    Otherwise returns 0.

   $int = cmp_NV($ld, $nv);
    $nv can be any perl number - ie NV, UV or IV.
    If the Math::LongDouble object $ld < $nv returns -1.
    If it is > $nv, returns 1.
    Otherwise returns 0.
     

=head1 LICENSE

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

=head1 AUTHOR

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

=cut

