home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / BigRat.pm < prev    next >
Encoding:
Perl POD Document  |  2004-01-07  |  38.2 KB  |  1,492 lines

  1.  
  2. #
  3. # "Tax the rat farms." - Lord Vetinari
  4. #
  5.  
  6. # The following hash values are used:
  7. #   sign : +,-,NaN,+inf,-inf
  8. #   _d   : denominator
  9. #   _n   : numeraotr (value = _n/_d)
  10. #   _a   : accuracy
  11. #   _p   : precision
  12. #   _f   : flags, used by MBR to flag parts of a rational as untouchable
  13. # You should not look at the innards of a BigRat - use the methods for this.
  14.  
  15. package Math::BigRat;
  16.  
  17. require 5.005_03;
  18. use strict;
  19.  
  20. require Exporter;
  21. use Math::BigFloat;
  22. use vars qw($VERSION @ISA $PACKAGE @EXPORT_OK $upgrade $downgrade
  23.             $accuracy $precision $round_mode $div_scale $_trap_nan $_trap_inf);
  24.  
  25. @ISA = qw(Exporter Math::BigFloat);
  26. @EXPORT_OK = qw();
  27.  
  28. $VERSION = '0.11';
  29.  
  30. use overload;            # inherit from Math::BigFloat
  31.  
  32. ##############################################################################
  33. # global constants, flags and accessory
  34.  
  35. $accuracy = $precision = undef;
  36. $round_mode = 'even';
  37. $div_scale = 40;
  38. $upgrade = undef;
  39. $downgrade = undef;
  40.  
  41. # these are internally, and not to be used from the outside
  42.  
  43. use constant MB_NEVER_ROUND => 0x0001;
  44.  
  45. $_trap_nan = 0;                         # are NaNs ok? set w/ config()
  46. $_trap_inf = 0;                         # are infs ok? set w/ config()
  47.  
  48. my $nan = 'NaN';
  49. my $class = 'Math::BigRat';
  50. my $MBI = 'Math::BigInt';
  51.  
  52. sub isa
  53.   {
  54.   return 0 if $_[1] =~ /^Math::Big(Int|Float)/;        # we aren't
  55.   UNIVERSAL::isa(@_);
  56.   }
  57.  
  58. sub _new_from_float
  59.   {
  60.   # turn a single float input into a rational number (like '0.1')
  61.   my ($self,$f) = @_;
  62.  
  63.   return $self->bnan() if $f->is_nan();
  64.   return $self->binf('-inf') if $f->{sign} eq '-inf';
  65.   return $self->binf('+inf') if $f->{sign} eq '+inf';
  66.  
  67.   $self->{_n} = $f->{_m}->copy();            # mantissa
  68.   $self->{_d} = $MBI->bone();
  69.   $self->{sign} = $f->{sign} || '+'; $self->{_n}->{sign} = '+';
  70.   if ($f->{_e}->{sign} eq '-')
  71.     {
  72.     # something like Math::BigRat->new('0.1');
  73.     $self->{_d}->blsft($f->{_e}->copy()->babs(),10);    # 1 / 1 => 1/10
  74.     }
  75.   else
  76.     {
  77.     # something like Math::BigRat->new('10');
  78.     # 1 / 1 => 10/1
  79.     $self->{_n}->blsft($f->{_e},10) unless $f->{_e}->is_zero();    
  80.     }
  81.   $self;
  82.   }
  83.  
  84. sub new
  85.   {
  86.   # create a Math::BigRat
  87.   my $class = shift;
  88.  
  89.   my ($n,$d) = shift;
  90.  
  91.   my $self = { }; bless $self,$class;
  92.  
  93.   # input like (BigInt,BigInt) or (BigFloat,BigFloat) not handled yet
  94.  
  95.   if ((!defined $d) && (ref $n) && (!$n->isa('Math::BigRat')))
  96.     {
  97.     if ($n->isa('Math::BigFloat'))
  98.       {
  99.       $self->_new_from_float($n);
  100.       }
  101.     if ($n->isa('Math::BigInt'))
  102.       {
  103.       # TODO: trap NaN, inf
  104.       $self->{_n} = $n->copy();                # "mantissa" = $n
  105.       $self->{_d} = $MBI->bone();
  106.       $self->{sign} = $self->{_n}->{sign}; $self->{_n}->{sign} = '+';
  107.       }
  108.     if ($n->isa('Math::BigInt::Lite'))
  109.       {
  110.       # TODO: trap NaN, inf
  111.       $self->{sign} = '+'; $self->{sign} = '-' if $$n < 0;
  112.       $self->{_n} = $MBI->new(abs($$n),undef,undef);    # "mantissa" = $n
  113.       $self->{_d} = $MBI->bone();
  114.       }
  115.     return $self->bnorm();
  116.     }
  117.   return $n->copy() if ref $n;
  118.  
  119.   if (!defined $n)
  120.     {
  121.     $self->{_n} = $MBI->bzero();            # undef => 0
  122.     $self->{_d} = $MBI->bone();
  123.     $self->{sign} = '+';
  124.     return $self->bnorm();
  125.     }
  126.   # string input with / delimiter
  127.   if ($n =~ /\s*\/\s*/)
  128.     {
  129.     return $class->bnan() if $n =~ /\/.*\//;    # 1/2/3 isn't valid
  130.     return $class->bnan() if $n =~ /\/\s*$/;    # 1/ isn't valid
  131.     ($n,$d) = split (/\//,$n);
  132.     # try as BigFloats first
  133.     if (($n =~ /[\.eE]/) || ($d =~ /[\.eE]/))
  134.       {
  135.       # one of them looks like a float 
  136.       # Math::BigFloat($n,undef,undef) does not what it is supposed to do, so:
  137.       local $Math::BigFloat::accuracy = undef;
  138.       local $Math::BigFloat::precision = undef;
  139.       local $Math::BigInt::accuracy = undef;
  140.       local $Math::BigInt::precision = undef;
  141.       my $nf = Math::BigFloat->new($n);
  142.       $self->{sign} = '+';
  143.       return $self->bnan() if $nf->is_nan();
  144.       $self->{_n} = $nf->{_m};
  145.       # now correct $self->{_n} due to $n
  146.       my $f = Math::BigFloat->new($d,undef,undef);
  147.       $self->{_d} = $f->{_m};
  148.       return $self->bnan() if $f->is_nan();
  149.       #print "n=$nf e$nf->{_e} d=$f e$f->{_e}\n";
  150.       # calculate the difference between nE and dE
  151.       my $diff_e = $nf->{_e}->copy()->bsub ( $f->{_e} );
  152.       if ($diff_e->is_negative())
  153.     {
  154.         # < 0: mul d with it
  155.         $self->{_d}->blsft($diff_e->babs(),10);
  156.     }
  157.       elsif (!$diff_e->is_zero())
  158.         {
  159.         # > 0: mul n with it
  160.         $self->{_n}->blsft($diff_e,10);
  161.         }
  162.       }
  163.     else
  164.       {
  165.       # both d and n are (big)ints
  166.       $self->{_n} = $MBI->new($n,undef,undef);
  167.       $self->{_d} = $MBI->new($d,undef,undef);
  168.       $self->{sign} = '+';
  169.       return $self->bnan() if $self->{_n}->{sign} eq $nan ||
  170.                               $self->{_d}->{sign} eq $nan;
  171.       # handle inf and NAN cases:
  172.       if ($self->{_n}->is_inf() || $self->{_d}->is_inf())
  173.         {
  174.         # inf/inf => NaN
  175.         return $self->bnan() if
  176.       ($self->{_n}->is_inf() && $self->{_d}->is_inf());
  177.         if ($self->{_n}->is_inf())
  178.       {
  179.       my $s = '+';         # '+inf/+123' or '-inf/-123'
  180.       $s = '-' if substr($self->{_n}->{sign},0,1) ne $self->{_d}->{sign};
  181.       # +-inf/123 => +-inf
  182.           return $self->binf($s);
  183.       }
  184.         # 123/inf => 0
  185.         return $self->bzero();
  186.         }
  187.  
  188.       $self->{sign} = $self->{_n}->{sign}; $self->{_n}->babs();
  189.       # if $d is negative, flip sign
  190.       $self->{sign} =~ tr/+-/-+/ if $self->{_d}->{sign} eq '-';
  191.       $self->{_d}->babs();                # normalize
  192.       }
  193.  
  194.     return $self->bnorm();
  195.     }
  196.  
  197.   # simple string input
  198.   if (($n =~ /[\.eE]/))
  199.     {
  200.     # looks like a float, quacks like a float, so probably is a float
  201.     # Math::BigFloat($n,undef,undef) does not what it is supposed to do, so:
  202.     local $Math::BigFloat::accuracy = undef;
  203.     local $Math::BigFloat::precision = undef;
  204.     local $Math::BigInt::accuracy = undef;
  205.     local $Math::BigInt::precision = undef;
  206.     $self->{sign} = 'NaN';
  207.     $self->_new_from_float(Math::BigFloat->new($n,undef,undef));
  208.     }
  209.   else
  210.     {
  211.     $self->{_n} = $MBI->new($n,undef,undef);
  212.     $self->{_d} = $MBI->bone();
  213.     $self->{sign} = $self->{_n}->{sign}; $self->{_n}->babs();
  214.     return $self->bnan() if $self->{sign} eq 'NaN';
  215.     return $self->binf($self->{sign}) if $self->{sign} =~ /^[+-]inf$/;
  216.     }
  217.   $self->bnorm();
  218.   }
  219.  
  220. ##############################################################################
  221.  
  222. sub config
  223.   {
  224.   # return (later set?) configuration data as hash ref
  225.   my $class = shift || 'Math::BigFloat';
  226.  
  227.   my $cfg = $class->SUPER::config(@_);
  228.  
  229.   # now we need only to override the ones that are different from our parent
  230.   $cfg->{class} = $class;
  231.   $cfg->{with} = $MBI;
  232.   $cfg;
  233.   }
  234.  
  235. ##############################################################################
  236.  
  237. sub bstr
  238.   {
  239.   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
  240.  
  241.   if ($x->{sign} !~ /^[+-]$/)        # inf, NaN etc
  242.     {
  243.     my $s = $x->{sign}; $s =~ s/^\+//;     # +inf => inf
  244.     return $s;
  245.     }
  246.  
  247.   my $s = ''; $s = $x->{sign} if $x->{sign} ne '+';    # '+3/2' => '3/2'
  248.  
  249.   return $s . $x->{_n}->bstr() if $x->{_d}->is_one();
  250.   $s . $x->{_n}->bstr() . '/' . $x->{_d}->bstr();
  251.   }
  252.  
  253. sub bsstr
  254.   {
  255.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  256.  
  257.   if ($x->{sign} !~ /^[+-]$/)        # inf, NaN etc
  258.     {
  259.     my $s = $x->{sign}; $s =~ s/^\+//;     # +inf => inf
  260.     return $s;
  261.     }
  262.   
  263.   my $s = ''; $s = $x->{sign} if $x->{sign} ne '+';    # +3 vs 3
  264.   $s . $x->{_n}->bstr() . '/' . $x->{_d}->bstr(); 
  265.   }
  266.  
  267. sub bnorm
  268.   {
  269.   # reduce the number to the shortest form and remember this (so that we
  270.   # don't reduce again)
  271.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  272.  
  273.   # both parts must be BigInt's (or whatever we are using today)
  274.   if (ref($x->{_n}) ne $MBI)
  275.     {
  276.     require Carp; Carp::croak ("n is not $MBI but (".ref($x->{_n}).')');
  277.     }
  278.   if (ref($x->{_d}) ne $MBI)
  279.     {
  280.     require Carp; Carp::croak ("d is not $MBI but (".ref($x->{_d}).')');
  281.     }
  282.  
  283.   # this is to prevent automatically rounding when MBI's globals are set
  284.   $x->{_d}->{_f} = MB_NEVER_ROUND;
  285.   $x->{_n}->{_f} = MB_NEVER_ROUND;
  286.   # 'forget' that parts were rounded via MBI::bround() in MBF's bfround()
  287.   delete $x->{_d}->{_a}; delete $x->{_n}->{_a};
  288.   delete $x->{_d}->{_p}; delete $x->{_n}->{_p}; 
  289.  
  290.   # no normalize for NaN, inf etc.
  291.   return $x if $x->{sign} !~ /^[+-]$/;
  292.  
  293.   # normalize zeros to 0/1
  294.   if (($x->{sign} =~ /^[+-]$/) &&
  295.       ($x->{_n}->is_zero()))
  296.     {
  297.     $x->{sign} = '+';                    # never -0
  298.     $x->{_d} = $MBI->bone() unless $x->{_d}->is_one();
  299.     return $x;
  300.     }
  301.  
  302.   return $x if $x->{_d}->is_one();            # no need to reduce
  303.  
  304.   # reduce other numbers
  305.   # disable upgrade in BigInt, otherwise deep recursion
  306.   local $Math::BigInt::upgrade = undef;
  307.   local $Math::BigInt::accuracy = undef;
  308.   local $Math::BigInt::precision = undef;
  309.   my $gcd = $x->{_n}->bgcd($x->{_d});
  310.  
  311.   if (!$gcd->is_one())
  312.     {
  313.     $x->{_n}->bdiv($gcd);
  314.     $x->{_d}->bdiv($gcd);
  315.     }
  316.   $x;
  317.   }
  318.  
  319. ##############################################################################
  320. # special values
  321.  
  322. sub _bnan
  323.   {
  324.   # used by parent class bnan() to initialize number to NaN
  325.   my $self = shift;
  326.  
  327.   if ($_trap_nan)
  328.     {
  329.     require Carp;
  330.     my $class = ref($self);
  331.     Carp::croak ("Tried to set $self to NaN in $class\::_bnan()");
  332.     }
  333.   $self->{_n} = $MBI->bzero();
  334.   $self->{_d} = $MBI->bzero();
  335.   }
  336.  
  337. sub _binf
  338.   {
  339.   # used by parent class bone() to initialize number to +inf/-inf
  340.   my $self = shift;
  341.  
  342.   if ($_trap_inf)
  343.     {
  344.     require Carp;
  345.     my $class = ref($self);
  346.     Carp::croak ("Tried to set $self to inf in $class\::_binf()");
  347.     }
  348.   $self->{_n} = $MBI->bzero();
  349.   $self->{_d} = $MBI->bzero();
  350.   }
  351.  
  352. sub _bone
  353.   {
  354.   # used by parent class bone() to initialize number to +1/-1
  355.   my $self = shift;
  356.   $self->{_n} = $MBI->bone();
  357.   $self->{_d} = $MBI->bone();
  358.   }
  359.  
  360. sub _bzero
  361.   {
  362.   # used by parent class bzero() to initialize number to 0
  363.   my $self = shift;
  364.   $self->{_n} = $MBI->bzero();
  365.   $self->{_d} = $MBI->bone();
  366.   }
  367.  
  368. ##############################################################################
  369. # mul/add/div etc
  370.  
  371. sub badd
  372.   {
  373.   # add two rational numbers
  374.  
  375.   # set up parameters
  376.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  377.   # objectify is costly, so avoid it
  378.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  379.     {
  380.     ($self,$x,$y,@r) = objectify(2,@_);
  381.     }
  382.  
  383.   $x = $self->new($x) unless $x->isa($self);
  384.   $y = $self->new($y) unless $y->isa($self);
  385.  
  386.   return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
  387.   # TODO: inf handling
  388.  
  389.   #  1   1    gcd(3,4) = 1    1*3 + 1*4    7
  390.   #  - + -                  = --------- = --                 
  391.   #  4   3                      4*3       12
  392.  
  393.   # we do not compute the gcd() here, but simple do:
  394.   #  5   7    5*3 + 7*4   41
  395.   #  - + -  = --------- = --                 
  396.   #  4   3       4*3      12
  397.  
  398.   # the gcd() calculation and reducing is then done in bnorm()
  399.  
  400.   local $Math::BigInt::accuracy = undef;
  401.   local $Math::BigInt::precision = undef;
  402.  
  403.   $x->{_n}->bmul($y->{_d}); $x->{_n}->{sign} = $x->{sign};
  404.   my $m = $y->{_n}->copy()->bmul($x->{_d});
  405.   $m->{sign} = $y->{sign};            # 2/1 - 2/1
  406.   $x->{_n}->badd($m);
  407.  
  408.   $x->{_d}->bmul($y->{_d});
  409.  
  410.   # calculate sign of result and norm our _n part
  411.   $x->{sign} = $x->{_n}->{sign}; $x->{_n}->{sign} = '+';
  412.  
  413.   $x->bnorm()->round(@r);
  414.   }
  415.  
  416. sub bsub
  417.   {
  418.   # subtract two rational numbers
  419.  
  420.   # set up parameters
  421.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  422.   # objectify is costly, so avoid it
  423.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  424.     {
  425.     ($self,$x,$y,@r) = objectify(2,@_);
  426.     }
  427.  
  428.   # flip sign of $x, call badd(), then flip sign of result
  429.   $x->{sign} =~ tr/+-/-+/
  430.     unless $x->{sign} eq '+' && $x->{_n}->is_zero();    # not -0
  431.   $x->badd($y,@r);            # does norm and round
  432.   $x->{sign} =~ tr/+-/-+/ 
  433.     unless $x->{sign} eq '+' && $x->{_n}->is_zero();    # not -0
  434.   $x;
  435.   }
  436.  
  437. sub bmul
  438.   {
  439.   # multiply two rational numbers
  440.   
  441.   # set up parameters
  442.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  443.   # objectify is costly, so avoid it
  444.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  445.     {
  446.     ($self,$x,$y,@r) = objectify(2,@_);
  447.     }
  448.  
  449.   # TODO: $self instead or $class??
  450.   $x = $class->new($x) unless $x->isa($class);
  451.   $y = $class->new($y) unless $y->isa($class);
  452.  
  453.   return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
  454.  
  455.   # inf handling
  456.   if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/))
  457.     {
  458.     return $x->bnan() if $x->is_zero() || $y->is_zero();
  459.     # result will always be +-inf:
  460.     # +inf * +/+inf => +inf, -inf * -/-inf => +inf
  461.     # +inf * -/-inf => -inf, -inf * +/+inf => -inf
  462.     return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
  463.     return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
  464.     return $x->binf('-');
  465.     }
  466.  
  467.   # x== 0 # also: or y == 1 or y == -1
  468.   return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
  469.  
  470.   # According to Knuth, this can be optimized by doingtwice gcd (for d and n)
  471.   # and reducing in one step)
  472.  
  473.   #  1   1    2    1
  474.   #  - * - =  -  = -
  475.   #  4   3    12   6
  476.   
  477.   local $Math::BigInt::accuracy = undef;
  478.   local $Math::BigInt::precision = undef;
  479.   $x->{_n}->bmul($y->{_n});
  480.   $x->{_d}->bmul($y->{_d});
  481.  
  482.   # compute new sign
  483.   $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
  484.  
  485.   $x->bnorm()->round(@r);
  486.   }
  487.  
  488. sub bdiv
  489.   {
  490.   # (dividend: BRAT or num_str, divisor: BRAT or num_str) return
  491.   # (BRAT,BRAT) (quo,rem) or BRAT (only rem)
  492.  
  493.   # set up parameters
  494.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  495.   # objectify is costly, so avoid it
  496.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  497.     {
  498.     ($self,$x,$y,@r) = objectify(2,@_);
  499.     }
  500.  
  501.   # TODO: $self instead or $class??
  502.   $x = $class->new($x) unless $x->isa($class);
  503.   $y = $class->new($y) unless $y->isa($class);
  504.  
  505.   return $self->_div_inf($x,$y)
  506.    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
  507.  
  508.   # x== 0 # also: or y == 1 or y == -1
  509.   return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
  510.  
  511.   # TODO: list context, upgrade
  512.  
  513.   # 1     1    1   3
  514.   # -  /  - == - * -
  515.   # 4     3    4   1
  516.   
  517. #  local $Math::BigInt::accuracy = undef;
  518. #  local $Math::BigInt::precision = undef;
  519.   $x->{_n}->bmul($y->{_d});
  520.   $x->{_d}->bmul($y->{_n});
  521.  
  522.   # compute new sign 
  523.   $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
  524.  
  525.   $x->bnorm()->round(@r);
  526.   $x;
  527.   }
  528.  
  529. sub bmod
  530.   {
  531.   # compute "remainder" (in Perl way) of $x / $y
  532.  
  533.   # set up parameters
  534.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  535.   # objectify is costly, so avoid it
  536.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  537.     {
  538.     ($self,$x,$y,@r) = objectify(2,@_);
  539.     }
  540.  
  541.   # TODO: $self instead or $class??
  542.   $x = $class->new($x) unless $x->isa($class);
  543.   $y = $class->new($y) unless $y->isa($class);
  544.  
  545.   return $self->_div_inf($x,$y)
  546.    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
  547.  
  548.   return $self->_div_inf($x,$y)
  549.    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
  550.  
  551.   return $x if $x->is_zero();           # 0 / 7 = 0, mod 0
  552.  
  553.   # compute $x - $y * floor($x/$y), keeping the sign of $x
  554.  
  555.   # locally disable these, since they would interfere
  556.   local $Math::BigInt::upgrade = undef;
  557.   local $Math::BigInt::accuracy = undef;
  558.   local $Math::BigInt::precision = undef;
  559.  
  560.   my $u = $x->copy()->babs();
  561.   # first, do a "normal" division ($x/$y)
  562.   $u->{_d}->bmul($y->{_n});
  563.   $u->{_n}->bmul($y->{_d});
  564.  
  565.   # compute floor
  566.   if (!$u->{_d}->is_one())
  567.     {
  568.     $u->{_n}->bdiv($u->{_d});            # 22/7 => 3/1 w/ truncate
  569.     # no need to set $u->{_d} to 1, since later we set it to $y->{_d}
  570.     #$x->{_n}->binc() if $x->{sign} eq '-';    # -22/7 => -4/1
  571.     }
  572.   
  573.   # compute $y * $u
  574.   $u->{_d} = $y->{_d};            # 1 * $y->{_d}, see floor above
  575.   $u->{_n}->bmul($y->{_n});
  576.  
  577.   my $xsign = $x->{sign}; $x->{sign} = '+';    # remember sign and make abs
  578.   # compute $x - $u
  579.   $x->bsub($u);
  580.   $x->{sign} = $xsign;                # put sign back
  581.  
  582.   $x->bnorm()->round(@r);
  583.   }
  584.  
  585. ##############################################################################
  586. # bdec/binc
  587.  
  588. sub bdec
  589.   {
  590.   # decrement value (subtract 1)
  591.   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
  592.  
  593.   return $x if $x->{sign} !~ /^[+-]$/;    # NaN, inf, -inf
  594.  
  595.   if ($x->{sign} eq '-')
  596.     {
  597.     $x->{_n}->badd($x->{_d});    # -5/2 => -7/2
  598.     }
  599.   else
  600.     {
  601.     if ($x->{_n}->bacmp($x->{_d}) < 0)
  602.       {
  603.       # 1/3 -- => -2/3
  604.       $x->{_n} = $x->{_d} - $x->{_n};
  605.       $x->{sign} = '-';
  606.       }
  607.     else
  608.       {
  609.       $x->{_n}->bsub($x->{_d});        # 5/2 => 3/2
  610.       }
  611.     }
  612.   $x->bnorm()->round(@r);
  613.   }
  614.  
  615. sub binc
  616.   {
  617.   # increment value (add 1)
  618.   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
  619.   
  620.   return $x if $x->{sign} !~ /^[+-]$/;    # NaN, inf, -inf
  621.  
  622.   if ($x->{sign} eq '-')
  623.     {
  624.     if ($x->{_n}->bacmp($x->{_d}) < 0)
  625.       {
  626.       # -1/3 ++ => 2/3 (overflow at 0)
  627.       $x->{_n} = $x->{_d} - $x->{_n};
  628.       $x->{sign} = '+';
  629.       }
  630.     else
  631.       {
  632.       $x->{_n}->bsub($x->{_d});        # -5/2 => -3/2
  633.       }
  634.     }
  635.   else
  636.     {
  637.     $x->{_n}->badd($x->{_d});    # 5/2 => 7/2
  638.     }
  639.   $x->bnorm()->round(@r);
  640.   }
  641.  
  642. ##############################################################################
  643. # is_foo methods (the rest is inherited)
  644.  
  645. sub is_int
  646.   {
  647.   # return true if arg (BRAT or num_str) is an integer
  648.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  649.  
  650.   return 1 if ($x->{sign} =~ /^[+-]$/) &&    # NaN and +-inf aren't
  651.     $x->{_d}->is_one();                # x/y && y != 1 => no integer
  652.   0;
  653.   }
  654.  
  655. sub is_zero
  656.   {
  657.   # return true if arg (BRAT or num_str) is zero
  658.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  659.  
  660.   return 1 if $x->{sign} eq '+' && $x->{_n}->is_zero();
  661.   0;
  662.   }
  663.  
  664. sub is_one
  665.   {
  666.   # return true if arg (BRAT or num_str) is +1 or -1 if signis given
  667.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  668.  
  669.   my $sign = shift || ''; $sign = '+' if $sign ne '-';
  670.   return 1
  671.    if ($x->{sign} eq $sign && $x->{_n}->is_one() && $x->{_d}->is_one());
  672.   0;
  673.   }
  674.  
  675. sub is_odd
  676.   {
  677.   # return true if arg (BFLOAT or num_str) is odd or false if even
  678.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  679.  
  680.   return 1 if ($x->{sign} =~ /^[+-]$/) &&        # NaN & +-inf aren't
  681.     ($x->{_d}->is_one() && $x->{_n}->is_odd());        # x/2 is not, but 3/1
  682.   0;
  683.   }
  684.  
  685. sub is_even
  686.   {
  687.   # return true if arg (BINT or num_str) is even or false if odd
  688.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  689.  
  690.   return 0 if $x->{sign} !~ /^[+-]$/;            # NaN & +-inf aren't
  691.   return 1 if ($x->{_d}->is_one()            # x/3 is never
  692.      && $x->{_n}->is_even());                # but 4/1 is
  693.   0;
  694.   }
  695.  
  696. BEGIN
  697.   {
  698.   *objectify = \&Math::BigInt::objectify;
  699.   }
  700.  
  701. ##############################################################################
  702. # parts() and friends
  703.  
  704. sub numerator
  705.   {
  706.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  707.  
  708.   return $MBI->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
  709.  
  710.   my $n = $x->{_n}->copy(); $n->{sign} = $x->{sign};
  711.   $n;
  712.   }
  713.  
  714. sub denominator
  715.   {
  716.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  717.  
  718.   return $MBI->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
  719.   $x->{_d}->copy(); 
  720.   }
  721.  
  722. sub parts
  723.   {
  724.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  725.  
  726.   return ($self->bnan(),$self->bnan()) if $x->{sign} eq 'NaN';
  727.   return ($self->binf(),$self->binf()) if $x->{sign} eq '+inf';
  728.   return ($self->binf('-'),$self->binf()) if $x->{sign} eq '-inf';
  729.  
  730.   my $n = $x->{_n}->copy();
  731.   $n->{sign} = $x->{sign};
  732.   return ($n,$x->{_d}->copy());
  733.   }
  734.  
  735. sub length
  736.   {
  737.   return 0;
  738.   }
  739.  
  740. sub digit
  741.   {
  742.   return 0;
  743.   }
  744.  
  745. ##############################################################################
  746. # special calc routines
  747.  
  748. sub bceil
  749.   {
  750.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  751.  
  752.   return $x unless $x->{sign} =~ /^[+-]$/;
  753.   return $x if $x->{_d}->is_one();        # 22/1 => 22, 0/1 => 0
  754.  
  755.   local $Math::BigInt::upgrade = undef;
  756.   local $Math::BigInt::accuracy = undef;
  757.   local $Math::BigInt::precision = undef;
  758.   $x->{_n}->bdiv($x->{_d});            # 22/7 => 3/1 w/ truncate
  759.   $x->{_d}->bone();
  760.   $x->{_n}->binc() if $x->{sign} eq '+';    # +22/7 => 4/1
  761.   $x->{sign} = '+' if $x->{_n}->is_zero();    # -0 => 0
  762.   $x;
  763.   }
  764.  
  765. sub bfloor
  766.   {
  767.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  768.  
  769.   return $x unless $x->{sign} =~ /^[+-]$/;
  770.   return $x if $x->{_d}->is_one();        # 22/1 => 22, 0/1 => 0
  771.  
  772.   local $Math::BigInt::upgrade = undef;
  773.   local $Math::BigInt::accuracy = undef;
  774.   local $Math::BigInt::precision = undef;
  775.   $x->{_n}->bdiv($x->{_d});            # 22/7 => 3/1 w/ truncate
  776.   $x->{_d}->bone();
  777.   $x->{_n}->binc() if $x->{sign} eq '-';    # -22/7 => -4/1
  778.   $x;
  779.   }
  780.  
  781. sub bfac
  782.   {
  783.   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
  784.  
  785.   # if $x is an integer
  786.   if (($x->{sign} eq '+') && ($x->{_d}->is_one()))
  787.     {
  788.     $x->{_n}->bfac();
  789.     return $x->round(@r);
  790.     }
  791.   $x->bnan();
  792.   }
  793.  
  794. sub bpow
  795.   {
  796.   # power ($x ** $y)
  797.  
  798.   # set up parameters
  799.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  800.   # objectify is costly, so avoid it
  801.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  802.     {
  803.     ($self,$x,$y,@r) = objectify(2,@_);
  804.     }
  805.  
  806.   return $x if $x->{sign} =~ /^[+-]inf$/;       # -inf/+inf ** x
  807.   return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan;
  808.   return $x->bone(@r) if $y->is_zero();
  809.   return $x->round(@r) if $x->is_one() || $y->is_one();
  810.   if ($x->{sign} eq '-' && $x->{_n}->is_one() && $x->{_d}->is_one())
  811.     {
  812.     # if $x == -1 and odd/even y => +1/-1
  813.     return $y->is_odd() ? $x->round(@r) : $x->babs()->round(@r);
  814.     # my Casio FX-5500L has a bug here: -1 ** 2 is -1, but -1 * -1 is 1;
  815.     }
  816.   # 1 ** -y => 1 / (1 ** |y|)
  817.   # so do test for negative $y after above's clause
  818.  #  return $x->bnan() if $y->{sign} eq '-';
  819.   return $x->round(@r) if $x->is_zero();  # 0**y => 0 (if not y <= 0)
  820.  
  821.   # shortcut y/1 (and/or x/1)
  822.   if ($y->{_d}->is_one())
  823.     {
  824.     # shortcut for x/1 and y/1
  825.     if ($x->{_d}->is_one())
  826.       {
  827.       $x->{_n}->bpow($y->{_n});        # x/1 ** y/1 => (x ** y)/1
  828.       if ($y->{sign} eq '-')
  829.         {
  830.         # 0.2 ** -3 => 1/(0.2 ** 3)
  831.         ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n});    # swap
  832.         }
  833.       # correct sign; + ** + => +
  834.       if ($x->{sign} eq '-')
  835.         {
  836.         # - * - => +, - * - * - => -
  837.         $x->{sign} = '+' if $y->{_n}->is_even();    
  838.         }
  839.       return $x->round(@r);
  840.       }
  841.     # x/z ** y/1
  842.     $x->{_n}->bpow($y->{_n});        # 5/2 ** y/1 => 5 ** y / 2 ** y
  843.     $x->{_d}->bpow($y->{_n});
  844.     if ($y->{sign} eq '-')
  845.       {
  846.       # 0.2 ** -3 => 1/(0.2 ** 3)
  847.       ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n});    # swap
  848.       }
  849.     # correct sign; + ** + => +
  850.     if ($x->{sign} eq '-')
  851.       {
  852.       # - * - => +, - * - * - => -
  853.       $x->{sign} = '+' if $y->{_n}->is_even();    
  854.       }
  855.     return $x->round(@r);
  856.     }
  857.  
  858.   # regular calculation (this is wrong for d/e ** f/g)
  859.   my $pow2 = $self->__one();
  860.   my $y1 = $MBI->new($y->{_n}/$y->{_d})->babs();
  861.   my $two = $MBI->new(2);
  862.   while (!$y1->is_one())
  863.     {
  864.     $pow2->bmul($x) if $y1->is_odd();
  865.     $y1->bdiv($two);
  866.     $x->bmul($x);
  867.     }
  868.   $x->bmul($pow2) unless $pow2->is_one();
  869.   # n ** -x => 1/n ** x
  870.   ($x->{_d},$x->{_n}) = ($x->{_n},$x->{_d}) if $y->{sign} eq '-'; 
  871.   $x->bnorm()->round(@r);
  872.   }
  873.  
  874. sub blog
  875.   {
  876.   # set up parameters
  877.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  878.  
  879.   # objectify is costly, so avoid it
  880.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  881.     {
  882.     ($self,$x,$y,@r) = objectify(2,@_);
  883.     }
  884.  
  885.   # $x <= 0 => NaN
  886.   return $x->bnan() if $x->is_zero() || $x->{sign} ne '+' || $y->{sign} ne '+';
  887.  
  888.   if ($x->is_int() && $y->is_int())
  889.     {
  890.     return $self->new($x->as_number()->blog($y->as_number(),@r));
  891.     }
  892.  
  893.   warn ("blog() not fully implemented");
  894.   $x->bnan();
  895.   }
  896.  
  897. sub broot
  898.   {
  899.   # set up parameters
  900.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  901.   # objectify is costly, so avoid it
  902.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  903.     {
  904.     ($self,$x,$y,@r) = objectify(2,@_);
  905.     }
  906.  
  907.   if ($x->is_int() && $y->is_int())
  908.     {
  909.     return $self->new($x->as_number()->broot($y->as_number(),@r));
  910.     }
  911.  
  912.   warn ("broot() not fully implemented"); 
  913.   $x->bnan();
  914.   }
  915.  
  916. sub bmodpow
  917.   {
  918.   # set up parameters
  919.   my ($self,$x,$y,$m,@r) = (ref($_[0]),@_);
  920.   # objectify is costly, so avoid it
  921.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  922.     {
  923.     ($self,$x,$y,$m,@r) = objectify(3,@_);
  924.     }
  925.  
  926.   # $x or $y or $m are NaN or +-inf => NaN
  927.   return $x->bnan()
  928.    if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/ ||
  929.    $m->{sign} !~ /^[+-]$/;
  930.  
  931.   if ($x->is_int() && $y->is_int() && $m->is_int())
  932.     {
  933.     return $self->new($x->as_number()->bmodpow($y->as_number(),$m,@r));
  934.     }
  935.  
  936.   warn ("bmodpow() not fully implemented");
  937.   $x->bnan();
  938.   }
  939.  
  940. sub bmodinv
  941.   {
  942.   # set up parameters
  943.   my ($self,$x,$y,@r) = (ref($_[0]),@_);
  944.   # objectify is costly, so avoid it
  945.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  946.     {
  947.     ($self,$x,$y,@r) = objectify(2,@_);
  948.     }
  949.  
  950.   # $x or $y are NaN or +-inf => NaN
  951.   return $x->bnan() 
  952.    if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/;
  953.  
  954.   if ($x->is_int() && $y->is_int())
  955.     {
  956.     return $self->new($x->as_number()->bmodinv($y->as_number(),@r));
  957.     }
  958.  
  959.   warn ("bmodinv() not fully implemented");
  960.   $x->bnan();
  961.   }
  962.  
  963. sub bsqrt
  964.   {
  965.   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
  966.  
  967.   return $x->bnan() if $x->{sign} !~ /^[+]/;    # NaN, -inf or < 0
  968.   return $x if $x->{sign} eq '+inf';            # sqrt(inf) == inf
  969.   return $x->round(@r) if $x->is_zero() || $x->is_one();
  970.  
  971.   local $Math::BigFloat::upgrade = undef;
  972.   local $Math::BigFloat::downgrade = undef;
  973.   local $Math::BigFloat::precision = undef;
  974.   local $Math::BigFloat::accuracy = undef;
  975.   local $Math::BigInt::upgrade = undef;
  976.   local $Math::BigInt::precision = undef;
  977.   local $Math::BigInt::accuracy = undef;
  978.   $x->{_d} = Math::BigFloat->new($x->{_d})->bsqrt();
  979.   $x->{_n} = Math::BigFloat->new($x->{_n})->bsqrt();
  980.  
  981.   # if sqrt(D) was not integer
  982.   if ($x->{_d}->{_e}->{sign} ne '+')
  983.     {
  984.     $x->{_n}->blsft($x->{_d}->{_e}->babs(),10);        # 7.1/4.51 => 7.1/45.1
  985.     $x->{_d} = $x->{_d}->{_m};                # 7.1/45.1 => 71/45.1
  986.     }
  987.   # if sqrt(N) was not integer
  988.   if ($x->{_n}->{_e}->{sign} ne '+')
  989.     {
  990.     $x->{_d}->blsft($x->{_n}->{_e}->babs(),10);        # 71/45.1 => 710/45.1
  991.     $x->{_n} = $x->{_n}->{_m};                # 710/45.1 => 710/451
  992.     }
  993.  
  994.   # convert parts to $MBI again 
  995.   $x->{_n} = $x->{_n}->as_number();
  996.   $x->{_d} = $x->{_d}->as_number();
  997.   $x->bnorm()->round(@r);
  998.   }
  999.  
  1000. sub blsft
  1001.   {
  1002.   my ($self,$x,$y,$b,$a,$p,$r) = objectify(3,@_);
  1003.  
  1004.   $x->bmul( $b->copy()->bpow($y), $a,$p,$r);
  1005.   $x;
  1006.   }
  1007.  
  1008. sub brsft
  1009.   {
  1010.   my ($self,$x,$y,$b,$a,$p,$r) = objectify(2,@_);
  1011.  
  1012.   $x->bdiv( $b->copy()->bpow($y), $a,$p,$r);
  1013.   $x;
  1014.   }
  1015.  
  1016. ##############################################################################
  1017. # round
  1018.  
  1019. sub round
  1020.   {
  1021.   $_[0];
  1022.   }
  1023.  
  1024. sub bround
  1025.   {
  1026.   $_[0];
  1027.   }
  1028.  
  1029. sub bfround
  1030.   {
  1031.   $_[0];
  1032.   }
  1033.  
  1034. ##############################################################################
  1035. # comparing
  1036.  
  1037. sub bcmp
  1038.   {
  1039.   # compare two signed numbers 
  1040.   
  1041.   # set up parameters
  1042.   my ($self,$x,$y) = (ref($_[0]),@_);
  1043.   # objectify is costly, so avoid it
  1044.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  1045.     {
  1046.     ($self,$x,$y) = objectify(2,@_);
  1047.     }
  1048.  
  1049.   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
  1050.     {
  1051.     # handle +-inf and NaN
  1052.     return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
  1053.     return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
  1054.     return +1 if $x->{sign} eq '+inf';
  1055.     return -1 if $x->{sign} eq '-inf';
  1056.     return -1 if $y->{sign} eq '+inf';
  1057.     return +1;
  1058.     }
  1059.   # check sign for speed first
  1060.   return 1 if $x->{sign} eq '+' && $y->{sign} eq '-';   # does also 0 <=> -y
  1061.   return -1 if $x->{sign} eq '-' && $y->{sign} eq '+';  # does also -x <=> 0
  1062.  
  1063.   # shortcut
  1064.   my $xz = $x->{_n}->is_zero();
  1065.   my $yz = $y->{_n}->is_zero();
  1066.   return 0 if $xz && $yz;                               # 0 <=> 0
  1067.   return -1 if $xz && $y->{sign} eq '+';                # 0 <=> +y
  1068.   return 1 if $yz && $x->{sign} eq '+';                 # +x <=> 0
  1069.  
  1070.   my $t = $x->{_n} * $y->{_d}; $t->{sign} = $x->{sign};
  1071.   my $u = $y->{_n} * $x->{_d}; $u->{sign} = $y->{sign};
  1072.   $t->bcmp($u);
  1073.   }
  1074.  
  1075. sub bacmp
  1076.   {
  1077.   # compare two numbers (as unsigned)
  1078.   
  1079.   # set up parameters
  1080.   my ($self,$x,$y) = (ref($_[0]),@_);
  1081.   # objectify is costly, so avoid it
  1082.   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
  1083.     {
  1084.     ($self,$x,$y) = objectify(2,@_);
  1085.     }
  1086.  
  1087.   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
  1088.     {
  1089.     # handle +-inf and NaN
  1090.     return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
  1091.     return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
  1092.     return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/;
  1093.     return -1;
  1094.     }
  1095.  
  1096.   my $t = $x->{_n} * $y->{_d};
  1097.   my $u = $y->{_n} * $x->{_d};
  1098.   $t->bacmp($u);
  1099.   }
  1100.  
  1101. ##############################################################################
  1102. # output conversation
  1103.  
  1104. sub numify
  1105.   {
  1106.   # convert 17/8 => float (aka 2.125)
  1107.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  1108.  
  1109.   return $x->bstr() if $x->{sign} !~ /^[+-]$/;    # inf, NaN, etc
  1110.  
  1111.   # N/1 => N
  1112.   return $x->{_n}->numify() if $x->{_d}->is_one();
  1113.  
  1114.   # N/D
  1115.   my $neg = 1; $neg = -1 if $x->{sign} ne '+';
  1116.   $neg * $x->{_n}->numify() / $x->{_d}->numify();    # return sign * N/D
  1117.   }
  1118.  
  1119. sub as_number
  1120.   {
  1121.   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
  1122.  
  1123.   return $x if $x->{sign} !~ /^[+-]$/;            # NaN, inf etc
  1124.  
  1125.   # need to disable these, otherwise bdiv() gives BigRat again
  1126.   local $Math::BigInt::upgrade = undef;
  1127.   local $Math::BigInt::accuracy = undef;
  1128.   local $Math::BigInt::precision = undef;
  1129.   my $t = $x->{_n}->copy()->bdiv($x->{_d});        # 22/7 => 3
  1130.   $t->{sign} = $x->{sign};
  1131.   $t;
  1132.   }
  1133.  
  1134. sub import
  1135.   {
  1136.   my $self = shift;
  1137.   my $l = scalar @_;
  1138.   my $lib = ''; my @a;
  1139.   for ( my $i = 0; $i < $l ; $i++)
  1140.     {
  1141. #    print "at $_[$i] (",$_[$i+1]||'undef',")\n";
  1142.     if ( $_[$i] eq ':constant' )
  1143.       {
  1144.       # this rest causes overlord er load to step in
  1145.       # print "overload @_\n";
  1146.       overload::constant float => sub { $self->new(shift); };
  1147.       }
  1148. #    elsif ($_[$i] eq 'upgrade')
  1149. #      {
  1150. #     # this causes upgrading
  1151. #      $upgrade = $_[$i+1];              # or undef to disable
  1152. #      $i++;
  1153. #      }
  1154.     elsif ($_[$i] eq 'downgrade')
  1155.       {
  1156.       # this causes downgrading
  1157.       $downgrade = $_[$i+1];            # or undef to disable
  1158.       $i++;
  1159.       }
  1160.     elsif ($_[$i] eq 'lib')
  1161.       {
  1162.       $lib = $_[$i+1] || '';            # default Calc
  1163.       $i++;
  1164.       }
  1165.     elsif ($_[$i] eq 'with')
  1166.       {
  1167.       $MBI = $_[$i+1] || 'Math::BigInt';        # default Math::BigInt
  1168.       $i++;
  1169.       }
  1170.     else
  1171.       {
  1172.       push @a, $_[$i];
  1173.       }
  1174.     }
  1175.   # let use Math::BigInt lib => 'GMP'; use Math::BigFloat; still work
  1176.   my $mbilib = eval { Math::BigInt->config()->{lib} };
  1177.   if ((defined $mbilib) && ($MBI eq 'Math::BigInt'))
  1178.     {
  1179.     # MBI already loaded
  1180.     $MBI->import('lib',"$lib,$mbilib", 'objectify');
  1181.     }
  1182.   else
  1183.     {
  1184.     # MBI not loaded, or not with "Math::BigInt"
  1185.     $lib .= ",$mbilib" if defined $mbilib;
  1186.  
  1187.     if ($] < 5.006)
  1188.       {
  1189.       # Perl < 5.6.0 dies with "out of memory!" when eval() and ':constant' is
  1190.       # used in the same script, or eval inside import().
  1191.       my @parts = split /::/, $MBI;             # Math::BigInt => Math BigInt
  1192.       my $file = pop @parts; $file .= '.pm';    # BigInt => BigInt.pm
  1193.       $file = File::Spec->catfile (@parts, $file);
  1194.       eval { require $file; $MBI->import( lib => '$lib', 'objectify' ); }
  1195.       }
  1196.     else
  1197.       {
  1198.       my $rc = "use $MBI lib => '$lib', 'objectify';";
  1199.       eval $rc;
  1200.       }
  1201.     }
  1202.   if ($@)
  1203.     {
  1204.     require Carp; Carp::croak ("Couldn't load $MBI: $! $@");
  1205.     }
  1206.  
  1207.   # any non :constant stuff is handled by our parent, Exporter
  1208.   # even if @_ is empty, to give it a chance
  1209.   $self->SUPER::import(@a);             # for subclasses
  1210.   $self->export_to_level(1,$self,@a);   # need this, too
  1211.   }
  1212.  
  1213. 1;
  1214.  
  1215. __END__
  1216.  
  1217. =head1 NAME
  1218.  
  1219. Math::BigRat - arbitrarily big rational numbers
  1220.  
  1221. =head1 SYNOPSIS
  1222.  
  1223.     use Math::BigRat;
  1224.  
  1225.     my $x = Math::BigRat->new('3/7'); $x += '5/9';
  1226.  
  1227.     print $x->bstr(),"\n";
  1228.       print $x ** 2,"\n";
  1229.  
  1230.     my $y = Math::BigRat->new('inf');
  1231.     print "$y ", ($y->is_inf ? 'is' : 'is not') , " infinity\n";
  1232.  
  1233.     my $z = Math::BigRat->new(144); $z->bsqrt();
  1234.  
  1235. =head1 DESCRIPTION
  1236.  
  1237. Math::BigRat complements Math::BigInt and Math::BigFloat by providing support
  1238. for arbitrarily big rational numbers.
  1239.  
  1240. =head2 MATH LIBRARY
  1241.  
  1242. Math with the numbers is done (by default) by a module called
  1243. Math::BigInt::Calc. This is equivalent to saying:
  1244.  
  1245.     use Math::BigRat lib => 'Calc';
  1246.  
  1247. You can change this by using:
  1248.  
  1249.     use Math::BigRat lib => 'BitVect';
  1250.  
  1251. The following would first try to find Math::BigInt::Foo, then
  1252. Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
  1253.  
  1254.     use Math::BigRat lib => 'Foo,Math::BigInt::Bar';
  1255.  
  1256. Calc.pm uses as internal format an array of elements of some decimal base
  1257. (usually 1e7, but this might be different for some systems) with the least
  1258. significant digit first, while BitVect.pm uses a bit vector of base 2, most
  1259. significant bit first. Other modules might use even different means of
  1260. representing the numbers. See the respective module documentation for further
  1261. details.
  1262.  
  1263. Currently the following replacement libraries exist, search for them at CPAN:
  1264.  
  1265.     Math::BigInt::BitVect
  1266.     Math::BigInt::GMP
  1267.     Math::BigInt::Pari
  1268.     Math::BigInt::FastCalc
  1269.  
  1270. =head1 METHODS
  1271.  
  1272. Any methods not listed here are dervied from Math::BigFloat (or
  1273. Math::BigInt), so make sure you check these two modules for further
  1274. information.
  1275.  
  1276. =head2 new()
  1277.  
  1278.     $x = Math::BigRat->new('1/3');
  1279.  
  1280. Create a new Math::BigRat object. Input can come in various forms:
  1281.  
  1282.     $x = Math::BigRat->new(123);                # scalars
  1283.     $x = Math::BigRat->new('inf');                # infinity
  1284.     $x = Math::BigRat->new('123.3');            # float
  1285.     $x = Math::BigRat->new('1/3');                # simple string
  1286.     $x = Math::BigRat->new('1 / 3');            # spaced
  1287.     $x = Math::BigRat->new('1 / 0.1');            # w/ floats
  1288.     $x = Math::BigRat->new(Math::BigInt->new(3));        # BigInt
  1289.     $x = Math::BigRat->new(Math::BigFloat->new('3.1'));    # BigFloat
  1290.     $x = Math::BigRat->new(Math::BigInt::Lite->new('2'));    # BigLite
  1291.  
  1292. =head2 numerator()
  1293.  
  1294.     $n = $x->numerator();
  1295.  
  1296. Returns a copy of the numerator (the part above the line) as signed BigInt.
  1297.  
  1298. =head2 denominator()
  1299.     
  1300.     $d = $x->denominator();
  1301.  
  1302. Returns a copy of the denominator (the part under the line) as positive BigInt.
  1303.  
  1304. =head2 parts()
  1305.  
  1306.     ($n,$d) = $x->parts();
  1307.  
  1308. Return a list consisting of (signed) numerator and (unsigned) denominator as
  1309. BigInts.
  1310.  
  1311. =head2 as_number()
  1312.  
  1313.     $x = Math::BigRat->new('13/7');
  1314.     print $x->as_number(),"\n";        # '1'
  1315.  
  1316. Returns a copy of the object as BigInt trunced it to integer.
  1317.  
  1318. =head2 bfac()
  1319.  
  1320.     $x->bfac();
  1321.  
  1322. Calculates the factorial of $x. For instance:
  1323.  
  1324.     print Math::BigRat->new('3/1')->bfac(),"\n";    # 1*2*3
  1325.     print Math::BigRat->new('5/1')->bfac(),"\n";    # 1*2*3*4*5
  1326.  
  1327. Works currently only for integers.
  1328.  
  1329. =head2 blog()
  1330.  
  1331. Is not yet implemented.
  1332.  
  1333. =head2 bround()/round()/bfround()
  1334.  
  1335. Are not yet implemented.
  1336.  
  1337. =head2 bmod()
  1338.  
  1339.     use Math::BigRat;
  1340.     my $x = Math::BigRat->new('7/4');
  1341.     my $y = Math::BigRat->new('4/3');
  1342.     print $x->bmod($y);
  1343.  
  1344. Set $x to the remainder of the division of $x by $y.
  1345.  
  1346. =head2 is_one()
  1347.  
  1348.     print "$x is 1\n" if $x->is_one();
  1349.  
  1350. Return true if $x is exactly one, otherwise false.
  1351.  
  1352. =head2 is_zero()
  1353.  
  1354.     print "$x is 0\n" if $x->is_zero();
  1355.  
  1356. Return true if $x is exactly zero, otherwise false.
  1357.  
  1358. =head2 is_positive()
  1359.  
  1360.     print "$x is >= 0\n" if $x->is_positive();
  1361.  
  1362. Return true if $x is positive (greater than or equal to zero), otherwise
  1363. false. Please note that '+inf' is also positive, while 'NaN' and '-inf' aren't.
  1364.  
  1365. =head2 is_negative()
  1366.  
  1367.     print "$x is < 0\n" if $x->is_negative();
  1368.  
  1369. Return true if $x is negative (smaller than zero), otherwise false. Please
  1370. note that '-inf' is also negative, while 'NaN' and '+inf' aren't.
  1371.  
  1372. =head2 is_int()
  1373.  
  1374.     print "$x is an integer\n" if $x->is_int();
  1375.  
  1376. Return true if $x has a denominator of 1 (e.g. no fraction parts), otherwise
  1377. false. Please note that '-inf', 'inf' and 'NaN' aren't integer.
  1378.  
  1379. =head2 is_odd()
  1380.  
  1381.     print "$x is odd\n" if $x->is_odd();
  1382.  
  1383. Return true if $x is odd, otherwise false.
  1384.  
  1385. =head2 is_even()
  1386.  
  1387.     print "$x is even\n" if $x->is_even();
  1388.  
  1389. Return true if $x is even, otherwise false.
  1390.  
  1391. =head2 bceil()
  1392.  
  1393.     $x->bceil();
  1394.  
  1395. Set $x to the next bigger integer value (e.g. truncate the number to integer
  1396. and then increment it by one).
  1397.  
  1398. =head2 bfloor()
  1399.     
  1400.     $x->bfloor();
  1401.  
  1402. Truncate $x to an integer value.
  1403.  
  1404. =head2 bsqrt()
  1405.     
  1406.     $x->bsqrt();
  1407.  
  1408. Calculate the square root of $x.
  1409.  
  1410. =head2 config
  1411.  
  1412.         use Data::Dumper;
  1413.  
  1414.         print Dumper ( Math::BigRat->config() );
  1415.         print Math::BigRat->config()->{lib},"\n";
  1416.  
  1417. Returns a hash containing the configuration, e.g. the version number, lib
  1418. loaded etc. The following hash keys are currently filled in with the
  1419. appropriate information.
  1420.  
  1421.         key             RO/RW   Description
  1422.                                 Example
  1423.         ============================================================
  1424.         lib             RO      Name of the Math library
  1425.                                 Math::BigInt::Calc
  1426.         lib_version     RO      Version of 'lib'
  1427.                                 0.30
  1428.         class           RO      The class of config you just called
  1429.                                 Math::BigRat
  1430.         version         RO      version number of the class you used
  1431.                                 0.10
  1432.         upgrade         RW      To which class numbers are upgraded
  1433.                                 undef
  1434.         downgrade       RW      To which class numbers are downgraded
  1435.                                 undef
  1436.         precision       RW      Global precision
  1437.                                 undef
  1438.         accuracy        RW      Global accuracy
  1439.                                 undef
  1440.         round_mode      RW      Global round mode
  1441.                                 even
  1442.         div_scale       RW      Fallback acccuracy for div
  1443.                                 40
  1444.         trap_nan        RW      Trap creation of NaN (undef = no)
  1445.                                 undef
  1446.         trap_inf        RW      Trap creation of +inf/-inf (undef = no)
  1447.                                 undef
  1448.  
  1449. By passing a reference to a hash you may set the configuration values. This
  1450. works only for values that a marked with a C<RW> above, anything else is
  1451. read-only.
  1452.  
  1453. =head1 BUGS
  1454.  
  1455. Some things are not yet implemented, or only implemented half-way:
  1456.  
  1457. =over 2
  1458.  
  1459. =item inf handling (partial)
  1460.  
  1461. =item NaN handling (partial)
  1462.  
  1463. =item rounding (not implemented except for bceil/bfloor)
  1464.  
  1465. =item $x ** $y where $y is not an integer
  1466.  
  1467. =item bmod(), blog(), bmodinv() and bmodpow() (partial)
  1468.  
  1469. =back
  1470.  
  1471. =head1 LICENSE
  1472.  
  1473. This program is free software; you may redistribute it and/or modify it under
  1474. the same terms as Perl itself.
  1475.  
  1476. =head1 SEE ALSO
  1477.  
  1478. L<Math::BigFloat> and L<Math::Big> as well as L<Math::BigInt::BitVect>,
  1479. L<Math::BigInt::Pari> and  L<Math::BigInt::GMP>.
  1480.  
  1481. See L<http://search.cpan.org/search?dist=bignum> for a way to use
  1482. Math::BigRat.
  1483.  
  1484. The package at L<http://search.cpan.org/search?dist=Math%3A%3ABigRat>
  1485. may contain more documentation and examples as well as testcases.
  1486.  
  1487. =head1 AUTHORS
  1488.  
  1489. (C) by Tels L<http://bloodgate.com/> 2001, 2002, 2003, 2004.
  1490.  
  1491. =cut
  1492.