This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
new file for #17756
[perl5.git] / lib / bigint.pm
CommitLineData
126f3c5f
JH
1package bigint;
2require 5.005;
3
4$VERSION = '0.02';
5use Exporter;
6@ISA = qw( Exporter );
7@EXPORT_OK = qw( );
8
9use strict;
10use overload;
11
12##############################################################################
13
14# These are all alike, and thus faked by AUTOLOAD
15
16my @faked = qw/round_mode accuracy precision div_scale/;
17use vars qw/$VERSION $AUTOLOAD $_lite/; # _lite for testsuite
18
19sub 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 *{"bigint::$name"} = sub
30 {
31 my $self = shift;
32 no strict 'refs';
33 if (defined $_[0])
34 {
35 Math::BigInt->$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 bigint\-\>$name, not a valid method");
46 }
47
48sub upgrade
49 {
50 my $self = shift;
51 no strict 'refs';
52# if (defined $_[0])
53# {
54# $Math::BigInt::upgrade = $_[0];
55# }
56 return $Math::BigInt::upgrade;
57 }
58
59sub _constant
60 {
61 # this takes a floating point constant string and returns it truncated to
62 # integer. For instance, '4.5' => '4', '1.234e2' => '123' etc
63 my $float = shift;
64
65 # some simple cases first
66 return $float if ($float =~ /^[+-]?[0-9]+$/); # '+123','-1','0' etc
67 return $float
68 if ($float =~ /^[+-]?[0-9]+\.?[eE]\+?[0-9]+$/); # 123e2, 123.e+2
69 return '0' if ($float =~ /^[+-]?[0]*\.[0-9]+$/); # .2, 0.2, -.1
70 if ($float =~ /^[+-]?[0-9]+\.[0-9]*$/) # 1., 1.23, -1.2 etc
71 {
72 $float =~ s/\..*//;
73 return $float;
74 }
75 my ($mis,$miv,$mfv,$es,$ev) = Math::BigInt::_split(\$float);
76 return $float if !defined $mis; # doesn't look like a number to me
77 my $ec = int($$ev);
78 my $sign = $$mis; $sign = '' if $sign eq '+';
79 if ($$es eq '-')
80 {
81 # ignore fraction part entirely
82 if ($ec >= length($$miv)) # 123.23E-4
83 {
84 return '0';
85 }
86 return $sign . substr ($$miv,0,length($$miv)-$ec); # 1234.45E-2 = 12
87 }
88 # xE+y
89 if ($ec >= length($$mfv))
90 {
91 $ec -= length($$mfv);
92 return $sign.$$miv.$$mfv if $ec == 0; # 123.45E+2 => 12345
93 return $sign.$$miv.$$mfv.'E'.$ec; # 123.45e+3 => 12345e1
94 }
95 $mfv = substr($$mfv,0,$ec);
96 return $sign.$$miv.$mfv; # 123.45e+1 => 1234
97 }
98
99sub import
100 {
101 my $self = shift;
102
103 # some defaults
104 my $lib = 'Calc';
105
106 my @import = ( ':constant' ); # drive it w/ constant
107 my @a = @_; my $l = scalar @_; my $j = 0;
108 my ($ver,$trace); # version? trace?
109 my ($a,$p); # accuracy, precision
110 for ( my $i = 0; $i < $l ; $i++,$j++ )
111 {
112 if ($_[$i] =~ /^(l|lib)$/)
113 {
114 # this causes a different low lib to take care...
115 $lib = $_[$i+1] || '';
116 my $s = 2; $s = 1 if @a-$j < 2; # avoid "can not modify non-existant..."
117 splice @a, $j, $s; $j -= $s; $i++;
118 }
119 elsif ($_[$i] =~ /^(a|accuracy)$/)
120 {
121 $a = $_[$i+1];
122 my $s = 2; $s = 1 if @a-$j < 2; # avoid "can not modify non-existant..."
123 splice @a, $j, $s; $j -= $s; $i++;
124 }
125 elsif ($_[$i] =~ /^(p|precision)$/)
126 {
127 $p = $_[$i+1];
128 my $s = 2; $s = 1 if @a-$j < 2; # avoid "can not modify non-existant..."
129 splice @a, $j, $s; $j -= $s; $i++;
130 }
131 elsif ($_[$i] =~ /^(v|version)$/)
132 {
133 $ver = 1;
134 splice @a, $j, 1; $j --;
135 }
136 elsif ($_[$i] =~ /^(t|trace)$/)
137 {
138 $trace = 1;
139 splice @a, $j, 1; $j --;
140 }
141 else { die "unknown option $_[$i]"; }
142 }
143 my $class;
144 $_lite = 0; # using M::BI::L ?
145 if ($trace)
146 {
147 require Math::BigInt::Trace; $class = 'Math::BigInt::Trace';
126f3c5f
JH
148 }
149 else
150 {
151 # see if we can find Math::BigInt::Lite
152 if (!defined $a && !defined $p) # rounding won't work to well
153 {
154 eval 'require Math::BigInt::Lite;';
155 if ($@ eq '')
156 {
157 @import = ( ); # :constant in Lite, not MBI
158 Math::BigInt::Lite->import( ':constant' );
159 $_lite= 1; # signal okay
160 }
161 }
162 require Math::BigInt if $_lite == 0; # not already loaded?
163 $class = 'Math::BigInt'; # regardless of MBIL or not
164 }
165 # Math::BigInt::Trace or plain Math::BigInt
166 $class->import(@import, lib => $lib);
167
168 bigint->accuracy($a) if defined $a;
169 bigint->precision($p) if defined $p;
170 if ($ver)
171 {
172 print "bigint\t\t\t v$VERSION\n";
173 print "Math::BigInt::Lite\t v$Math::BigInt::Lite::VERSION\n" if $_lite;
174 print "Math::BigInt\t\t v$Math::BigInt::VERSION";
175 my $config = Math::BigInt->config();
176 print " lib => $config->{lib} v$config->{lib_version}\n";
177 exit;
178 }
179 # we take care of floating point constants, since BigFloat isn't available
180 # and BigInt doesn't like them:
181 overload::constant float => sub { Math::BigInt->new( _constant(shift) ); };
182 }
183
1841;
185
186__END__
187
188=head1 NAME
189
190bigint - Transparent big integer support for Perl
191
192=head1 SYNOPSIS
193
194 use bignt;
195
196 $x = 2 + 4.5,"\n"; # BigInt 6
197 print 2 ** 512; # really is what you think it is
198
199=head1 DESCRIPTION
200
201All operators (including basic math operations) are overloaded. Integer
202constants are created as proper BigInts.
203
204Floating point constants are truncated to integer. All results are also
205trunctaed.
206
207=head2 OPTIONS
208
209bigint recognizes some options that can be passed while loading it via use.
210The options can (currently) be either a single letter form, or the long form.
211The following options exist:
212
213=over 2
214
215=item a or accuracy
216
217This sets the accuracy for all math operations. The argument must be greater
218than or equal to zero. See Math::BigInt's bround() function for details.
219
220 perl -Mbigint=a,2 -le 'print 12345+1'
221
222=item p or precision
223
224This sets the precision for all math operations. The argument can be any
225integer. Negative values mean a fixed number of digits after the dot, and
226are <B>ignored</B> since all operations happen in integer space.
227A positive value rounds to this digit left from the dot. 0 or 1 mean round to
228integer and are ignore like negative values.
229
230See Math::BigInt's bfround() function for details.
231
232 perl -Mbignum=p,5 -le 'print 123456789+123'
233
234=item t or trace
235
236This enables a trace mode and is primarily for debugging bigint or
237Math::BigInt.
238
239=item l or lib
240
241Load a different math lib, see L<MATH LIBRARY>.
242
243 perl -Mbigint=l,GMP -e 'print 2 ** 512'
244
245Currently there is no way to specify more than one library on the command
246line. This will be hopefully fixed soon ;)
247
248=item v or version
249
250This prints out the name and version of all modules used and then exits.
251
252 perl -Mbigint=v -e ''
253
254=head2 MATH LIBRARY
255
256Math with the numbers is done (by default) by a module called
257Math::BigInt::Calc. This is equivalent to saying:
258
259 use bigint lib => 'Calc';
260
261You can change this by using:
262
263 use bigint lib => 'BitVect';
264
265The following would first try to find Math::BigInt::Foo, then
266Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
267
268 use bigint lib => 'Foo,Math::BigInt::Bar';
269
270Please see respective module documentation for further details.
271
272=head2 INTERNAL FORMAT
273
274The numbers are stored as objects, and their internals might change at anytime,
275especially between math operations. The objects also might belong to different
276classes, like Math::BigInt, or Math::BigInt::Lite. Mixing them together, even
277with normal scalars is not extraordinary, but normal and expected.
278
279You should not depend on the internal format, all accesses must go through
280accessor methods. E.g. looking at $x->{sign} is not a bright idea since there
281is no guaranty that the object in question has such a hash key, nor is a hash
282underneath at all.
283
284=head2 SIGN
285
286The sign is either '+', '-', 'NaN', '+inf' or '-inf' and stored seperately.
287You can access it with the sign() method.
288
289A sign of 'NaN' is used to represent the result when input arguments are not
290numbers or as a result of 0/0. '+inf' and '-inf' represent plus respectively
291minus infinity. You will get '+inf' when dividing a positive number by 0, and
292'-inf' when dividing any negative number by 0.
293
294=head2 METHODS
295
296Since all numbers are now objects, you can use all functions that are part of
297the BigInt API. You can only use the bxxx() notation, and not the fxxx()
298notation, though.
299
300=head1 MODULES USED
301
302C<bigint> is just a thin wrapper around various modules of the Math::BigInt
303family. Think of it as the head of the family, who runs the shop, and orders
304the others to do the work.
305
306The following modules are currently used by bigint:
307
308 Math::BigInt::Lite (for speed, and only if it is loadable)
309 Math::BigInt
310
311=head1 EXAMPLES
312
313Some cool command line examples to impress the Python crowd ;) You might want
314to compare them to the results under -Mbignum or -Mbigrat:
315
316 perl -Mbigint -le 'print sqrt(33)'
317 perl -Mbigint -le 'print 2*255'
318 perl -Mbigint -le 'print 4.5+2*255'
319 perl -Mbigint -le 'print 3/7 + 5/7 + 8/3'
320 perl -Mbigint -le 'print 123->is_odd()'
321 perl -Mbigint -le 'print log(2)'
322 perl -Mbigint -le 'print 2 ** 0.5'
323 perl -Mbigint=a,65 -le 'print 2 ** 0.2'
324
325=head1 LICENSE
326
327This program is free software; you may redistribute it and/or modify it under
328the same terms as Perl itself.
329
330=head1 SEE ALSO
331
332Especially L<bigrat> as in C<perl -Mbigrat -le 'print 1/3+1/4'> and
333L<bignum> as in C<perl -Mbignum -le 'print sqrt(2)'>.
334
335L<Math::BigInt>, L<Math::BigRat> and L<Math::Big> as well
336as L<Math::BigInt::BitVect>, L<Math::BigInt::Pari> and L<Math::BigInt::GMP>.
337
338=head1 AUTHORS
339
340(C) by Tels L<http://bloodgate.com/> in early 2002.
341
342=cut