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