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