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