fix warning + carp interaction
[p5sagit/p5-mst-13.2.git] / lib / bigrat.pm
1 package bigrat;
2 require 5.005;
3
4 $VERSION = '0.04';
5 use Exporter;
6 @ISA =       qw( Exporter );
7 @EXPORT_OK = qw( ); 
8
9 use strict;
10
11 ############################################################################## 
12
13 # These are all alike, and thus faked by AUTOLOAD
14
15 my @faked = qw/round_mode accuracy precision div_scale/;
16 use vars qw/$VERSION $AUTOLOAD $_lite/;         # _lite for testsuite
17
18 sub AUTOLOAD
19   {
20   my $name = $AUTOLOAD;
21
22   $name =~ s/.*:://;    # split package
23   no strict 'refs';
24   foreach my $n (@faked)
25     {
26     if ($n eq $name)
27       {
28       *{"bigrat::$name"} = sub 
29         {
30         my $self = shift;
31         no strict 'refs';
32         if (defined $_[0])
33           {
34           Math::BigInt->$name($_[0]);
35           Math::BigFloat->$name($_[0]);
36           }
37         return Math::BigInt->$name();
38         };
39       return &$name;
40       }
41     }
42  
43   # delayed load of Carp and avoid recursion
44   require Carp;
45   Carp::croak ("Can't call bigrat\-\>$name, not a valid method");
46   }
47
48 sub upgrade
49   {
50   my $self = shift;
51   no strict 'refs';
52 #  if (defined $_[0])
53 #    {
54 #    $Math::BigInt::upgrade = $_[0];
55 #    $Math::BigFloat::upgrade = $_[0];
56 #    }
57   return $Math::BigInt::upgrade;
58   }
59
60 sub import 
61   {
62   my $self = shift;
63
64   # see also bignum->import() for additional comments
65
66   # some defaults
67   my $lib = 'Calc'; my $upgrade = 'Math::BigFloat';
68
69   my @import = ( ':constant' );                         # drive it w/ constant
70   my @a = @_; my $l = scalar @_; my $j = 0;
71   my ($a,$p);
72   my ($ver,$trace);                                     # version? trace?
73   for ( my $i = 0; $i < $l ; $i++,$j++ )
74     {
75     if ($_[$i] eq 'upgrade')
76       {
77       # this causes upgrading
78       $upgrade = $_[$i+1];              # or undef to disable
79       my $s = 2; $s = 1 if @a-$j < 2;   # avoid "can not modify non-existant..."
80       splice @a, $j, $s; $j -= $s;
81       }
82     elsif ($_[$i] =~ /^(l|lib)$/)
83       {
84       # this causes a different low lib to take care...
85       $lib = $_[$i+1] || '';
86       my $s = 2; $s = 1 if @a-$j < 2;   # avoid "can not modify non-existant..."
87       splice @a, $j, $s; $j -= $s;
88       }
89     elsif ($_[$i] =~ /^(v|version)$/)
90       {
91       $ver = 1;
92       splice @a, $j, 1; $j --;
93       }
94     elsif ($_[$i] =~ /^(t|trace)$/)
95       {
96       $trace = 1;
97       splice @a, $j, 1; $j --;
98       }
99     else
100       {
101       die ("unknown option $_[$i]");
102       }
103     }
104   my $class;
105   $_lite = 0;                                   # using M::BI::L ?
106   if ($trace)
107     {
108     require Math::BigInt::Trace; $class = 'Math::BigInt::Trace';
109     $upgrade = 'Math::BigFloat::Trace';
110 #    print STDERR "Loading $class";
111     }
112   else
113     {
114     # see if we can find Math::BigInt::Lite
115     if (!defined $a && !defined $p)             # rounding won't work to well
116       {
117       eval 'require Math::BigInt::Lite;';
118       if ($@ eq '')
119         {
120         @import = ( );                          # :constant in Lite, not MBI
121         Math::BigInt::Lite->import( ':constant' );
122         $_lite= 1;                              # signal okay
123         }
124       }
125     require Math::BigInt if $_lite == 0;        # not already loaded?
126     $class = 'Math::BigInt';                    # regardless of MBIL or not
127     }
128   # Math::BigInt::Trace or plain Math::BigInt
129   $class->import(@import, upgrade => $upgrade, lib => $lib);
130
131   require Math::BigFloat;
132   Math::BigFloat->import( upgrade => 'Math::BigRat', ':constant' );
133   require Math::BigRat;
134   if ($ver)
135     {
136     print "bigrat\t\t\t v$VERSION\n";
137     print "Math::BigInt::Lite\t v$Math::BigInt::Lite::VERSION\n" if $_lite;  
138     print "Math::BigInt\t\t v$Math::BigInt::VERSION";
139     my $config = Math::BigInt->config();
140     print " lib => $config->{lib} v$config->{lib_version}\n";
141     print "Math::BigFloat\t\t v$Math::BigFloat::VERSION\n";
142     print "Math::BigRat\t\t v$Math::BigRat::VERSION\n";
143     exit;
144     }
145   }
146
147 1;
148
149 __END__
150
151 =head1 NAME
152
153 bigrat - Transparent BigNumber/BigRationale support for Perl
154
155 =head1 SYNOPSIS
156
157   use bigrat;
158
159   $x = 2 + 4.5,"\n";                    # BigFloat 6.5
160   print 1/3 + 1/4,"\n";                 # produces 7/12
161
162 =head1 DESCRIPTION
163
164 All operators (inlcuding basic math operations) are overloaded. Integer and
165 floating-point constants are created as proper BigInts or BigFloats,
166 respectively.
167
168 Other than L<bignum>, this module upgrades to Math::BigRat, meaning that
169 instead of 2.5 you will get 2+1/2 as output.
170
171 =head2 MODULES USED
172
173 C<bigrat> is just a thin wrapper around various modules of the Math::BigInt
174 family. Think of it as the head of the family, who runs the shop, and orders
175 the others to do the work.
176
177 The following modules are currently used by bignum:
178
179         Math::BigInt::Lite      (for speed, and only if it is loadable)
180         Math::BigInt
181         Math::BigFloat
182         Math::BigRat
183
184 =head2 MATH LIBRARY
185
186 Math with the numbers is done (by default) by a module called
187 Math::BigInt::Calc. This is equivalent to saying:
188
189         use bigrat lib => 'Calc';
190
191 You can change this by using:
192
193         use bigrat lib => 'BitVect';
194
195 The following would first try to find Math::BigInt::Foo, then
196 Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
197
198         use bigrat lib => 'Foo,Math::BigInt::Bar';
199
200 Please see respective module documentation for further details.
201
202 =head2 SIGN
203
204 The sign is either '+', '-', 'NaN', '+inf' or '-inf' and stored seperately.
205
206 A sign of 'NaN' is used to represent the result when input arguments are not
207 numbers or as a result of 0/0. '+inf' and '-inf' represent plus respectively
208 minus infinity. You will get '+inf' when dividing a positive number by 0, and
209 '-inf' when dividing any negative number by 0.
210
211 =head2 METHODS
212
213 Since all numbers are not objects, you can use all functions that are part of
214 the BigInt or BigFloat API. It is wise to use only the bxxx() notation, and not
215 the fxxx() notation, though. This makes you independed on the fact that the
216 underlying object might morph into a different class than BigFloat.
217
218 =head1 EXAMPLES
219  
220         perl -Mbigrat -le 'print sqrt(33)'
221         perl -Mbigrat -le 'print 2*255'
222         perl -Mbigrat -le 'print 4.5+2*255'
223         perl -Mbigrat -le 'print 3/7 + 5/7 + 8/3'       
224         perl -Mbigrat -le 'print 12->is_odd()';
225
226 =head1 LICENSE
227
228 This program is free software; you may redistribute it and/or modify it under
229 the same terms as Perl itself.
230
231 =head1 SEE ALSO
232
233 Especially L<bignum>.
234
235 L<Math::BigFloat>, L<Math::BigInt>, L<Math::BigRat> and L<Math::Big> as well
236 as L<Math::BigInt::BitVect>, L<Math::BigInt::Pari> and  L<Math::BigInt::GMP>.
237
238 =head1 AUTHORS
239
240 (C) by Tels L<http://bloodgate.com/> in early 2002.
241
242 =cut