Rewrite bignum’s hex and oct overrides
[perl.git] / dist / bignum / lib / bigrat.pm
1 package bigrat;
2 use 5.006;
3
4 $VERSION = '0.30';
5 require Exporter;
6 @ISA            = qw( bigint );
7 @EXPORT_OK      = qw( PI e bpi bexp hex oct );
8 @EXPORT         = qw( inf NaN );
9
10 use strict;
11 use overload;
12 require bigint;         # no "use" to avoid callind import
13
14 ############################################################################## 
15
16 BEGIN 
17   {
18   *inf = \&bigint::inf;
19   *NaN = \&bigint::NaN;
20   *hex = \&bigint::hex;
21   *oct = \&bigint::oct;
22   }
23
24 # These are all alike, and thus faked by AUTOLOAD
25
26 my @faked = qw/round_mode accuracy precision div_scale/;
27 use vars qw/$VERSION $AUTOLOAD $_lite/;         # _lite for testsuite
28
29 sub AUTOLOAD
30   {
31   my $name = $AUTOLOAD;
32
33   $name =~ s/.*:://;    # split package
34   no strict 'refs';
35   foreach my $n (@faked)
36     {
37     if ($n eq $name)
38       {
39       *{"bigrat::$name"} = sub 
40         {
41         my $self = shift;
42         no strict 'refs';
43         if (defined $_[0])
44           {
45           Math::BigInt->$name($_[0]);
46           Math::BigFloat->$name($_[0]);
47           return Math::BigRat->$name($_[0]);
48           }
49         return Math::BigInt->$name();
50         };
51       return &$name;
52       }
53     }
54  
55   # delayed load of Carp and avoid recursion
56   require Carp;
57   Carp::croak ("Can't call bigrat\-\>$name, not a valid method");
58   }
59
60 sub unimport
61   {
62   $^H{bigrat} = undef;                                  # no longer in effect
63   overload::remove_constant('binary','','float','','integer');
64   }
65
66 sub in_effect
67   {
68   my $level = shift || 0;
69   my $hinthash = (caller($level))[10];
70   $hinthash->{bigrat};
71   }
72
73 #############################################################################
74
75 sub import 
76   {
77   my $self = shift;
78
79   # see also bignum->import() for additional comments
80
81   $^H{bigrat} = 1;                                      # we are in effect
82
83   # for newer Perls always override hex() and oct() with a lexical version:
84   if ($] > 5.009004)
85     {
86     bigint::_override();
87     }
88   # some defaults
89   my $lib = ''; my $lib_kind = 'try'; my $upgrade = 'Math::BigFloat';
90
91   my @import = ( ':constant' );                         # drive it w/ constant
92   my @a = @_; my $l = scalar @_; my $j = 0;
93   my ($a,$p);
94   my ($ver,$trace);                                     # version? trace?
95   for ( my $i = 0; $i < $l ; $i++,$j++ )
96     {
97     if ($_[$i] eq 'upgrade')
98       {
99       # this causes upgrading
100       $upgrade = $_[$i+1];              # or undef to disable
101       my $s = 2; $s = 1 if @a-$j < 2;   # avoid "can not modify non-existent..."
102       splice @a, $j, $s; $j -= $s;
103       }
104     elsif ($_[$i] =~ /^(l|lib|try|only)$/)
105       {
106       # this causes a different low lib to take care...
107       $lib_kind = $1; $lib_kind = 'lib' if $lib_kind eq 'l';
108       $lib = $_[$i+1] || '';
109       my $s = 2; $s = 1 if @a-$j < 2;   # avoid "can not modify non-existent..."
110       splice @a, $j, $s; $j -= $s; $i++;
111       }
112     elsif ($_[$i] =~ /^(a|accuracy)$/)
113       {
114       $a = $_[$i+1];
115       my $s = 2; $s = 1 if @a-$j < 2;   # avoid "can not modify non-existent..."
116       splice @a, $j, $s; $j -= $s; $i++;
117       }
118     elsif ($_[$i] =~ /^(p|precision)$/)
119       {
120       $p = $_[$i+1];
121       my $s = 2; $s = 1 if @a-$j < 2;   # avoid "can not modify non-existent..."
122       splice @a, $j, $s; $j -= $s; $i++;
123       }
124     elsif ($_[$i] =~ /^(v|version)$/)
125       {
126       $ver = 1;
127       splice @a, $j, 1; $j --;
128       }
129     elsif ($_[$i] =~ /^(t|trace)$/)
130       {
131       $trace = 1;
132       splice @a, $j, 1; $j --;
133       }
134     elsif ($_[$i] !~ /^(PI|e|bpi|bexp|hex|oct)\z/)
135       {
136       die ("unknown option $_[$i]");
137       }
138     }
139   my $class;
140   $_lite = 0;                                   # using M::BI::L ?
141   if ($trace)
142     {
143     require Math::BigInt::Trace; $class = 'Math::BigInt::Trace';
144     $upgrade = 'Math::BigFloat::Trace';
145     }
146   else
147     {
148     # see if we can find Math::BigInt::Lite
149     if (!defined $a && !defined $p)             # rounding won't work to well
150       {
151       eval 'require Math::BigInt::Lite;';
152       if ($@ eq '')
153         {
154         @import = ( );                          # :constant in Lite, not MBI
155         Math::BigInt::Lite->import( ':constant' );
156         $_lite= 1;                              # signal okay
157         }
158       }
159     require Math::BigInt if $_lite == 0;        # not already loaded?
160     $class = 'Math::BigInt';                    # regardless of MBIL or not
161     }
162   push @import, $lib_kind => $lib if $lib ne ''; 
163   # Math::BigInt::Trace or plain Math::BigInt
164   $class->import(@import, upgrade => $upgrade);
165
166   require Math::BigFloat;
167   Math::BigFloat->import( upgrade => 'Math::BigRat', ':constant' );
168   require Math::BigRat;
169
170   bigrat->accuracy($a) if defined $a;
171   bigrat->precision($p) if defined $p;
172   if ($ver)
173     {
174     print "bigrat\t\t\t v$VERSION\n";
175     print "Math::BigInt::Lite\t v$Math::BigInt::Lite::VERSION\n" if $_lite;  
176     print "Math::BigInt\t\t v$Math::BigInt::VERSION";
177     my $config = Math::BigInt->config();
178     print " lib => $config->{lib} v$config->{lib_version}\n";
179     print "Math::BigFloat\t\t v$Math::BigFloat::VERSION\n";
180     print "Math::BigRat\t\t v$Math::BigRat::VERSION\n";
181     exit;
182     }
183
184   # Take care of octal/hexadecimal constants
185   overload::constant binary => sub { bigint::_binary_constant(shift) };
186
187   # if another big* was already loaded:
188   my ($package) = caller();
189
190   no strict 'refs';
191   if (!defined *{"${package}::inf"})
192     {
193     $self->export_to_level(1,$self,@a);           # export inf and NaN
194     }
195   }
196
197 sub PI () { Math::BigFloat->new('3.141592653589793238462643383279502884197'); }
198 sub e () { Math::BigFloat->new('2.718281828459045235360287471352662497757'); }
199
200 sub bpi ($) { local $Math::BigFloat::upgrade; Math::BigFloat::bpi(@_); }
201
202 sub bexp ($$)
203   {
204   local $Math::BigFloat::upgrade;
205   my $x = Math::BigFloat->new($_[0]); $x->bexp($_[1]);
206   }
207
208 1;
209
210 __END__
211
212 =head1 NAME
213
214 bigrat - Transparent BigNumber/BigRational support for Perl
215
216 =head1 SYNOPSIS
217
218   use bigrat;
219
220   print 2 + 4.5,"\n";                   # BigFloat 6.5
221   print 1/3 + 1/4,"\n";                 # produces 7/12
222
223   {
224     no bigrat;
225     print 1/3,"\n";                     # 0.33333...
226   }
227
228   # Import into current package:
229   use bigrat qw/hex oct/;
230   print hex("0x1234567890123490"),"\n";
231   print oct("01234567890123490"),"\n";
232
233 =head1 DESCRIPTION
234
235 All operators (including basic math operations) are overloaded. Integer and
236 floating-point constants are created as proper BigInts or BigFloats,
237 respectively.
238
239 Other than L<bignum>, this module upgrades to Math::BigRat, meaning that
240 instead of 2.5 you will get 2+1/2 as output.
241
242 =head2 Modules Used
243
244 C<bigrat> is just a thin wrapper around various modules of the Math::BigInt
245 family. Think of it as the head of the family, who runs the shop, and orders
246 the others to do the work.
247
248 The following modules are currently used by bignum:
249
250         Math::BigInt::Lite      (for speed, and only if it is loadable)
251         Math::BigInt
252         Math::BigFloat
253         Math::BigRat
254
255 =head2 Math Library
256
257 Math with the numbers is done (by default) by a module called
258 Math::BigInt::Calc. This is equivalent to saying:
259
260         use bigrat lib => 'Calc';
261
262 You can change this by using:
263
264         use bignum lib => 'GMP';
265
266 The following would first try to find Math::BigInt::Foo, then
267 Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
268
269         use bigrat lib => 'Foo,Math::BigInt::Bar';
270
271 Using C<lib> warns if none of the specified libraries can be found and
272 L<Math::BigInt> did fall back to one of the default libraries.
273 To suppress this warning, use C<try> instead:
274
275         use bignum try => 'GMP';
276
277 If you want the code to die instead of falling back, use C<only> instead:
278
279         use bignum only => 'GMP';
280
281 Please see respective module documentation for further details.
282
283 =head2 Sign
284
285 The sign is either '+', '-', 'NaN', '+inf' or '-inf'.
286
287 A sign of 'NaN' is used to represent the result when input arguments are not
288 numbers or as a result of 0/0. '+inf' and '-inf' represent plus respectively
289 minus infinity. You will get '+inf' when dividing a positive number by 0, and
290 '-inf' when dividing any negative number by 0.
291
292 =head2 Methods
293
294 Since all numbers are not objects, you can use all functions that are part of
295 the BigInt or BigFloat API. It is wise to use only the bxxx() notation, and not
296 the fxxx() notation, though. This makes you independent on the fact that the
297 underlying object might morph into a different class than BigFloat.
298
299 =over 2
300
301 =item inf()
302
303 A shortcut to return Math::BigInt->binf(). Useful because Perl does not always
304 handle bareword C<inf> properly.
305
306 =item NaN()
307
308 A shortcut to return Math::BigInt->bnan(). Useful because Perl does not always
309 handle bareword C<NaN> properly.
310
311 =item e
312
313         # perl -Mbigrat=e -wle 'print e'
314
315 Returns Euler's number C<e>, aka exp(1).
316
317 =item PI
318
319         # perl -Mbigrat=PI -wle 'print PI'
320
321 Returns PI.
322
323 =item bexp()
324
325         bexp($power,$accuracy);
326
327
328 Returns Euler's number C<e> raised to the appropriate power, to
329 the wanted accuracy.
330
331 Example:
332
333         # perl -Mbigrat=bexp -wle 'print bexp(1,80)'
334
335 =item bpi()
336
337         bpi($accuracy);
338
339 Returns PI to the wanted accuracy.
340
341 Example:
342
343         # perl -Mbigrat=bpi -wle 'print bpi(80)'
344
345 =item upgrade()
346
347 Return the class that numbers are upgraded to, is in fact returning
348 C<$Math::BigInt::upgrade>.
349
350 =item in_effect()
351
352         use bigrat;
353
354         print "in effect\n" if bigrat::in_effect;       # true
355         {
356           no bigrat;
357           print "in effect\n" if bigrat::in_effect;     # false
358         }
359
360 Returns true or false if C<bigrat> is in effect in the current scope.
361
362 This method only works on Perl v5.9.4 or later.
363
364 =back
365
366 =head2 MATH LIBRARY
367
368 Math with the numbers is done (by default) by a module called
369
370 =head2 Caveat
371
372 But a warning is in order. When using the following to make a copy of a number,
373 only a shallow copy will be made.
374
375         $x = 9; $y = $x;
376         $x = $y = 7;
377
378 If you want to make a real copy, use the following:
379
380         $y = $x->copy();
381
382 Using the copy or the original with overloaded math is okay, e.g. the
383 following work:
384
385         $x = 9; $y = $x;
386         print $x + 1, " ", $y,"\n";     # prints 10 9
387
388 but calling any method that modifies the number directly will result in
389 B<both> the original and the copy being destroyed:
390
391         $x = 9; $y = $x;
392         print $x->badd(1), " ", $y,"\n";        # prints 10 10
393
394         $x = 9; $y = $x;
395         print $x->binc(1), " ", $y,"\n";        # prints 10 10
396
397         $x = 9; $y = $x;
398         print $x->bmul(2), " ", $y,"\n";        # prints 18 18
399
400 Using methods that do not modify, but testthe contents works:
401
402         $x = 9; $y = $x;
403         $z = 9 if $x->is_zero();                # works fine
404
405 See the documentation about the copy constructor and C<=> in overload, as
406 well as the documentation in BigInt for further details.
407
408 =head2 Options
409
410 bignum recognizes some options that can be passed while loading it via use.
411 The options can (currently) be either a single letter form, or the long form.
412 The following options exist:
413
414 =over 2
415
416 =item a or accuracy
417
418 This sets the accuracy for all math operations. The argument must be greater
419 than or equal to zero. See Math::BigInt's bround() function for details.
420
421         perl -Mbigrat=a,50 -le 'print sqrt(20)'
422
423 Note that setting precision and accuracy at the same time is not possible.
424
425 =item p or precision
426
427 This sets the precision for all math operations. The argument can be any
428 integer. Negative values mean a fixed number of digits after the dot, while
429 a positive value rounds to this digit left from the dot. 0 or 1 mean round to
430 integer. See Math::BigInt's bfround() function for details.
431
432         perl -Mbigrat=p,-50 -le 'print sqrt(20)'
433
434 Note that setting precision and accuracy at the same time is not possible.
435
436 =item t or trace
437
438 This enables a trace mode and is primarily for debugging bignum or
439 Math::BigInt/Math::BigFloat.
440
441 =item l or lib
442
443 Load a different math lib, see L<MATH LIBRARY>.
444
445         perl -Mbigrat=l,GMP -e 'print 2 ** 512'
446
447 Currently there is no way to specify more than one library on the command
448 line. This means the following does not work:
449
450         perl -Mbignum=l,GMP,Pari -e 'print 2 ** 512'
451
452 This will be hopefully fixed soon ;)
453
454 =item hex
455
456 Override the built-in hex() method with a version that can handle big
457 numbers. This overrides it by exporting it to the current package. Under
458 Perl v5.10.0 and higher, this is not so necessary, as hex() is lexically
459 overridden in the current scope whenever the bigrat pragma is active.
460
461 =item oct
462
463 Override the built-in oct() method with a version that can handle big
464 numbers. This overrides it by exporting it to the current package. Under
465 Perl v5.10.0 and higher, this is not so necessary, as oct() is lexically
466 overridden in the current scope whenever the bigrat pragma is active.
467
468 =item v or version
469
470 This prints out the name and version of all modules used and then exits.
471
472         perl -Mbigrat=v
473
474 =back
475
476 =head1 CAVEATS
477
478 =over 2
479
480 =item in_effect()
481
482 This method only works on Perl v5.9.4 or later.
483
484 =item hex()/oct()
485
486 C<bigint> overrides these routines with versions that can also handle
487 big integer values. Under Perl prior to version v5.9.4, however, this
488 will not happen unless you specifically ask for it with the two
489 import tags "hex" and "oct" - and then it will be global and cannot be
490 disabled inside a scope with "no bigint":
491
492         use bigint qw/hex oct/;
493
494         print hex("0x1234567890123456");
495         {
496                 no bigint;
497                 print hex("0x1234567890123456");
498         }
499
500 The second call to hex() will warn about a non-portable constant.
501
502 Compare this to:
503
504         use bigint;
505
506         # will warn only under Perl older than v5.9.4
507         print hex("0x1234567890123456");
508
509 =back
510
511 =head1 EXAMPLES
512
513         perl -Mbigrat -le 'print sqrt(33)'
514         perl -Mbigrat -le 'print 2*255'
515         perl -Mbigrat -le 'print 4.5+2*255'
516         perl -Mbigrat -le 'print 3/7 + 5/7 + 8/3'
517         perl -Mbigrat -le 'print 12->is_odd()';
518         perl -Mbignum=l,GMP -le 'print 7 ** 7777'
519
520 =head1 LICENSE
521
522 This program is free software; you may redistribute it and/or modify it under
523 the same terms as Perl itself.
524
525 =head1 SEE ALSO
526
527 Especially L<bignum>.
528
529 L<Math::BigFloat>, L<Math::BigInt>, L<Math::BigRat> and L<Math::Big> as well
530 as L<Math::BigInt::BitVect>, L<Math::BigInt::Pari> and  L<Math::BigInt::GMP>.
531
532 =head1 AUTHORS
533
534 (C) by Tels L<http://bloodgate.com/> in early 2002 - 2007.
535
536 =cut