Upgrage to bignum-0.21 and Math-BigRat-0.19
[p5sagit/p5-mst-13.2.git] / lib / bigrat.pm
1 package bigrat;
2 use 5.006002;
3
4 $VERSION = '0.10';
5 require Exporter;
6 @ISA            = qw( Exporter );
7 @EXPORT_OK      = qw( ); 
8 @EXPORT         = qw( inf NaN ); 
9
10 use strict;
11 use overload;
12
13 ############################################################################## 
14
15 # These are all alike, and thus faked by AUTOLOAD
16
17 my @faked = qw/round_mode accuracy precision div_scale/;
18 use vars qw/$VERSION $AUTOLOAD $_lite/;         # _lite for testsuite
19
20 sub AUTOLOAD
21   {
22   my $name = $AUTOLOAD;
23
24   $name =~ s/.*:://;    # split package
25   no strict 'refs';
26   foreach my $n (@faked)
27     {
28     if ($n eq $name)
29       {
30       *{"bigrat::$name"} = sub 
31         {
32         my $self = shift;
33         no strict 'refs';
34         if (defined $_[0])
35           {
36           Math::BigInt->$name($_[0]);
37           Math::BigFloat->$name($_[0]);
38           return Math::BigRat->$name($_[0]);
39           }
40         return Math::BigInt->$name();
41         };
42       return &$name;
43       }
44     }
45  
46   # delayed load of Carp and avoid recursion
47   require Carp;
48   Carp::croak ("Can't call bigrat\-\>$name, not a valid method");
49   }
50
51 sub upgrade
52   {
53   my $self = shift;
54   no strict 'refs';
55 #  if (defined $_[0])
56 #    {
57 #    $Math::BigInt::upgrade = $_[0];
58 #    $Math::BigFloat::upgrade = $_[0];
59 #    }
60   $Math::BigInt::upgrade;
61   }
62
63 sub _binary_constant
64   {
65   # this takes a binary/hexadecimal/octal constant string and returns it
66   # as string suitable for new. Basically it converts octal to decimal, and
67   # passes every thing else unmodified back.
68   my $string = shift;
69
70   return Math::BigInt->new($string) if $string =~ /^0[bx]/;
71
72   # so it must be an octal constant
73   Math::BigInt->from_oct($string);
74   }
75
76 sub import 
77   {
78   my $self = shift;
79
80   # see also bignum->import() for additional comments
81
82   # some defaults
83   my $lib = ''; my $lib_kind = 'try'; my $upgrade = 'Math::BigFloat';
84
85   my @import = ( ':constant' );                         # drive it w/ constant
86   my @a = @_; my $l = scalar @_; my $j = 0;
87   my ($a,$p);
88   my ($ver,$trace);                                     # version? trace?
89   for ( my $i = 0; $i < $l ; $i++,$j++ )
90     {
91     if ($_[$i] eq 'upgrade')
92       {
93       # this causes upgrading
94       $upgrade = $_[$i+1];              # or undef to disable
95       my $s = 2; $s = 1 if @a-$j < 2;   # avoid "can not modify non-existant..."
96       splice @a, $j, $s; $j -= $s;
97       }
98     elsif ($_[$i] =~ /^(l|lib|try|only)$/)
99       {
100       # this causes a different low lib to take care...
101       $lib_kind = $1; $lib_kind = 'lib' if $lib_kind eq 'l';
102       $lib = $_[$i+1] || '';
103       my $s = 2; $s = 1 if @a-$j < 2;   # avoid "can not modify non-existant..."
104       splice @a, $j, $s; $j -= $s; $i++;
105       }
106     elsif ($_[$i] =~ /^(a|accuracy)$/)
107       {
108       $a = $_[$i+1];
109       my $s = 2; $s = 1 if @a-$j < 2;   # avoid "can not modify non-existant..."
110       splice @a, $j, $s; $j -= $s; $i++;
111       }
112     elsif ($_[$i] =~ /^(p|precision)$/)
113       {
114       $p = $_[$i+1];
115       my $s = 2; $s = 1 if @a-$j < 2;   # avoid "can not modify non-existant..."
116       splice @a, $j, $s; $j -= $s; $i++;
117       }
118     elsif ($_[$i] =~ /^(v|version)$/)
119       {
120       $ver = 1;
121       splice @a, $j, 1; $j --;
122       }
123     elsif ($_[$i] =~ /^(t|trace)$/)
124       {
125       $trace = 1;
126       splice @a, $j, 1; $j --;
127       }
128     else
129       {
130       die ("unknown option $_[$i]");
131       }
132     }
133   my $class;
134   $_lite = 0;                                   # using M::BI::L ?
135   if ($trace)
136     {
137     require Math::BigInt::Trace; $class = 'Math::BigInt::Trace';
138     $upgrade = 'Math::BigFloat::Trace';
139     }
140   else
141     {
142     # see if we can find Math::BigInt::Lite
143     if (!defined $a && !defined $p)             # rounding won't work to well
144       {
145       eval 'require Math::BigInt::Lite;';
146       if ($@ eq '')
147         {
148         @import = ( );                          # :constant in Lite, not MBI
149         Math::BigInt::Lite->import( ':constant' );
150         $_lite= 1;                              # signal okay
151         }
152       }
153     require Math::BigInt if $_lite == 0;        # not already loaded?
154     $class = 'Math::BigInt';                    # regardless of MBIL or not
155     }
156   push @import, $lib_kind => $lib if $lib ne ''; 
157   # Math::BigInt::Trace or plain Math::BigInt
158   $class->import(@import, upgrade => $upgrade);
159
160   require Math::BigFloat;
161   Math::BigFloat->import( upgrade => 'Math::BigRat', ':constant' );
162   require Math::BigRat;
163
164   bigrat->accuracy($a) if defined $a;
165   bigrat->precision($p) if defined $p;
166   if ($ver)
167     {
168     print "bigrat\t\t\t v$VERSION\n";
169     print "Math::BigInt::Lite\t v$Math::BigInt::Lite::VERSION\n" if $_lite;  
170     print "Math::BigInt\t\t v$Math::BigInt::VERSION";
171     my $config = Math::BigInt->config();
172     print " lib => $config->{lib} v$config->{lib_version}\n";
173     print "Math::BigFloat\t\t v$Math::BigFloat::VERSION\n";
174     print "Math::BigRat\t\t v$Math::BigRat::VERSION\n";
175     exit;
176     }
177
178   # Take care of octal/hexadecimal constants
179   overload::constant binary => sub { _binary_constant(shift) };
180
181   $self->export_to_level(1,$self,@a);           # export inf and NaN
182   }
183
184 sub inf () { Math::BigInt->binf(); }
185 sub NaN () { Math::BigInt->bnan(); }
186
187 1;
188
189 __END__
190
191 =head1 NAME
192
193 bigrat - Transparent BigNumber/BigRational support for Perl
194
195 =head1 SYNOPSIS
196
197   use bigrat;
198
199   $x = 2 + 4.5,"\n";                    # BigFloat 6.5
200   print 1/3 + 1/4,"\n";                 # produces 7/12
201
202 =head1 DESCRIPTION
203
204 All operators (including basic math operations) are overloaded. Integer and
205 floating-point constants are created as proper BigInts or BigFloats,
206 respectively.
207
208 Other than L<bignum>, this module upgrades to Math::BigRat, meaning that
209 instead of 2.5 you will get 2+1/2 as output.
210
211 =head2 Modules Used
212
213 C<bigrat> is just a thin wrapper around various modules of the Math::BigInt
214 family. Think of it as the head of the family, who runs the shop, and orders
215 the others to do the work.
216
217 The following modules are currently used by bignum:
218
219         Math::BigInt::Lite      (for speed, and only if it is loadable)
220         Math::BigInt
221         Math::BigFloat
222         Math::BigRat
223
224 =head2 Math Library
225
226 Math with the numbers is done (by default) by a module called
227 Math::BigInt::Calc. This is equivalent to saying:
228
229         use bigrat lib => 'Calc';
230
231 You can change this by using:
232
233         use bignum lib => 'GMP';
234
235 The following would first try to find Math::BigInt::Foo, then
236 Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
237
238         use bigrat lib => 'Foo,Math::BigInt::Bar';
239
240 Using C<lib> warns if none of the specified libraries can be found and
241 L<Math::BigInt> did fall back to one of the default libraries.
242 To supress this warning, use C<try> instead:
243
244         use bignum try => 'GMP';
245
246 If you want the code to die instead of falling back, use C<only> instead:
247
248         use bignum only => 'GMP';
249
250 Please see respective module documentation for further details.
251
252 =head2 Sign
253
254 The sign is either '+', '-', 'NaN', '+inf' or '-inf'.
255
256 A sign of 'NaN' is used to represent the result when input arguments are not
257 numbers or as a result of 0/0. '+inf' and '-inf' represent plus respectively
258 minus infinity. You will get '+inf' when dividing a positive number by 0, and
259 '-inf' when dividing any negative number by 0.
260
261 =head2 Methods
262
263 Since all numbers are not objects, you can use all functions that are part of
264 the BigInt or BigFloat API. It is wise to use only the bxxx() notation, and not
265 the fxxx() notation, though. This makes you independed on the fact that the
266 underlying object might morph into a different class than BigFloat.
267
268 =over 2
269
270 =item inf()
271
272 A shortcut to return Math::BigInt->binf(). Useful because Perl does not always
273 handle bareword C<inf> properly.
274
275 =item NaN()
276
277 A shortcut to return Math::BigInt->bnan(). Useful because Perl does not always
278 handle bareword C<NaN> properly.
279
280 =item upgrade()
281
282 Return the class that numbers are upgraded to, is in fact returning
283 C<$Math::BigInt::upgrade>.
284
285 =back
286
287 =head2 MATH LIBRARY
288
289 Math with the numbers is done (by default) by a module called
290
291 =head2 Cavaet
292
293 But a warning is in order. When using the following to make a copy of a number,
294 only a shallow copy will be made.
295
296         $x = 9; $y = $x;
297         $x = $y = 7;
298
299 If you want to make a real copy, use the following:
300
301         $y = $x->copy();
302
303 Using the copy or the original with overloaded math is okay, e.g. the
304 following work:
305
306         $x = 9; $y = $x;
307         print $x + 1, " ", $y,"\n";     # prints 10 9
308
309 but calling any method that modifies the number directly will result in
310 B<both> the original and the copy being destroyed:
311
312         $x = 9; $y = $x;
313         print $x->badd(1), " ", $y,"\n";        # prints 10 10
314
315         $x = 9; $y = $x;
316         print $x->binc(1), " ", $y,"\n";        # prints 10 10
317
318         $x = 9; $y = $x;
319         print $x->bmul(2), " ", $y,"\n";        # prints 18 18
320
321 Using methods that do not modify, but testthe contents works:
322
323         $x = 9; $y = $x;
324         $z = 9 if $x->is_zero();                # works fine
325
326 See the documentation about the copy constructor and C<=> in overload, as
327 well as the documentation in BigInt for further details.
328
329 =head2 Options
330
331 bignum recognizes some options that can be passed while loading it via use.
332 The options can (currently) be either a single letter form, or the long form.
333 The following options exist:
334
335 =over 2
336
337 =item a or accuracy
338
339 This sets the accuracy for all math operations. The argument must be greater
340 than or equal to zero. See Math::BigInt's bround() function for details.
341
342         perl -Mbigrat=a,50 -le 'print sqrt(20)'
343
344 Note that setting precision and accurary at the same time is not possible.
345
346 =item p or precision
347
348 This sets the precision for all math operations. The argument can be any
349 integer. Negative values mean a fixed number of digits after the dot, while
350 a positive value rounds to this digit left from the dot. 0 or 1 mean round to
351 integer. See Math::BigInt's bfround() function for details.
352
353         perl -Mbigrat=p,-50 -le 'print sqrt(20)'
354
355 Note that setting precision and accurary at the same time is not possible.
356
357 =item t or trace
358
359 This enables a trace mode and is primarily for debugging bignum or
360 Math::BigInt/Math::BigFloat.
361
362 =item l or lib
363
364 Load a different math lib, see L<MATH LIBRARY>.
365
366         perl -Mbigrat=l,GMP -e 'print 2 ** 512'
367
368 Currently there is no way to specify more than one library on the command
369 line. This means the following does not work:
370
371         perl -Mbignum=l,GMP,Pari -e 'print 2 ** 512'
372
373 This will be hopefully fixed soon ;)
374
375 =item v or version
376
377 This prints out the name and version of all modules used and then exits.
378
379         perl -Mbigrat=v
380
381 =back
382
383 =head1 EXAMPLES
384  
385         perl -Mbigrat -le 'print sqrt(33)'
386         perl -Mbigrat -le 'print 2*255'
387         perl -Mbigrat -le 'print 4.5+2*255'
388         perl -Mbigrat -le 'print 3/7 + 5/7 + 8/3'       
389         perl -Mbigrat -le 'print 12->is_odd()';
390         perl -Mbignum=l,GMP -le 'print 7 ** 7777'
391
392 =head1 LICENSE
393
394 This program is free software; you may redistribute it and/or modify it under
395 the same terms as Perl itself.
396
397 =head1 SEE ALSO
398
399 Especially L<bignum>.
400
401 L<Math::BigFloat>, L<Math::BigInt>, L<Math::BigRat> and L<Math::Big> as well
402 as L<Math::BigInt::BitVect>, L<Math::BigInt::Pari> and  L<Math::BigInt::GMP>.
403
404 =head1 AUTHORS
405
406 (C) by Tels L<http://bloodgate.com/> in early 2002 - 2007.
407
408 =cut