Commit | Line | Data |
---|---|---|
13a12e00 JH |
1 | package Math::BigInt; |
2 | ||
3 | # | |
4 | # "Mike had an infinite amount to do and a negative amount of time in which | |
5 | # to do it." - Before and After | |
6 | # | |
7 | ||
58cde26e | 8 | # The following hash values are used: |
9681bfa6 | 9 | # value: unsigned int with actual value (as a Math::BigInt::Calc or similar) |
58cde26e JH |
10 | # sign : +,-,NaN,+inf,-inf |
11 | # _a : accuracy | |
12 | # _p : precision | |
0716bf9b | 13 | # _f : flags, used by MBF to flag parts of a float as untouchable |
b4f14daa | 14 | |
574bacfe JH |
15 | # Remember not to take shortcuts ala $xs = $x->{value}; $CALC->foo($xs); since |
16 | # underlying lib might change the reference! | |
17 | ||
58cde26e | 18 | my $class = "Math::BigInt"; |
0d71d61a | 19 | use 5.006002; |
58cde26e | 20 | |
80df1b84 | 21 | $VERSION = '1.996'; |
b68b7ab1 | 22 | |
233f7bc0 T |
23 | @ISA = qw(Exporter); |
24 | @EXPORT_OK = qw(objectify bgcd blcm); | |
b68b7ab1 | 25 | |
b282a552 T |
26 | # _trap_inf and _trap_nan are internal and should never be accessed from the |
27 | # outside | |
28 | use vars qw/$round_mode $accuracy $precision $div_scale $rnd_mode | |
29 | $upgrade $downgrade $_trap_nan $_trap_inf/; | |
58cde26e JH |
30 | use strict; |
31 | ||
32 | # Inside overload, the first arg is always an object. If the original code had | |
df0693ed | 33 | # it reversed (like $x = 2 * $y), then the third parameter is true. |
091c87b1 T |
34 | # In some cases (like add, $x = $x + 2 is the same as $x = 2 + $x) this makes |
35 | # no difference, but in some cases it does. | |
58cde26e JH |
36 | |
37 | # For overloaded ops with only one argument we simple use $_[0]->copy() to | |
38 | # preserve the argument. | |
39 | ||
40 | # Thus inheritance of overload operators becomes possible and transparent for | |
41 | # our subclasses without the need to repeat the entire overload section there. | |
a0d0e21e | 42 | |
a5f75d66 | 43 | use overload |
58cde26e JH |
44 | '=' => sub { $_[0]->copy(); }, |
45 | ||
58cde26e JH |
46 | # some shortcuts for speed (assumes that reversed order of arguments is routed |
47 | # to normal '+' and we thus can always modify first arg. If this is changed, | |
48 | # this breaks and must be adjusted.) | |
49 | '+=' => sub { $_[0]->badd($_[1]); }, | |
50 | '-=' => sub { $_[0]->bsub($_[1]); }, | |
51 | '*=' => sub { $_[0]->bmul($_[1]); }, | |
52 | '/=' => sub { scalar $_[0]->bdiv($_[1]); }, | |
027dc388 JH |
53 | '%=' => sub { $_[0]->bmod($_[1]); }, |
54 | '^=' => sub { $_[0]->bxor($_[1]); }, | |
55 | '&=' => sub { $_[0]->band($_[1]); }, | |
56 | '|=' => sub { $_[0]->bior($_[1]); }, | |
58cde26e | 57 | |
b68b7ab1 | 58 | '**=' => sub { $_[0]->bpow($_[1]); }, |
2d2b2744 T |
59 | '<<=' => sub { $_[0]->blsft($_[1]); }, |
60 | '>>=' => sub { $_[0]->brsft($_[1]); }, | |
61 | ||
b3abae2a | 62 | # not supported by Perl yet |
027dc388 JH |
63 | '..' => \&_pointpoint, |
64 | ||
a0ac753d | 65 | '<=>' => sub { my $rc = $_[2] ? |
bd05a461 | 66 | ref($_[0])->bcmp($_[1],$_[0]) : |
a0ac753d T |
67 | $_[0]->bcmp($_[1]); |
68 | $rc = 1 unless defined $rc; | |
69 | $rc <=> 0; | |
70 | }, | |
71 | # we need '>=' to get things like "1 >= NaN" right: | |
72 | '>=' => sub { my $rc = $_[2] ? | |
73 | ref($_[0])->bcmp($_[1],$_[0]) : | |
74 | $_[0]->bcmp($_[1]); | |
75 | # if there was a NaN involved, return false | |
76 | return '' unless defined $rc; | |
77 | $rc >= 0; | |
78 | }, | |
027dc388 | 79 | 'cmp' => sub { |
58cde26e | 80 | $_[2] ? |
b3abae2a JH |
81 | "$_[1]" cmp $_[0]->bstr() : |
82 | $_[0]->bstr() cmp "$_[1]" }, | |
58cde26e | 83 | |
60a1aa19 T |
84 | 'cos' => sub { $_[0]->copy->bcos(); }, |
85 | 'sin' => sub { $_[0]->copy->bsin(); }, | |
a87115f0 | 86 | 'atan2' => sub { $_[2] ? |
20e2035c T |
87 | ref($_[0])->new($_[1])->batan2($_[0]) : |
88 | $_[0]->copy()->batan2($_[1]) }, | |
091c87b1 | 89 | |
b68b7ab1 T |
90 | # are not yet overloadable |
91 | #'hex' => sub { print "hex"; $_[0]; }, | |
92 | #'oct' => sub { print "oct"; $_[0]; }, | |
93 | ||
a0ac753d T |
94 | # log(N) is log(N, e), where e is Euler's number |
95 | 'log' => sub { $_[0]->copy()->blog($_[1], undef); }, | |
7d193e39 | 96 | 'exp' => sub { $_[0]->copy()->bexp($_[1]); }, |
58cde26e JH |
97 | 'int' => sub { $_[0]->copy(); }, |
98 | 'neg' => sub { $_[0]->copy()->bneg(); }, | |
99 | 'abs' => sub { $_[0]->copy()->babs(); }, | |
b3abae2a | 100 | 'sqrt' => sub { $_[0]->copy()->bsqrt(); }, |
58cde26e JH |
101 | '~' => sub { $_[0]->copy()->bnot(); }, |
102 | ||
12fc2493 | 103 | # for subtract it's a bit tricky to not modify b: b-a => -a+b |
091c87b1 | 104 | '-' => sub { my $c = $_[0]->copy; $_[2] ? |
a87115f0 RGS |
105 | $c->bneg()->badd( $_[1]) : |
106 | $c->bsub( $_[1]) }, | |
091c87b1 T |
107 | '+' => sub { $_[0]->copy()->badd($_[1]); }, |
108 | '*' => sub { $_[0]->copy()->bmul($_[1]); }, | |
109 | ||
110 | '/' => sub { | |
111 | $_[2] ? ref($_[0])->new($_[1])->bdiv($_[0]) : $_[0]->copy->bdiv($_[1]); | |
112 | }, | |
113 | '%' => sub { | |
114 | $_[2] ? ref($_[0])->new($_[1])->bmod($_[0]) : $_[0]->copy->bmod($_[1]); | |
115 | }, | |
116 | '**' => sub { | |
117 | $_[2] ? ref($_[0])->new($_[1])->bpow($_[0]) : $_[0]->copy->bpow($_[1]); | |
118 | }, | |
119 | '<<' => sub { | |
120 | $_[2] ? ref($_[0])->new($_[1])->blsft($_[0]) : $_[0]->copy->blsft($_[1]); | |
121 | }, | |
122 | '>>' => sub { | |
123 | $_[2] ? ref($_[0])->new($_[1])->brsft($_[0]) : $_[0]->copy->brsft($_[1]); | |
124 | }, | |
125 | '&' => sub { | |
126 | $_[2] ? ref($_[0])->new($_[1])->band($_[0]) : $_[0]->copy->band($_[1]); | |
127 | }, | |
128 | '|' => sub { | |
129 | $_[2] ? ref($_[0])->new($_[1])->bior($_[0]) : $_[0]->copy->bior($_[1]); | |
130 | }, | |
131 | '^' => sub { | |
132 | $_[2] ? ref($_[0])->new($_[1])->bxor($_[0]) : $_[0]->copy->bxor($_[1]); | |
133 | }, | |
134 | ||
135 | # can modify arg of ++ and --, so avoid a copy() for speed, but don't | |
136 | # use $_[0]->bone(), it would modify $_[0] to be 1! | |
58cde26e JH |
137 | '++' => sub { $_[0]->binc() }, |
138 | '--' => sub { $_[0]->bdec() }, | |
139 | ||
140 | # if overloaded, O(1) instead of O(N) and twice as fast for small numbers | |
141 | 'bool' => sub { | |
142 | # this kludge is needed for perl prior 5.6.0 since returning 0 here fails :-/ | |
091c87b1 | 143 | # v5.6.1 dumps on this: return !$_[0]->is_zero() || undef; :-( |
3a427a11 RGS |
144 | my $t = undef; |
145 | $t = 1 if !$_[0]->is_zero(); | |
b3abae2a | 146 | $t; |
58cde26e | 147 | }, |
a0d0e21e | 148 | |
027dc388 JH |
149 | # the original qw() does not work with the TIESCALAR below, why? |
150 | # Order of arguments unsignificant | |
151 | '""' => sub { $_[0]->bstr(); }, | |
152 | '0+' => sub { $_[0]->numify(); } | |
a5f75d66 | 153 | ; |
a0d0e21e | 154 | |
58cde26e JH |
155 | ############################################################################## |
156 | # global constants, flags and accessory | |
157 | ||
b68b7ab1 T |
158 | # These vars are public, but their direct usage is not recommended, use the |
159 | # accessor methods instead | |
0716bf9b | 160 | |
7b29e1e6 | 161 | $round_mode = 'even'; # one of 'even', 'odd', '+inf', '-inf', 'zero', 'trunc' or 'common' |
ee15d750 JH |
162 | $accuracy = undef; |
163 | $precision = undef; | |
164 | $div_scale = 40; | |
58cde26e | 165 | |
b3abae2a JH |
166 | $upgrade = undef; # default is no upgrade |
167 | $downgrade = undef; # default is no downgrade | |
168 | ||
b68b7ab1 | 169 | # These are internally, and not to be used from the outside at all |
990fb837 RGS |
170 | |
171 | $_trap_nan = 0; # are NaNs ok? set w/ config() | |
172 | $_trap_inf = 0; # are infs ok? set w/ config() | |
173 | my $nan = 'NaN'; # constants for easier life | |
174 | ||
a90064ab PJA |
175 | my $CALC = 'Math::BigInt::Calc'; # module to do the low level math |
176 | # default is Calc.pm | |
990fb837 RGS |
177 | my $IMPORT = 0; # was import() called yet? |
178 | # used to make require work | |
9b924220 RGS |
179 | my %WARN; # warn only once for low-level libs |
180 | my %CAN; # cache for $CALC->can(...) | |
b68b7ab1 | 181 | my %CALLBACKS; # callbacks to notify on lib loads |
b282a552 | 182 | my $EMU_LIB = 'Math/BigInt/CalcEmu.pm'; # emulate low-level math |
b282a552 | 183 | |
027dc388 JH |
184 | ############################################################################## |
185 | # the old code had $rnd_mode, so we need to support it, too | |
186 | ||
187 | $rnd_mode = 'even'; | |
188 | sub TIESCALAR { my ($class) = @_; bless \$round_mode, $class; } | |
189 | sub FETCH { return $round_mode; } | |
190 | sub STORE { $rnd_mode = $_[0]->round_mode($_[1]); } | |
191 | ||
b282a552 T |
192 | BEGIN |
193 | { | |
194 | # tie to enable $rnd_mode to work transparently | |
195 | tie $rnd_mode, 'Math::BigInt'; | |
196 | ||
197 | # set up some handy alias names | |
198 | *as_int = \&as_number; | |
199 | *is_pos = \&is_positive; | |
200 | *is_neg = \&is_negative; | |
201 | } | |
027dc388 JH |
202 | |
203 | ############################################################################## | |
204 | ||
58cde26e JH |
205 | sub round_mode |
206 | { | |
ee15d750 | 207 | no strict 'refs'; |
58cde26e | 208 | # make Class->round_mode() work |
ee15d750 JH |
209 | my $self = shift; |
210 | my $class = ref($self) || $self || __PACKAGE__; | |
58cde26e JH |
211 | if (defined $_[0]) |
212 | { | |
213 | my $m = shift; | |
7b29e1e6 | 214 | if ($m !~ /^(even|odd|\+inf|\-inf|zero|trunc|common)$/) |
990fb837 RGS |
215 | { |
216 | require Carp; Carp::croak ("Unknown round mode '$m'"); | |
217 | } | |
b3abae2a | 218 | return ${"${class}::round_mode"} = $m; |
58cde26e | 219 | } |
990fb837 | 220 | ${"${class}::round_mode"}; |
ee15d750 JH |
221 | } |
222 | ||
b3abae2a JH |
223 | sub upgrade |
224 | { | |
225 | no strict 'refs'; | |
28df3e88 | 226 | # make Class->upgrade() work |
b3abae2a JH |
227 | my $self = shift; |
228 | my $class = ref($self) || $self || __PACKAGE__; | |
9393ace2 JH |
229 | # need to set new value? |
230 | if (@_ > 0) | |
b3abae2a | 231 | { |
b68b7ab1 | 232 | return ${"${class}::upgrade"} = $_[0]; |
b3abae2a | 233 | } |
990fb837 | 234 | ${"${class}::upgrade"}; |
b3abae2a JH |
235 | } |
236 | ||
28df3e88 JH |
237 | sub downgrade |
238 | { | |
239 | no strict 'refs'; | |
240 | # make Class->downgrade() work | |
241 | my $self = shift; | |
242 | my $class = ref($self) || $self || __PACKAGE__; | |
9393ace2 JH |
243 | # need to set new value? |
244 | if (@_ > 0) | |
28df3e88 | 245 | { |
b68b7ab1 | 246 | return ${"${class}::downgrade"} = $_[0]; |
28df3e88 | 247 | } |
990fb837 | 248 | ${"${class}::downgrade"}; |
28df3e88 JH |
249 | } |
250 | ||
ee15d750 JH |
251 | sub div_scale |
252 | { | |
253 | no strict 'refs'; | |
990fb837 | 254 | # make Class->div_scale() work |
ee15d750 JH |
255 | my $self = shift; |
256 | my $class = ref($self) || $self || __PACKAGE__; | |
257 | if (defined $_[0]) | |
258 | { | |
990fb837 RGS |
259 | if ($_[0] < 0) |
260 | { | |
261 | require Carp; Carp::croak ('div_scale must be greater than zero'); | |
262 | } | |
b68b7ab1 | 263 | ${"${class}::div_scale"} = $_[0]; |
ee15d750 | 264 | } |
990fb837 | 265 | ${"${class}::div_scale"}; |
58cde26e JH |
266 | } |
267 | ||
268 | sub accuracy | |
269 | { | |
ee15d750 JH |
270 | # $x->accuracy($a); ref($x) $a |
271 | # $x->accuracy(); ref($x) | |
272 | # Class->accuracy(); class | |
273 | # Class->accuracy($a); class $a | |
58cde26e | 274 | |
ee15d750 JH |
275 | my $x = shift; |
276 | my $class = ref($x) || $x || __PACKAGE__; | |
58cde26e | 277 | |
ee15d750 JH |
278 | no strict 'refs'; |
279 | # need to set new value? | |
58cde26e JH |
280 | if (@_ > 0) |
281 | { | |
ee15d750 | 282 | my $a = shift; |
990fb837 RGS |
283 | # convert objects to scalars to avoid deep recursion. If object doesn't |
284 | # have numify(), then hopefully it will have overloading for int() and | |
285 | # boolean test without wandering into a deep recursion path... | |
286 | $a = $a->numify() if ref($a) && $a->can('numify'); | |
287 | ||
288 | if (defined $a) | |
289 | { | |
290 | # also croak on non-numerical | |
291 | if (!$a || $a <= 0) | |
292 | { | |
293 | require Carp; | |
d5351619 | 294 | Carp::croak ('Argument to accuracy must be greater than zero'); |
990fb837 RGS |
295 | } |
296 | if (int($a) != $a) | |
297 | { | |
d5351619 T |
298 | require Carp; |
299 | Carp::croak ('Argument to accuracy must be an integer'); | |
990fb837 RGS |
300 | } |
301 | } | |
ee15d750 JH |
302 | if (ref($x)) |
303 | { | |
304 | # $object->accuracy() or fallback to global | |
ef9466ea T |
305 | $x->bround($a) if $a; # not for undef, 0 |
306 | $x->{_a} = $a; # set/overwrite, even if not rounded | |
307 | delete $x->{_p}; # clear P | |
990fb837 | 308 | $a = ${"${class}::accuracy"} unless defined $a; # proper return value |
ee15d750 JH |
309 | } |
310 | else | |
311 | { | |
ef9466ea T |
312 | ${"${class}::accuracy"} = $a; # set global A |
313 | ${"${class}::precision"} = undef; # clear global P | |
ee15d750 | 314 | } |
ef9466ea | 315 | return $a; # shortcut |
ee15d750 JH |
316 | } |
317 | ||
b68b7ab1 | 318 | my $a; |
f9a08e12 | 319 | # $object->accuracy() or fallback to global |
b68b7ab1 | 320 | $a = $x->{_a} if ref($x); |
f9a08e12 | 321 | # but don't return global undef, when $x's accuracy is 0! |
b68b7ab1 T |
322 | $a = ${"${class}::accuracy"} if !defined $a; |
323 | $a; | |
990fb837 | 324 | } |
58cde26e JH |
325 | |
326 | sub precision | |
327 | { | |
ee15d750 JH |
328 | # $x->precision($p); ref($x) $p |
329 | # $x->precision(); ref($x) | |
330 | # Class->precision(); class | |
331 | # Class->precision($p); class $p | |
58cde26e | 332 | |
ee15d750 JH |
333 | my $x = shift; |
334 | my $class = ref($x) || $x || __PACKAGE__; | |
58cde26e | 335 | |
ee15d750 | 336 | no strict 'refs'; |
58cde26e JH |
337 | if (@_ > 0) |
338 | { | |
ee15d750 | 339 | my $p = shift; |
990fb837 RGS |
340 | # convert objects to scalars to avoid deep recursion. If object doesn't |
341 | # have numify(), then hopefully it will have overloading for int() and | |
342 | # boolean test without wandering into a deep recursion path... | |
343 | $p = $p->numify() if ref($p) && $p->can('numify'); | |
344 | if ((defined $p) && (int($p) != $p)) | |
345 | { | |
346 | require Carp; Carp::croak ('Argument to precision must be an integer'); | |
347 | } | |
ee15d750 JH |
348 | if (ref($x)) |
349 | { | |
350 | # $object->precision() or fallback to global | |
ef9466ea T |
351 | $x->bfround($p) if $p; # not for undef, 0 |
352 | $x->{_p} = $p; # set/overwrite, even if not rounded | |
353 | delete $x->{_a}; # clear A | |
990fb837 | 354 | $p = ${"${class}::precision"} unless defined $p; # proper return value |
ee15d750 JH |
355 | } |
356 | else | |
357 | { | |
ef9466ea T |
358 | ${"${class}::precision"} = $p; # set global P |
359 | ${"${class}::accuracy"} = undef; # clear global A | |
ee15d750 | 360 | } |
ef9466ea | 361 | return $p; # shortcut |
58cde26e | 362 | } |
ee15d750 | 363 | |
b68b7ab1 | 364 | my $p; |
f9a08e12 | 365 | # $object->precision() or fallback to global |
b68b7ab1 | 366 | $p = $x->{_p} if ref($x); |
f9a08e12 | 367 | # but don't return global undef, when $x's precision is 0! |
b68b7ab1 T |
368 | $p = ${"${class}::precision"} if !defined $p; |
369 | $p; | |
990fb837 | 370 | } |
58cde26e | 371 | |
b3abae2a JH |
372 | sub config |
373 | { | |
990fb837 | 374 | # return (or set) configuration data as hash ref |
b3abae2a JH |
375 | my $class = shift || 'Math::BigInt'; |
376 | ||
377 | no strict 'refs'; | |
2ebb273f | 378 | if (@_ > 1 || (@_ == 1 && (ref($_[0]) eq 'HASH'))) |
990fb837 RGS |
379 | { |
380 | # try to set given options as arguments from hash | |
381 | ||
382 | my $args = $_[0]; | |
383 | if (ref($args) ne 'HASH') | |
384 | { | |
385 | $args = { @_ }; | |
386 | } | |
387 | # these values can be "set" | |
388 | my $set_args = {}; | |
389 | foreach my $key ( | |
390 | qw/trap_inf trap_nan | |
391 | upgrade downgrade precision accuracy round_mode div_scale/ | |
392 | ) | |
393 | { | |
394 | $set_args->{$key} = $args->{$key} if exists $args->{$key}; | |
395 | delete $args->{$key}; | |
396 | } | |
397 | if (keys %$args > 0) | |
398 | { | |
399 | require Carp; | |
400 | Carp::croak ("Illegal key(s) '", | |
401 | join("','",keys %$args),"' passed to $class\->config()"); | |
402 | } | |
403 | foreach my $key (keys %$set_args) | |
404 | { | |
405 | if ($key =~ /^trap_(inf|nan)\z/) | |
406 | { | |
407 | ${"${class}::_trap_$1"} = ($set_args->{"trap_$1"} ? 1 : 0); | |
408 | next; | |
409 | } | |
410 | # use a call instead of just setting the $variable to check argument | |
411 | $class->$key($set_args->{$key}); | |
412 | } | |
413 | } | |
414 | ||
415 | # now return actual configuration | |
416 | ||
b3abae2a | 417 | my $cfg = { |
990fb837 RGS |
418 | lib => $CALC, |
419 | lib_version => ${"${CALC}::VERSION"}, | |
b3abae2a | 420 | class => $class, |
990fb837 RGS |
421 | trap_nan => ${"${class}::_trap_nan"}, |
422 | trap_inf => ${"${class}::_trap_inf"}, | |
423 | version => ${"${class}::VERSION"}, | |
b3abae2a | 424 | }; |
990fb837 RGS |
425 | foreach my $key (qw/ |
426 | upgrade downgrade precision accuracy round_mode div_scale | |
427 | /) | |
b3abae2a | 428 | { |
990fb837 | 429 | $cfg->{$key} = ${"${class}::$key"}; |
b3abae2a | 430 | }; |
2ebb273f T |
431 | if (@_ == 1 && (ref($_[0]) ne 'HASH')) |
432 | { | |
433 | # calls of the style config('lib') return just this value | |
434 | return $cfg->{$_[0]}; | |
435 | } | |
b3abae2a JH |
436 | $cfg; |
437 | } | |
438 | ||
58cde26e JH |
439 | sub _scale_a |
440 | { | |
441 | # select accuracy parameter based on precedence, | |
442 | # used by bround() and bfround(), may return undef for scale (means no op) | |
b68b7ab1 T |
443 | my ($x,$scale,$mode) = @_; |
444 | ||
445 | $scale = $x->{_a} unless defined $scale; | |
446 | ||
447 | no strict 'refs'; | |
448 | my $class = ref($x); | |
449 | ||
450 | $scale = ${ $class . '::accuracy' } unless defined $scale; | |
451 | $mode = ${ $class . '::round_mode' } unless defined $mode; | |
452 | ||
d5351619 T |
453 | if (defined $scale) |
454 | { | |
455 | $scale = $scale->can('numify') ? $scale->numify() : "$scale" if ref($scale); | |
456 | $scale = int($scale); | |
457 | } | |
458 | ||
b68b7ab1 | 459 | ($scale,$mode); |
58cde26e JH |
460 | } |
461 | ||
462 | sub _scale_p | |
463 | { | |
464 | # select precision parameter based on precedence, | |
465 | # used by bround() and bfround(), may return undef for scale (means no op) | |
b68b7ab1 T |
466 | my ($x,$scale,$mode) = @_; |
467 | ||
468 | $scale = $x->{_p} unless defined $scale; | |
469 | ||
470 | no strict 'refs'; | |
471 | my $class = ref($x); | |
472 | ||
473 | $scale = ${ $class . '::precision' } unless defined $scale; | |
474 | $mode = ${ $class . '::round_mode' } unless defined $mode; | |
475 | ||
d5351619 T |
476 | if (defined $scale) |
477 | { | |
478 | $scale = $scale->can('numify') ? $scale->numify() : "$scale" if ref($scale); | |
479 | $scale = int($scale); | |
480 | } | |
481 | ||
b68b7ab1 | 482 | ($scale,$mode); |
58cde26e JH |
483 | } |
484 | ||
485 | ############################################################################## | |
486 | # constructors | |
487 | ||
488 | sub copy | |
489 | { | |
86f0d17a | 490 | # if two arguments, the first one is the class to "swallow" subclasses |
58cde26e JH |
491 | if (@_ > 1) |
492 | { | |
86f0d17a T |
493 | my $self = bless { |
494 | sign => $_[1]->{sign}, | |
495 | value => $CALC->_copy($_[1]->{value}), | |
496 | }, $_[0] if @_ > 1; | |
497 | ||
498 | $self->{_a} = $_[1]->{_a} if defined $_[1]->{_a}; | |
499 | $self->{_p} = $_[1]->{_p} if defined $_[1]->{_p}; | |
500 | return $self; | |
58cde26e | 501 | } |
58cde26e | 502 | |
86f0d17a T |
503 | my $self = bless { |
504 | sign => $_[0]->{sign}, | |
505 | value => $CALC->_copy($_[0]->{value}), | |
506 | }, ref($_[0]); | |
9b924220 | 507 | |
86f0d17a T |
508 | $self->{_a} = $_[0]->{_a} if defined $_[0]->{_a}; |
509 | $self->{_p} = $_[0]->{_p} if defined $_[0]->{_p}; | |
58cde26e JH |
510 | $self; |
511 | } | |
512 | ||
513 | sub new | |
514 | { | |
b22b3e31 | 515 | # create a new BigInt object from a string or another BigInt object. |
0716bf9b | 516 | # see hash keys documented at top |
58cde26e JH |
517 | |
518 | # the argument could be an object, so avoid ||, && etc on it, this would | |
b22b3e31 PN |
519 | # cause costly overloaded code to be called. The only allowed ops are |
520 | # ref() and defined. | |
58cde26e | 521 | |
61f5c3f5 | 522 | my ($class,$wanted,$a,$p,$r) = @_; |
58cde26e | 523 | |
61f5c3f5 T |
524 | # avoid numify-calls by not using || on $wanted! |
525 | return $class->bzero($a,$p) if !defined $wanted; # default to 0 | |
9393ace2 JH |
526 | return $class->copy($wanted,$a,$p,$r) |
527 | if ref($wanted) && $wanted->isa($class); # MBI or subclass | |
58cde26e | 528 | |
61f5c3f5 T |
529 | $class->import() if $IMPORT == 0; # make require work |
530 | ||
9393ace2 JH |
531 | my $self = bless {}, $class; |
532 | ||
533 | # shortcut for "normal" numbers | |
739c8b3a | 534 | if ((!ref $wanted) && ($wanted =~ /^([+-]?)[1-9][0-9]*\z/)) |
9393ace2 JH |
535 | { |
536 | $self->{sign} = $1 || '+'; | |
9b924220 | 537 | |
9393ace2 JH |
538 | if ($wanted =~ /^[+-]/) |
539 | { | |
56d9de68 | 540 | # remove sign without touching wanted to make it work with constants |
9b924220 RGS |
541 | my $t = $wanted; $t =~ s/^[+-]//; |
542 | $self->{value} = $CALC->_new($t); | |
543 | } | |
544 | else | |
545 | { | |
546 | $self->{value} = $CALC->_new($wanted); | |
9393ace2 | 547 | } |
9393ace2 JH |
548 | no strict 'refs'; |
549 | if ( (defined $a) || (defined $p) | |
550 | || (defined ${"${class}::precision"}) | |
551 | || (defined ${"${class}::accuracy"}) | |
552 | ) | |
553 | { | |
554 | $self->round($a,$p,$r) unless (@_ == 4 && !defined $a && !defined $p); | |
555 | } | |
556 | return $self; | |
557 | } | |
558 | ||
58cde26e | 559 | # handle '+inf', '-inf' first |
233f7bc0 | 560 | if ($wanted =~ /^[+-]?inf\z/) |
58cde26e | 561 | { |
233f7bc0 T |
562 | $self->{sign} = $wanted; # set a default sign for bstr() |
563 | return $self->binf($wanted); | |
58cde26e JH |
564 | } |
565 | # split str in m mantissa, e exponent, i integer, f fraction, v value, s sign | |
9b924220 | 566 | my ($mis,$miv,$mfv,$es,$ev) = _split($wanted); |
58cde26e JH |
567 | if (!ref $mis) |
568 | { | |
990fb837 RGS |
569 | if ($_trap_nan) |
570 | { | |
571 | require Carp; Carp::croak("$wanted is not a number in $class"); | |
572 | } | |
0716bf9b | 573 | $self->{value} = $CALC->_zero(); |
58cde26e JH |
574 | $self->{sign} = $nan; |
575 | return $self; | |
576 | } | |
574bacfe JH |
577 | if (!ref $miv) |
578 | { | |
579 | # _from_hex or _from_bin | |
580 | $self->{value} = $mis->{value}; | |
581 | $self->{sign} = $mis->{sign}; | |
582 | return $self; # throw away $mis | |
583 | } | |
58cde26e JH |
584 | # make integer from mantissa by adjusting exp, then convert to bigint |
585 | $self->{sign} = $$mis; # store sign | |
0716bf9b | 586 | $self->{value} = $CALC->_zero(); # for all the NaN cases |
58cde26e JH |
587 | my $e = int("$$es$$ev"); # exponent (avoid recursion) |
588 | if ($e > 0) | |
589 | { | |
590 | my $diff = $e - CORE::length($$mfv); | |
591 | if ($diff < 0) # Not integer | |
592 | { | |
990fb837 RGS |
593 | if ($_trap_nan) |
594 | { | |
595 | require Carp; Carp::croak("$wanted not an integer in $class"); | |
596 | } | |
58cde26e | 597 | #print "NOI 1\n"; |
b3abae2a | 598 | return $upgrade->new($wanted,$a,$p,$r) if defined $upgrade; |
58cde26e JH |
599 | $self->{sign} = $nan; |
600 | } | |
601 | else # diff >= 0 | |
602 | { | |
603 | # adjust fraction and add it to value | |
990fb837 | 604 | #print "diff > 0 $$miv\n"; |
58cde26e JH |
605 | $$miv = $$miv . ($$mfv . '0' x $diff); |
606 | } | |
607 | } | |
608 | else | |
609 | { | |
610 | if ($$mfv ne '') # e <= 0 | |
611 | { | |
612 | # fraction and negative/zero E => NOI | |
990fb837 RGS |
613 | if ($_trap_nan) |
614 | { | |
615 | require Carp; Carp::croak("$wanted not an integer in $class"); | |
616 | } | |
58cde26e | 617 | #print "NOI 2 \$\$mfv '$$mfv'\n"; |
b3abae2a | 618 | return $upgrade->new($wanted,$a,$p,$r) if defined $upgrade; |
58cde26e JH |
619 | $self->{sign} = $nan; |
620 | } | |
621 | elsif ($e < 0) | |
622 | { | |
623 | # xE-y, and empty mfv | |
624 | #print "xE-y\n"; | |
625 | $e = abs($e); | |
626 | if ($$miv !~ s/0{$e}$//) # can strip so many zero's? | |
627 | { | |
990fb837 RGS |
628 | if ($_trap_nan) |
629 | { | |
630 | require Carp; Carp::croak("$wanted not an integer in $class"); | |
631 | } | |
58cde26e | 632 | #print "NOI 3\n"; |
b3abae2a | 633 | return $upgrade->new($wanted,$a,$p,$r) if defined $upgrade; |
58cde26e JH |
634 | $self->{sign} = $nan; |
635 | } | |
636 | } | |
637 | } | |
638 | $self->{sign} = '+' if $$miv eq '0'; # normalize -0 => +0 | |
9b924220 | 639 | $self->{value} = $CALC->_new($$miv) if $self->{sign} =~ /^[+-]$/; |
0716bf9b | 640 | # if any of the globals is set, use them to round and store them inside $self |
61f5c3f5 T |
641 | # do not round for new($x,undef,undef) since that is used by MBF to signal |
642 | # no rounding | |
643 | $self->round($a,$p,$r) unless @_ == 4 && !defined $a && !defined $p; | |
9393ace2 | 644 | $self; |
58cde26e JH |
645 | } |
646 | ||
58cde26e JH |
647 | sub bnan |
648 | { | |
649 | # create a bigint 'NaN', if given a BigInt, set it to 'NaN' | |
b4f14daa | 650 | my $self = shift; |
58cde26e JH |
651 | $self = $class if !defined $self; |
652 | if (!ref($self)) | |
653 | { | |
654 | my $c = $self; $self = {}; bless $self, $c; | |
655 | } | |
990fb837 RGS |
656 | no strict 'refs'; |
657 | if (${"${class}::_trap_nan"}) | |
658 | { | |
659 | require Carp; | |
660 | Carp::croak ("Tried to set $self to NaN in $class\::bnan()"); | |
661 | } | |
61f5c3f5 | 662 | $self->import() if $IMPORT == 0; # make require work |
58cde26e | 663 | return if $self->modify('bnan'); |
13a12e00 JH |
664 | if ($self->can('_bnan')) |
665 | { | |
666 | # use subclass to initialize | |
667 | $self->_bnan(); | |
668 | } | |
669 | else | |
670 | { | |
671 | # otherwise do our own thing | |
672 | $self->{value} = $CALC->_zero(); | |
673 | } | |
58cde26e | 674 | $self->{sign} = $nan; |
394e6ffb | 675 | delete $self->{_a}; delete $self->{_p}; # rounding NaN is silly |
ef9466ea | 676 | $self; |
b4f14daa | 677 | } |
58cde26e JH |
678 | |
679 | sub binf | |
680 | { | |
681 | # create a bigint '+-inf', if given a BigInt, set it to '+-inf' | |
682 | # the sign is either '+', or if given, used from there | |
683 | my $self = shift; | |
56b9c951 | 684 | my $sign = shift; $sign = '+' if !defined $sign || $sign !~ /^-(inf)?$/; |
58cde26e JH |
685 | $self = $class if !defined $self; |
686 | if (!ref($self)) | |
687 | { | |
688 | my $c = $self; $self = {}; bless $self, $c; | |
689 | } | |
990fb837 RGS |
690 | no strict 'refs'; |
691 | if (${"${class}::_trap_inf"}) | |
692 | { | |
693 | require Carp; | |
233f7bc0 | 694 | Carp::croak ("Tried to set $self to +-inf in $class\::binf()"); |
990fb837 | 695 | } |
61f5c3f5 | 696 | $self->import() if $IMPORT == 0; # make require work |
58cde26e | 697 | return if $self->modify('binf'); |
13a12e00 JH |
698 | if ($self->can('_binf')) |
699 | { | |
700 | # use subclass to initialize | |
701 | $self->_binf(); | |
702 | } | |
703 | else | |
704 | { | |
705 | # otherwise do our own thing | |
706 | $self->{value} = $CALC->_zero(); | |
707 | } | |
56b9c951 JH |
708 | $sign = $sign . 'inf' if $sign !~ /inf$/; # - => -inf |
709 | $self->{sign} = $sign; | |
394e6ffb | 710 | ($self->{_a},$self->{_p}) = @_; # take over requested rounding |
ef9466ea | 711 | $self; |
58cde26e JH |
712 | } |
713 | ||
714 | sub bzero | |
715 | { | |
716 | # create a bigint '+0', if given a BigInt, set it to 0 | |
717 | my $self = shift; | |
12fc2493 | 718 | $self = __PACKAGE__ if !defined $self; |
0716bf9b | 719 | |
58cde26e JH |
720 | if (!ref($self)) |
721 | { | |
722 | my $c = $self; $self = {}; bless $self, $c; | |
723 | } | |
61f5c3f5 | 724 | $self->import() if $IMPORT == 0; # make require work |
58cde26e | 725 | return if $self->modify('bzero'); |
990fb837 | 726 | |
13a12e00 JH |
727 | if ($self->can('_bzero')) |
728 | { | |
729 | # use subclass to initialize | |
730 | $self->_bzero(); | |
731 | } | |
732 | else | |
733 | { | |
734 | # otherwise do our own thing | |
735 | $self->{value} = $CALC->_zero(); | |
736 | } | |
58cde26e | 737 | $self->{sign} = '+'; |
61f5c3f5 T |
738 | if (@_ > 0) |
739 | { | |
f9a08e12 JH |
740 | if (@_ > 3) |
741 | { | |
742 | # call like: $x->bzero($a,$p,$r,$y); | |
743 | ($self,$self->{_a},$self->{_p}) = $self->_find_round_parameters(@_); | |
744 | } | |
745 | else | |
746 | { | |
747 | $self->{_a} = $_[0] | |
748 | if ( (!defined $self->{_a}) || (defined $_[0] && $_[0] > $self->{_a})); | |
749 | $self->{_p} = $_[1] | |
750 | if ( (!defined $self->{_p}) || (defined $_[1] && $_[1] > $self->{_p})); | |
751 | } | |
61f5c3f5 | 752 | } |
f9a08e12 | 753 | $self; |
58cde26e JH |
754 | } |
755 | ||
574bacfe JH |
756 | sub bone |
757 | { | |
758 | # create a bigint '+1' (or -1 if given sign '-'), | |
3c4b39be | 759 | # if given a BigInt, set it to +1 or -1, respectively |
574bacfe JH |
760 | my $self = shift; |
761 | my $sign = shift; $sign = '+' if !defined $sign || $sign ne '-'; | |
762 | $self = $class if !defined $self; | |
990fb837 | 763 | |
574bacfe JH |
764 | if (!ref($self)) |
765 | { | |
766 | my $c = $self; $self = {}; bless $self, $c; | |
767 | } | |
61f5c3f5 | 768 | $self->import() if $IMPORT == 0; # make require work |
574bacfe | 769 | return if $self->modify('bone'); |
13a12e00 JH |
770 | |
771 | if ($self->can('_bone')) | |
772 | { | |
773 | # use subclass to initialize | |
774 | $self->_bone(); | |
775 | } | |
776 | else | |
777 | { | |
778 | # otherwise do our own thing | |
779 | $self->{value} = $CALC->_one(); | |
780 | } | |
574bacfe | 781 | $self->{sign} = $sign; |
61f5c3f5 T |
782 | if (@_ > 0) |
783 | { | |
f9a08e12 JH |
784 | if (@_ > 3) |
785 | { | |
786 | # call like: $x->bone($sign,$a,$p,$r,$y); | |
787 | ($self,$self->{_a},$self->{_p}) = $self->_find_round_parameters(@_); | |
788 | } | |
789 | else | |
790 | { | |
091c87b1 | 791 | # call like: $x->bone($sign,$a,$p,$r); |
f9a08e12 JH |
792 | $self->{_a} = $_[0] |
793 | if ( (!defined $self->{_a}) || (defined $_[0] && $_[0] > $self->{_a})); | |
794 | $self->{_p} = $_[1] | |
795 | if ( (!defined $self->{_p}) || (defined $_[1] && $_[1] > $self->{_p})); | |
796 | } | |
61f5c3f5 | 797 | } |
f9a08e12 | 798 | $self; |
574bacfe JH |
799 | } |
800 | ||
58cde26e | 801 | ############################################################################## |
9681bfa6 | 802 | # string conversion |
58cde26e JH |
803 | |
804 | sub bsstr | |
805 | { | |
806 | # (ref to BFLOAT or num_str ) return num_str | |
807 | # Convert number from internal format to scientific string format. | |
808 | # internal format is always normalized (no leading zeros, "-0E0" => "+0E0") | |
b68b7ab1 | 809 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
58cde26e | 810 | |
574bacfe JH |
811 | if ($x->{sign} !~ /^[+-]$/) |
812 | { | |
813 | return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN | |
814 | return 'inf'; # +inf | |
815 | } | |
58cde26e | 816 | my ($m,$e) = $x->parts(); |
b282a552 T |
817 | #$m->bstr() . 'e+' . $e->bstr(); # e can only be positive in BigInt |
818 | # 'e+' because E can only be positive in BigInt | |
9b924220 | 819 | $m->bstr() . 'e+' . $CALC->_str($e->{value}); |
58cde26e JH |
820 | } |
821 | ||
822 | sub bstr | |
823 | { | |
0716bf9b | 824 | # make a string from bigint object |
b68b7ab1 | 825 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
56b9c951 | 826 | |
574bacfe JH |
827 | if ($x->{sign} !~ /^[+-]$/) |
828 | { | |
829 | return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN | |
830 | return 'inf'; # +inf | |
831 | } | |
0716bf9b | 832 | my $es = ''; $es = $x->{sign} if $x->{sign} eq '-'; |
9b924220 | 833 | $es.$CALC->_str($x->{value}); |
58cde26e JH |
834 | } |
835 | ||
836 | sub numify | |
837 | { | |
394e6ffb | 838 | # Make a "normal" scalar from a BigInt object |
58cde26e | 839 | my $x = shift; $x = $class->new($x) unless ref $x; |
56d9de68 T |
840 | |
841 | return $x->bstr() if $x->{sign} !~ /^[+-]$/; | |
0716bf9b JH |
842 | my $num = $CALC->_num($x->{value}); |
843 | return -$num if $x->{sign} eq '-'; | |
9393ace2 | 844 | $num; |
58cde26e JH |
845 | } |
846 | ||
847 | ############################################################################## | |
848 | # public stuff (usually prefixed with "b") | |
849 | ||
850 | sub sign | |
851 | { | |
9393ace2 | 852 | # return the sign of the number: +/-/-inf/+inf/NaN |
b282a552 | 853 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
ee15d750 | 854 | |
9393ace2 | 855 | $x->{sign}; |
58cde26e JH |
856 | } |
857 | ||
ee15d750 | 858 | sub _find_round_parameters |
58cde26e JH |
859 | { |
860 | # After any operation or when calling round(), the result is rounded by | |
861 | # regarding the A & P from arguments, local parameters, or globals. | |
61f5c3f5 | 862 | |
990fb837 RGS |
863 | # !!!!!!! If you change this, remember to change round(), too! !!!!!!!!!! |
864 | ||
61f5c3f5 T |
865 | # This procedure finds the round parameters, but it is for speed reasons |
866 | # duplicated in round. Otherwise, it is tested by the testsuite and used | |
867 | # by fdiv(). | |
990fb837 RGS |
868 | |
869 | # returns ($self) or ($self,$a,$p,$r) - sets $self to NaN of both A and P | |
870 | # were requested/defined (locally or globally or both) | |
61f5c3f5 | 871 | |
394e6ffb JH |
872 | my ($self,$a,$p,$r,@args) = @_; |
873 | # $a accuracy, if given by caller | |
874 | # $p precision, if given by caller | |
875 | # $r round_mode, if given by caller | |
876 | # @args all 'other' arguments (0 for unary, 1 for binary ops) | |
58cde26e | 877 | |
394e6ffb | 878 | my $c = ref($self); # find out class of argument(s) |
574bacfe | 879 | no strict 'refs'; |
574bacfe | 880 | |
86b76201 | 881 | # convert to normal scalar for speed and correctness in inner parts |
86f0d17a T |
882 | $a = $a->can('numify') ? $a->numify() : "$a" if defined $a && ref($a); |
883 | $p = $p->can('numify') ? $p->numify() : "$p" if defined $p && ref($p); | |
86b76201 | 884 | |
58cde26e | 885 | # now pick $a or $p, but only if we have got "arguments" |
61f5c3f5 | 886 | if (!defined $a) |
58cde26e | 887 | { |
61f5c3f5 | 888 | foreach ($self,@args) |
58cde26e JH |
889 | { |
890 | # take the defined one, or if both defined, the one that is smaller | |
891 | $a = $_->{_a} if (defined $_->{_a}) && (!defined $a || $_->{_a} < $a); | |
892 | } | |
61f5c3f5 T |
893 | } |
894 | if (!defined $p) | |
ee15d750 | 895 | { |
61f5c3f5 T |
896 | # even if $a is defined, take $p, to signal error for both defined |
897 | foreach ($self,@args) | |
898 | { | |
899 | # take the defined one, or if both defined, the one that is bigger | |
900 | # -2 > -3, and 3 > 2 | |
901 | $p = $_->{_p} if (defined $_->{_p}) && (!defined $p || $_->{_p} > $p); | |
902 | } | |
ee15d750 | 903 | } |
61f5c3f5 T |
904 | # if still none defined, use globals (#2) |
905 | $a = ${"$c\::accuracy"} unless defined $a; | |
906 | $p = ${"$c\::precision"} unless defined $p; | |
990fb837 RGS |
907 | |
908 | # A == 0 is useless, so undef it to signal no rounding | |
909 | $a = undef if defined $a && $a == 0; | |
61f5c3f5 T |
910 | |
911 | # no rounding today? | |
912 | return ($self) unless defined $a || defined $p; # early out | |
913 | ||
914 | # set A and set P is an fatal error | |
990fb837 | 915 | return ($self->bnan()) if defined $a && defined $p; # error |
61f5c3f5 T |
916 | |
917 | $r = ${"$c\::round_mode"} unless defined $r; | |
7b29e1e6 | 918 | if ($r !~ /^(even|odd|\+inf|\-inf|zero|trunc|common)$/) |
990fb837 RGS |
919 | { |
920 | require Carp; Carp::croak ("Unknown round mode '$r'"); | |
921 | } | |
922 | ||
d5351619 T |
923 | $a = int($a) if defined $a; |
924 | $p = int($p) if defined $p; | |
925 | ||
990fb837 | 926 | ($self,$a,$p,$r); |
ee15d750 JH |
927 | } |
928 | ||
929 | sub round | |
930 | { | |
61f5c3f5 | 931 | # Round $self according to given parameters, or given second argument's |
ee15d750 | 932 | # parameters or global defaults |
ee15d750 | 933 | |
c4a6f826 | 934 | # for speed reasons, _find_round_parameters is embedded here: |
61f5c3f5 T |
935 | |
936 | my ($self,$a,$p,$r,@args) = @_; | |
937 | # $a accuracy, if given by caller | |
938 | # $p precision, if given by caller | |
939 | # $r round_mode, if given by caller | |
940 | # @args all 'other' arguments (0 for unary, 1 for binary ops) | |
941 | ||
61f5c3f5 T |
942 | my $c = ref($self); # find out class of argument(s) |
943 | no strict 'refs'; | |
944 | ||
945 | # now pick $a or $p, but only if we have got "arguments" | |
946 | if (!defined $a) | |
58cde26e | 947 | { |
61f5c3f5 T |
948 | foreach ($self,@args) |
949 | { | |
950 | # take the defined one, or if both defined, the one that is smaller | |
951 | $a = $_->{_a} if (defined $_->{_a}) && (!defined $a || $_->{_a} < $a); | |
952 | } | |
58cde26e | 953 | } |
61f5c3f5 T |
954 | if (!defined $p) |
955 | { | |
956 | # even if $a is defined, take $p, to signal error for both defined | |
957 | foreach ($self,@args) | |
958 | { | |
959 | # take the defined one, or if both defined, the one that is bigger | |
960 | # -2 > -3, and 3 > 2 | |
961 | $p = $_->{_p} if (defined $_->{_p}) && (!defined $p || $_->{_p} > $p); | |
962 | } | |
963 | } | |
964 | # if still none defined, use globals (#2) | |
965 | $a = ${"$c\::accuracy"} unless defined $a; | |
966 | $p = ${"$c\::precision"} unless defined $p; | |
967 | ||
990fb837 RGS |
968 | # A == 0 is useless, so undef it to signal no rounding |
969 | $a = undef if defined $a && $a == 0; | |
970 | ||
61f5c3f5 T |
971 | # no rounding today? |
972 | return $self unless defined $a || defined $p; # early out | |
973 | ||
974 | # set A and set P is an fatal error | |
975 | return $self->bnan() if defined $a && defined $p; | |
976 | ||
977 | $r = ${"$c\::round_mode"} unless defined $r; | |
7b29e1e6 | 978 | if ($r !~ /^(even|odd|\+inf|\-inf|zero|trunc|common)$/) |
990fb837 | 979 | { |
b282a552 | 980 | require Carp; Carp::croak ("Unknown round mode '$r'"); |
990fb837 | 981 | } |
61f5c3f5 T |
982 | |
983 | # now round, by calling either fround or ffround: | |
984 | if (defined $a) | |
985 | { | |
d5351619 | 986 | $self->bround(int($a),$r) if !defined $self->{_a} || $self->{_a} >= $a; |
61f5c3f5 T |
987 | } |
988 | else # both can't be undefined due to early out | |
58cde26e | 989 | { |
d5351619 | 990 | $self->bfround(int($p),$r) if !defined $self->{_p} || $self->{_p} <= $p; |
58cde26e | 991 | } |
c4a6f826 | 992 | # bround() or bfround() already called bnorm() if nec. |
12fc2493 | 993 | $self; |
58cde26e JH |
994 | } |
995 | ||
17baacb7 | 996 | sub bnorm |
58cde26e | 997 | { |
027dc388 | 998 | # (numstr or BINT) return BINT |
58cde26e | 999 | # Normalize number -- no-op here |
b282a552 | 1000 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
b3abae2a | 1001 | $x; |
58cde26e JH |
1002 | } |
1003 | ||
1004 | sub babs | |
1005 | { | |
1006 | # (BINT or num_str) return BINT | |
1007 | # make number absolute, or return absolute BINT from string | |
b68b7ab1 | 1008 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
ee15d750 | 1009 | |
58cde26e JH |
1010 | return $x if $x->modify('babs'); |
1011 | # post-normalized abs for internal use (does nothing for NaN) | |
1012 | $x->{sign} =~ s/^-/+/; | |
1013 | $x; | |
1014 | } | |
1015 | ||
7833bfdd PJA |
1016 | sub bsgn { |
1017 | # Signum function. | |
1018 | ||
1019 | my $self = shift; | |
1020 | ||
1021 | return $self if $self->modify('bsgn'); | |
1022 | ||
1023 | return $self -> bone("+") if $self -> is_pos(); | |
1024 | return $self -> bone("-") if $self -> is_neg(); | |
1025 | return $self; # zero or NaN | |
1026 | } | |
1027 | ||
58cde26e JH |
1028 | sub bneg |
1029 | { | |
1030 | # (BINT or num_str) return BINT | |
1031 | # negate number or make a negated number from string | |
b68b7ab1 | 1032 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
ee15d750 | 1033 | |
58cde26e | 1034 | return $x if $x->modify('bneg'); |
b3abae2a | 1035 | |
b68b7ab1 T |
1036 | # for +0 dont negate (to have always normalized +0). Does nothing for 'NaN' |
1037 | $x->{sign} =~ tr/+-/-+/ unless ($x->{sign} eq '+' && $CALC->_is_zero($x->{value})); | |
58cde26e JH |
1038 | $x; |
1039 | } | |
1040 | ||
1041 | sub bcmp | |
1042 | { | |
1043 | # Compares 2 values. Returns one of undef, <0, =0, >0. (suitable for sort) | |
1044 | # (BINT or num_str, BINT or num_str) return cond_code | |
f9a08e12 JH |
1045 | |
1046 | # set up parameters | |
1047 | my ($self,$x,$y) = (ref($_[0]),@_); | |
1048 | ||
1049 | # objectify is costly, so avoid it | |
1050 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1051 | { | |
1052 | ($self,$x,$y) = objectify(2,@_); | |
1053 | } | |
0716bf9b | 1054 | |
56d9de68 T |
1055 | return $upgrade->bcmp($x,$y) if defined $upgrade && |
1056 | ((!$x->isa($self)) || (!$y->isa($self))); | |
1057 | ||
0716bf9b JH |
1058 | if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/)) |
1059 | { | |
1060 | # handle +-inf and NaN | |
1061 | return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan)); | |
574bacfe | 1062 | return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/; |
0716bf9b JH |
1063 | return +1 if $x->{sign} eq '+inf'; |
1064 | return -1 if $x->{sign} eq '-inf'; | |
1065 | return -1 if $y->{sign} eq '+inf'; | |
b3abae2a | 1066 | return +1; |
0716bf9b | 1067 | } |
574bacfe JH |
1068 | # check sign for speed first |
1069 | return 1 if $x->{sign} eq '+' && $y->{sign} eq '-'; # does also 0 <=> -y | |
1070 | return -1 if $x->{sign} eq '-' && $y->{sign} eq '+'; # does also -x <=> 0 | |
1071 | ||
f9a08e12 JH |
1072 | # have same sign, so compare absolute values. Don't make tests for zero here |
1073 | # because it's actually slower than testin in Calc (especially w/ Pari et al) | |
1074 | ||
dccbb853 JH |
1075 | # post-normalized compare for internal use (honors signs) |
1076 | if ($x->{sign} eq '+') | |
1077 | { | |
56b9c951 | 1078 | # $x and $y both > 0 |
dccbb853 JH |
1079 | return $CALC->_acmp($x->{value},$y->{value}); |
1080 | } | |
1081 | ||
56b9c951 | 1082 | # $x && $y both < 0 |
b282a552 | 1083 | $CALC->_acmp($y->{value},$x->{value}); # swaped acmp (lib returns 0,1,-1) |
58cde26e JH |
1084 | } |
1085 | ||
1086 | sub bacmp | |
1087 | { | |
1088 | # Compares 2 values, ignoring their signs. | |
1089 | # Returns one of undef, <0, =0, >0. (suitable for sort) | |
1090 | # (BINT, BINT) return cond_code | |
574bacfe | 1091 | |
f9a08e12 JH |
1092 | # set up parameters |
1093 | my ($self,$x,$y) = (ref($_[0]),@_); | |
1094 | # objectify is costly, so avoid it | |
1095 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1096 | { | |
1097 | ($self,$x,$y) = objectify(2,@_); | |
1098 | } | |
1099 | ||
56d9de68 T |
1100 | return $upgrade->bacmp($x,$y) if defined $upgrade && |
1101 | ((!$x->isa($self)) || (!$y->isa($self))); | |
1102 | ||
574bacfe JH |
1103 | if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/)) |
1104 | { | |
1105 | # handle +-inf and NaN | |
1106 | return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan)); | |
1107 | return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/; | |
ef9466ea T |
1108 | return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/; |
1109 | return -1; | |
574bacfe | 1110 | } |
b3abae2a | 1111 | $CALC->_acmp($x->{value},$y->{value}); # lib does only 0,1,-1 |
58cde26e JH |
1112 | } |
1113 | ||
1114 | sub badd | |
1115 | { | |
1116 | # add second arg (BINT or string) to first (BINT) (modifies first) | |
1117 | # return result as BINT | |
f9a08e12 JH |
1118 | |
1119 | # set up parameters | |
1120 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
1121 | # objectify is costly, so avoid it | |
1122 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1123 | { | |
1124 | ($self,$x,$y,@r) = objectify(2,@_); | |
1125 | } | |
58cde26e JH |
1126 | |
1127 | return $x if $x->modify('badd'); | |
091c87b1 | 1128 | return $upgrade->badd($upgrade->new($x),$upgrade->new($y),@r) if defined $upgrade && |
8f675a64 | 1129 | ((!$x->isa($self)) || (!$y->isa($self))); |
58cde26e | 1130 | |
61f5c3f5 | 1131 | $r[3] = $y; # no push! |
574bacfe JH |
1132 | # inf and NaN handling |
1133 | if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/)) | |
1134 | { | |
1135 | # NaN first | |
1136 | return $x->bnan() if (($x->{sign} eq $nan) || ($y->{sign} eq $nan)); | |
13a12e00 JH |
1137 | # inf handling |
1138 | if (($x->{sign} =~ /^[+-]inf$/) && ($y->{sign} =~ /^[+-]inf$/)) | |
574bacfe | 1139 | { |
b3abae2a JH |
1140 | # +inf++inf or -inf+-inf => same, rest is NaN |
1141 | return $x if $x->{sign} eq $y->{sign}; | |
1142 | return $x->bnan(); | |
574bacfe JH |
1143 | } |
1144 | # +-inf + something => +inf | |
1145 | # something +-inf => +-inf | |
1146 | $x->{sign} = $y->{sign}, return $x if $y->{sign} =~ /^[+-]inf$/; | |
1147 | return $x; | |
1148 | } | |
1149 | ||
b282a552 | 1150 | my ($sx, $sy) = ( $x->{sign}, $y->{sign} ); # get signs |
58cde26e JH |
1151 | |
1152 | if ($sx eq $sy) | |
1153 | { | |
574bacfe | 1154 | $x->{value} = $CALC->_add($x->{value},$y->{value}); # same sign, abs add |
58cde26e JH |
1155 | } |
1156 | else | |
1157 | { | |
574bacfe | 1158 | my $a = $CALC->_acmp ($y->{value},$x->{value}); # absolute compare |
58cde26e JH |
1159 | if ($a > 0) |
1160 | { | |
574bacfe | 1161 | $x->{value} = $CALC->_sub($y->{value},$x->{value},1); # abs sub w/ swap |
58cde26e JH |
1162 | $x->{sign} = $sy; |
1163 | } | |
1164 | elsif ($a == 0) | |
1165 | { | |
1166 | # speedup, if equal, set result to 0 | |
0716bf9b | 1167 | $x->{value} = $CALC->_zero(); |
58cde26e JH |
1168 | $x->{sign} = '+'; |
1169 | } | |
1170 | else # a < 0 | |
1171 | { | |
574bacfe | 1172 | $x->{value} = $CALC->_sub($x->{value}, $y->{value}); # abs sub |
a0d0e21e | 1173 | } |
a0d0e21e | 1174 | } |
b68b7ab1 | 1175 | $x->round(@r); |
58cde26e JH |
1176 | } |
1177 | ||
1178 | sub bsub | |
1179 | { | |
091c87b1 | 1180 | # (BINT or num_str, BINT or num_str) return BINT |
58cde26e | 1181 | # subtract second arg from first, modify first |
f9a08e12 JH |
1182 | |
1183 | # set up parameters | |
1184 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
7d193e39 | 1185 | |
f9a08e12 JH |
1186 | # objectify is costly, so avoid it |
1187 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1188 | { | |
1189 | ($self,$x,$y,@r) = objectify(2,@_); | |
1190 | } | |
58cde26e | 1191 | |
58cde26e | 1192 | return $x if $x->modify('bsub'); |
8f675a64 | 1193 | |
9b924220 RGS |
1194 | return $upgrade->new($x)->bsub($upgrade->new($y),@r) if defined $upgrade && |
1195 | ((!$x->isa($self)) || (!$y->isa($self))); | |
b3abae2a | 1196 | |
b68b7ab1 | 1197 | return $x->round(@r) if $y->is_zero(); |
b3abae2a | 1198 | |
a87115f0 RGS |
1199 | # To correctly handle the lone special case $x->bsub($x), we note the sign |
1200 | # of $x, then flip the sign from $y, and if the sign of $x did change, too, | |
1201 | # then we caught the special case: | |
1202 | my $xsign = $x->{sign}; | |
1203 | $y->{sign} =~ tr/+\-/-+/; # does nothing for NaN | |
1204 | if ($xsign ne $x->{sign}) | |
03874afe | 1205 | { |
a87115f0 RGS |
1206 | # special case of $x->bsub($x) results in 0 |
1207 | return $x->bzero(@r) if $xsign =~ /^[+-]$/; | |
03874afe T |
1208 | return $x->bnan(); # NaN, -inf, +inf |
1209 | } | |
b3abae2a JH |
1210 | $x->badd($y,@r); # badd does not leave internal zeros |
1211 | $y->{sign} =~ tr/+\-/-+/; # refix $y (does nothing for NaN) | |
7b29e1e6 | 1212 | $x; # already rounded by badd() or no round nec. |
58cde26e JH |
1213 | } |
1214 | ||
1215 | sub binc | |
1216 | { | |
1217 | # increment arg by one | |
ee15d750 | 1218 | my ($self,$x,$a,$p,$r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_); |
58cde26e | 1219 | return $x if $x->modify('binc'); |
e745a66c JH |
1220 | |
1221 | if ($x->{sign} eq '+') | |
1222 | { | |
1223 | $x->{value} = $CALC->_inc($x->{value}); | |
b68b7ab1 | 1224 | return $x->round($a,$p,$r); |
e745a66c JH |
1225 | } |
1226 | elsif ($x->{sign} eq '-') | |
1227 | { | |
1228 | $x->{value} = $CALC->_dec($x->{value}); | |
1229 | $x->{sign} = '+' if $CALC->_is_zero($x->{value}); # -1 +1 => -0 => +0 | |
b68b7ab1 | 1230 | return $x->round($a,$p,$r); |
e745a66c JH |
1231 | } |
1232 | # inf, nan handling etc | |
091c87b1 | 1233 | $x->badd($self->bone(),$a,$p,$r); # badd does round |
58cde26e JH |
1234 | } |
1235 | ||
1236 | sub bdec | |
1237 | { | |
1238 | # decrement arg by one | |
b282a552 | 1239 | my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_); |
58cde26e | 1240 | return $x if $x->modify('bdec'); |
e745a66c | 1241 | |
b282a552 | 1242 | if ($x->{sign} eq '-') |
e745a66c | 1243 | { |
b68b7ab1 | 1244 | # x already < 0 |
e745a66c | 1245 | $x->{value} = $CALC->_inc($x->{value}); |
b282a552 T |
1246 | } |
1247 | else | |
e745a66c | 1248 | { |
b68b7ab1 | 1249 | return $x->badd($self->bone('-'),@r) unless $x->{sign} eq '+'; # inf or NaN |
b282a552 T |
1250 | # >= 0 |
1251 | if ($CALC->_is_zero($x->{value})) | |
1252 | { | |
1253 | # == 0 | |
1254 | $x->{value} = $CALC->_one(); $x->{sign} = '-'; # 0 => -1 | |
1255 | } | |
1256 | else | |
1257 | { | |
1258 | # > 0 | |
1259 | $x->{value} = $CALC->_dec($x->{value}); | |
1260 | } | |
e745a66c | 1261 | } |
b68b7ab1 | 1262 | $x->round(@r); |
b282a552 | 1263 | } |
58cde26e | 1264 | |
61f5c3f5 T |
1265 | sub blog |
1266 | { | |
091c87b1 T |
1267 | # calculate $x = $a ** $base + $b and return $a (e.g. the log() to base |
1268 | # $base of $x) | |
1269 | ||
1270 | # set up parameters | |
b68b7ab1 | 1271 | my ($self,$x,$base,@r) = (undef,@_); |
091c87b1 T |
1272 | # objectify is costly, so avoid it |
1273 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1274 | { | |
2aa6a1fb | 1275 | ($self,$x,$base,@r) = objectify(2,@_); |
091c87b1 | 1276 | } |
a0ac753d | 1277 | |
ef9466ea T |
1278 | return $x if $x->modify('blog'); |
1279 | ||
2ebb273f T |
1280 | $base = $self->new($base) if defined $base && !ref $base; |
1281 | ||
091c87b1 T |
1282 | # inf, -inf, NaN, <0 => NaN |
1283 | return $x->bnan() | |
9b924220 | 1284 | if $x->{sign} ne '+' || (defined $base && $base->{sign} ne '+'); |
091c87b1 | 1285 | |
9b924220 RGS |
1286 | return $upgrade->blog($upgrade->new($x),$base,@r) if |
1287 | defined $upgrade; | |
091c87b1 | 1288 | |
a0ac753d T |
1289 | # fix for bug #24969: |
1290 | # the default base is e (Euler's number) which is not an integer | |
1291 | if (!defined $base) | |
1292 | { | |
1293 | require Math::BigFloat; | |
1294 | my $u = Math::BigFloat->blog(Math::BigFloat->new($x))->as_int(); | |
1295 | # modify $x in place | |
1296 | $x->{value} = $u->{value}; | |
1297 | $x->{sign} = $u->{sign}; | |
1298 | return $x; | |
1299 | } | |
1300 | ||
9b924220 RGS |
1301 | my ($rc,$exact) = $CALC->_log_int($x->{value},$base->{value}); |
1302 | return $x->bnan() unless defined $rc; # not possible to take log? | |
1303 | $x->{value} = $rc; | |
1304 | $x->round(@r); | |
61f5c3f5 | 1305 | } |
091c87b1 | 1306 | |
50109ad0 RGS |
1307 | sub bnok |
1308 | { | |
1309 | # Calculate n over k (binomial coefficient or "choose" function) as integer. | |
1310 | # set up parameters | |
1311 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
1312 | ||
1313 | # objectify is costly, so avoid it | |
1314 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1315 | { | |
1316 | ($self,$x,$y,@r) = objectify(2,@_); | |
1317 | } | |
1318 | ||
1319 | return $x if $x->modify('bnok'); | |
1320 | return $x->bnan() if $x->{sign} eq 'NaN' || $y->{sign} eq 'NaN'; | |
1321 | return $x->binf() if $x->{sign} eq '+inf'; | |
1322 | ||
1323 | # k > n or k < 0 => 0 | |
1324 | my $cmp = $x->bacmp($y); | |
1325 | return $x->bzero() if $cmp < 0 || $y->{sign} =~ /^-/; | |
1326 | # k == n => 1 | |
1327 | return $x->bone(@r) if $cmp == 0; | |
1328 | ||
1329 | if ($CALC->can('_nok')) | |
1330 | { | |
1331 | $x->{value} = $CALC->_nok($x->{value},$y->{value}); | |
1332 | } | |
1333 | else | |
1334 | { | |
d5735945 PF |
1335 | # ( 7 ) 7! 1*2*3*4 * 5*6*7 5 * 6 * 7 6 7 |
1336 | # ( - ) = --------- = --------------- = --------- = 5 * - * - | |
1337 | # ( 3 ) (7-3)! 3! 1*2*3*4 * 1*2*3 1 * 2 * 3 2 3 | |
50109ad0 | 1338 | |
d5735945 | 1339 | if (!$y->is_zero()) |
50109ad0 | 1340 | { |
d5735945 | 1341 | my $z = $x - $y; |
50109ad0 RGS |
1342 | $z->binc(); |
1343 | my $r = $z->copy(); $z->binc(); | |
1344 | my $d = $self->new(2); | |
d5735945 | 1345 | while ($z->bacmp($x) <= 0) # f <= x ? |
50109ad0 RGS |
1346 | { |
1347 | $r->bmul($z); $r->bdiv($d); | |
1348 | $z->binc(); $d->binc(); | |
1349 | } | |
1350 | $x->{value} = $r->{value}; $x->{sign} = '+'; | |
1351 | } | |
1352 | else { $x->bone(); } | |
1353 | } | |
1354 | $x->round(@r); | |
1355 | } | |
1356 | ||
7d193e39 T |
1357 | sub bexp |
1358 | { | |
1359 | # Calculate e ** $x (Euler's number to the power of X), truncated to | |
1360 | # an integer value. | |
1361 | my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_); | |
1362 | return $x if $x->modify('bexp'); | |
1363 | ||
1364 | # inf, -inf, NaN, <0 => NaN | |
1365 | return $x->bnan() if $x->{sign} eq 'NaN'; | |
1366 | return $x->bone() if $x->is_zero(); | |
1367 | return $x if $x->{sign} eq '+inf'; | |
1368 | return $x->bzero() if $x->{sign} eq '-inf'; | |
1369 | ||
1370 | my $u; | |
1371 | { | |
1372 | # run through Math::BigFloat unless told otherwise | |
50109ad0 | 1373 | require Math::BigFloat unless defined $upgrade; |
7d193e39 T |
1374 | local $upgrade = 'Math::BigFloat' unless defined $upgrade; |
1375 | # calculate result, truncate it to integer | |
1376 | $u = $upgrade->bexp($upgrade->new($x),@r); | |
1377 | } | |
1378 | ||
1379 | if (!defined $upgrade) | |
1380 | { | |
1381 | $u = $u->as_int(); | |
1382 | # modify $x in place | |
1383 | $x->{value} = $u->{value}; | |
1384 | $x->round(@r); | |
1385 | } | |
1386 | else { $x = $u; } | |
1387 | } | |
1388 | ||
fdd59300 FR |
1389 | sub blcm |
1390 | { | |
58cde26e JH |
1391 | # (BINT or num_str, BINT or num_str) return BINT |
1392 | # does not modify arguments, but returns new object | |
fdd59300 | 1393 | # Lowest Common Multiple |
58cde26e | 1394 | |
0716bf9b JH |
1395 | my $y = shift; my ($x); |
1396 | if (ref($y)) | |
1397 | { | |
1398 | $x = $y->copy(); | |
1399 | } | |
1400 | else | |
1401 | { | |
12fc2493 | 1402 | $x = $class->new($y); |
0716bf9b | 1403 | } |
9b924220 RGS |
1404 | my $self = ref($x); |
1405 | while (@_) | |
1406 | { | |
1407 | my $y = shift; $y = $self->new($y) if !ref ($y); | |
1408 | $x = __lcm($x,$y); | |
1409 | } | |
58cde26e JH |
1410 | $x; |
1411 | } | |
1412 | ||
1413 | sub bgcd | |
1414 | { | |
1415 | # (BINT or num_str, BINT or num_str) return BINT | |
1416 | # does not modify arguments, but returns new object | |
c4a6f826 | 1417 | # GCD -- Euclid's algorithm, variant C (Knuth Vol 3, pg 341 ff) |
0716bf9b | 1418 | |
dccbb853 | 1419 | my $y = shift; |
12fc2493 | 1420 | $y = $class->new($y) if !ref($y); |
dccbb853 | 1421 | my $self = ref($y); |
9b924220 RGS |
1422 | my $x = $y->copy()->babs(); # keep arguments |
1423 | return $x->bnan() if $x->{sign} !~ /^[+-]$/; # x NaN? | |
1424 | ||
1425 | while (@_) | |
0716bf9b | 1426 | { |
9b924220 | 1427 | $y = shift; $y = $self->new($y) if !ref($y); |
9b924220 | 1428 | return $x->bnan() if $y->{sign} !~ /^[+-]$/; # y NaN? |
b68b7ab1 T |
1429 | $x->{value} = $CALC->_gcd($x->{value},$y->{value}); |
1430 | last if $CALC->_is_one($x->{value}); | |
0716bf9b | 1431 | } |
9b924220 | 1432 | $x; |
58cde26e JH |
1433 | } |
1434 | ||
58cde26e JH |
1435 | sub bnot |
1436 | { | |
1437 | # (num_str or BINT) return BINT | |
1438 | # represent ~x as twos-complement number | |
ee15d750 JH |
1439 | # we don't need $self, so undef instead of ref($_[0]) make it slightly faster |
1440 | my ($self,$x,$a,$p,$r) = ref($_[0]) ? (undef,@_) : objectify(1,@_); | |
1441 | ||
58cde26e | 1442 | return $x if $x->modify('bnot'); |
091c87b1 | 1443 | $x->binc()->bneg(); # binc already does round |
58cde26e JH |
1444 | } |
1445 | ||
091c87b1 | 1446 | ############################################################################## |
b3abae2a | 1447 | # is_foo test routines |
091c87b1 | 1448 | # we don't need $self, so undef instead of ref($_[0]) make it slightly faster |
b3abae2a | 1449 | |
58cde26e JH |
1450 | sub is_zero |
1451 | { | |
1452 | # return true if arg (BINT or num_str) is zero (array '+', '0') | |
ee15d750 | 1453 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
0716bf9b | 1454 | |
574bacfe | 1455 | return 0 if $x->{sign} !~ /^\+$/; # -, NaN & +-inf aren't |
17baacb7 | 1456 | $CALC->_is_zero($x->{value}); |
58cde26e JH |
1457 | } |
1458 | ||
1459 | sub is_nan | |
1460 | { | |
1461 | # return true if arg (BINT or num_str) is NaN | |
091c87b1 | 1462 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
ee15d750 | 1463 | |
091c87b1 | 1464 | $x->{sign} eq $nan ? 1 : 0; |
58cde26e JH |
1465 | } |
1466 | ||
1467 | sub is_inf | |
1468 | { | |
1469 | # return true if arg (BINT or num_str) is +-inf | |
091c87b1 | 1470 | my ($self,$x,$sign) = ref($_[0]) ? (undef,@_) : objectify(1,@_); |
58cde26e | 1471 | |
091c87b1 | 1472 | if (defined $sign) |
ee15d750 | 1473 | { |
091c87b1 T |
1474 | $sign = '[+-]inf' if $sign eq ''; # +- doesn't matter, only that's inf |
1475 | $sign = "[$1]inf" if $sign =~ /^([+-])(inf)?$/; # extract '+' or '-' | |
1476 | return $x->{sign} =~ /^$sign$/ ? 1 : 0; | |
ee15d750 | 1477 | } |
091c87b1 | 1478 | $x->{sign} =~ /^[+-]inf$/ ? 1 : 0; # only +-inf is infinity |
58cde26e JH |
1479 | } |
1480 | ||
1481 | sub is_one | |
1482 | { | |
091c87b1 | 1483 | # return true if arg (BINT or num_str) is +1, or -1 if sign is given |
ee15d750 JH |
1484 | my ($self,$x,$sign) = ref($_[0]) ? (undef,@_) : objectify(1,@_); |
1485 | ||
990fb837 | 1486 | $sign = '+' if !defined $sign || $sign ne '-'; |
0716bf9b | 1487 | |
ee15d750 | 1488 | return 0 if $x->{sign} ne $sign; # -1 != +1, NaN, +-inf aren't either |
394e6ffb | 1489 | $CALC->_is_one($x->{value}); |
58cde26e JH |
1490 | } |
1491 | ||
1492 | sub is_odd | |
1493 | { | |
1494 | # return true when arg (BINT or num_str) is odd, false for even | |
ee15d750 | 1495 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
0716bf9b | 1496 | |
b22b3e31 | 1497 | return 0 if $x->{sign} !~ /^[+-]$/; # NaN & +-inf aren't |
394e6ffb | 1498 | $CALC->_is_odd($x->{value}); |
58cde26e JH |
1499 | } |
1500 | ||
1501 | sub is_even | |
1502 | { | |
1503 | # return true when arg (BINT or num_str) is even, false for odd | |
ee15d750 | 1504 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
0716bf9b | 1505 | |
b22b3e31 | 1506 | return 0 if $x->{sign} !~ /^[+-]$/; # NaN & +-inf aren't |
394e6ffb | 1507 | $CALC->_is_even($x->{value}); |
0716bf9b JH |
1508 | } |
1509 | ||
1510 | sub is_positive | |
1511 | { | |
4af46cb8 | 1512 | # return true when arg (BINT or num_str) is positive (> 0) |
ee15d750 | 1513 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
b68b7ab1 T |
1514 | |
1515 | return 1 if $x->{sign} eq '+inf'; # +inf is positive | |
4af46cb8 | 1516 | |
b68b7ab1 | 1517 | # 0+ is neither positive nor negative |
4af46cb8 | 1518 | ($x->{sign} eq '+' && !$x->is_zero()) ? 1 : 0; |
0716bf9b JH |
1519 | } |
1520 | ||
1521 | sub is_negative | |
1522 | { | |
1523 | # return true when arg (BINT or num_str) is negative (< 0) | |
ee15d750 JH |
1524 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
1525 | ||
b68b7ab1 | 1526 | $x->{sign} =~ /^-/ ? 1 : 0; # -inf is negative, but NaN is not |
58cde26e JH |
1527 | } |
1528 | ||
b3abae2a JH |
1529 | sub is_int |
1530 | { | |
1531 | # return true when arg (BINT or num_str) is an integer | |
091c87b1 | 1532 | # always true for BigInt, but different for BigFloats |
b3abae2a JH |
1533 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
1534 | ||
1535 | $x->{sign} =~ /^[+-]$/ ? 1 : 0; # inf/-inf/NaN aren't | |
1536 | } | |
1537 | ||
0716bf9b JH |
1538 | ############################################################################### |
1539 | ||
58cde26e JH |
1540 | sub bmul |
1541 | { | |
c97ef841 | 1542 | # multiply the first number by the second number |
58cde26e | 1543 | # (BINT or num_str, BINT or num_str) return BINT |
f9a08e12 JH |
1544 | |
1545 | # set up parameters | |
1546 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
1547 | # objectify is costly, so avoid it | |
1548 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1549 | { | |
1550 | ($self,$x,$y,@r) = objectify(2,@_); | |
1551 | } | |
a0ac753d | 1552 | |
58cde26e | 1553 | return $x if $x->modify('bmul'); |
61f5c3f5 | 1554 | |
574bacfe | 1555 | return $x->bnan() if (($x->{sign} eq $nan) || ($y->{sign} eq $nan)); |
b3abae2a | 1556 | |
574bacfe JH |
1557 | # inf handling |
1558 | if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/)) | |
1559 | { | |
b3abae2a | 1560 | return $x->bnan() if $x->is_zero() || $y->is_zero(); |
574bacfe JH |
1561 | # result will always be +-inf: |
1562 | # +inf * +/+inf => +inf, -inf * -/-inf => +inf | |
1563 | # +inf * -/-inf => -inf, -inf * +/+inf => -inf | |
1564 | return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/); | |
1565 | return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/); | |
1566 | return $x->binf('-'); | |
1567 | } | |
9b924220 RGS |
1568 | |
1569 | return $upgrade->bmul($x,$upgrade->new($y),@r) | |
1570 | if defined $upgrade && !$y->isa($self); | |
9393ace2 JH |
1571 | |
1572 | $r[3] = $y; # no push here | |
58cde26e | 1573 | |
0716bf9b | 1574 | $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-'; # +1 * +1 or -1 * -1 => + |
dccbb853 | 1575 | |
b3abae2a JH |
1576 | $x->{value} = $CALC->_mul($x->{value},$y->{value}); # do actual math |
1577 | $x->{sign} = '+' if $CALC->_is_zero($x->{value}); # no -0 | |
f9a08e12 | 1578 | |
b68b7ab1 | 1579 | $x->round(@r); |
dccbb853 JH |
1580 | } |
1581 | ||
80365507 T |
1582 | sub bmuladd |
1583 | { | |
1584 | # multiply two numbers and then add the third to the result | |
1585 | # (BINT or num_str, BINT or num_str, BINT or num_str) return BINT | |
1586 | ||
1587 | # set up parameters | |
913a64d5 | 1588 | my ($self,$x,$y,$z,@r) = objectify(3,@_); |
80365507 T |
1589 | |
1590 | return $x if $x->modify('bmuladd'); | |
1591 | ||
1592 | return $x->bnan() if ($x->{sign} eq $nan) || | |
1593 | ($y->{sign} eq $nan) || | |
1594 | ($z->{sign} eq $nan); | |
1595 | ||
1596 | # inf handling of x and y | |
1597 | if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/)) | |
1598 | { | |
1599 | return $x->bnan() if $x->is_zero() || $y->is_zero(); | |
1600 | # result will always be +-inf: | |
1601 | # +inf * +/+inf => +inf, -inf * -/-inf => +inf | |
1602 | # +inf * -/-inf => -inf, -inf * +/+inf => -inf | |
1603 | return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/); | |
1604 | return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/); | |
1605 | return $x->binf('-'); | |
1606 | } | |
1607 | # inf handling x*y and z | |
1608 | if (($z->{sign} =~ /^[+-]inf$/)) | |
1609 | { | |
1610 | # something +-inf => +-inf | |
1611 | $x->{sign} = $z->{sign}, return $x if $z->{sign} =~ /^[+-]inf$/; | |
1612 | } | |
1613 | ||
1614 | return $upgrade->bmuladd($x,$upgrade->new($y),$upgrade->new($z),@r) | |
1615 | if defined $upgrade && (!$y->isa($self) || !$z->isa($self) || !$x->isa($self)); | |
1616 | ||
c97ef841 | 1617 | # TODO: what if $y and $z have A or P set? |
80365507 T |
1618 | $r[3] = $z; # no push here |
1619 | ||
1620 | $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-'; # +1 * +1 or -1 * -1 => + | |
1621 | ||
1622 | $x->{value} = $CALC->_mul($x->{value},$y->{value}); # do actual math | |
1623 | $x->{sign} = '+' if $CALC->_is_zero($x->{value}); # no -0 | |
1624 | ||
1625 | my ($sx, $sz) = ( $x->{sign}, $z->{sign} ); # get signs | |
1626 | ||
1627 | if ($sx eq $sz) | |
1628 | { | |
1629 | $x->{value} = $CALC->_add($x->{value},$z->{value}); # same sign, abs add | |
1630 | } | |
1631 | else | |
1632 | { | |
1633 | my $a = $CALC->_acmp ($z->{value},$x->{value}); # absolute compare | |
1634 | if ($a > 0) | |
1635 | { | |
1636 | $x->{value} = $CALC->_sub($z->{value},$x->{value},1); # abs sub w/ swap | |
1637 | $x->{sign} = $sz; | |
1638 | } | |
1639 | elsif ($a == 0) | |
1640 | { | |
1641 | # speedup, if equal, set result to 0 | |
1642 | $x->{value} = $CALC->_zero(); | |
1643 | $x->{sign} = '+'; | |
1644 | } | |
1645 | else # a < 0 | |
1646 | { | |
1647 | $x->{value} = $CALC->_sub($x->{value}, $z->{value}); # abs sub | |
1648 | } | |
1649 | } | |
1650 | $x->round(@r); | |
1651 | } | |
1652 | ||
dccbb853 JH |
1653 | sub _div_inf |
1654 | { | |
1655 | # helper function that handles +-inf cases for bdiv()/bmod() to reuse code | |
1656 | my ($self,$x,$y) = @_; | |
1657 | ||
1658 | # NaN if x == NaN or y == NaN or x==y==0 | |
1659 | return wantarray ? ($x->bnan(),$self->bnan()) : $x->bnan() | |
1660 | if (($x->is_nan() || $y->is_nan()) || | |
1661 | ($x->is_zero() && $y->is_zero())); | |
1662 | ||
f603091d | 1663 | # +-inf / +-inf == NaN, remainder also NaN |
b3abae2a | 1664 | if (($x->{sign} =~ /^[+-]inf$/) && ($y->{sign} =~ /^[+-]inf$/)) |
dccbb853 | 1665 | { |
b3abae2a | 1666 | return wantarray ? ($x->bnan(),$self->bnan()) : $x->bnan(); |
dccbb853 JH |
1667 | } |
1668 | # x / +-inf => 0, remainder x (works even if x == 0) | |
1669 | if ($y->{sign} =~ /^[+-]inf$/) | |
1670 | { | |
f9a08e12 | 1671 | my $t = $x->copy(); # bzero clobbers up $x |
dccbb853 JH |
1672 | return wantarray ? ($x->bzero(),$t) : $x->bzero() |
1673 | } | |
1674 | ||
1675 | # 5 / 0 => +inf, -6 / 0 => -inf | |
1676 | # +inf / 0 = inf, inf, and -inf / 0 => -inf, -inf | |
1677 | # exception: -8 / 0 has remainder -8, not 8 | |
1678 | # exception: -inf / 0 has remainder -inf, not inf | |
1679 | if ($y->is_zero()) | |
1680 | { | |
1681 | # +-inf / 0 => special case for -inf | |
1682 | return wantarray ? ($x,$x->copy()) : $x if $x->is_inf(); | |
1683 | if (!$x->is_zero() && !$x->is_inf()) | |
1684 | { | |
1685 | my $t = $x->copy(); # binf clobbers up $x | |
1686 | return wantarray ? | |
1687 | ($x->binf($x->{sign}),$t) : $x->binf($x->{sign}) | |
1688 | } | |
1689 | } | |
1690 | ||
1691 | # last case: +-inf / ordinary number | |
1692 | my $sign = '+inf'; | |
1693 | $sign = '-inf' if substr($x->{sign},0,1) ne $y->{sign}; | |
1694 | $x->{sign} = $sign; | |
1695 | return wantarray ? ($x,$self->bzero()) : $x; | |
58cde26e JH |
1696 | } |
1697 | ||
1698 | sub bdiv | |
1699 | { | |
1700 | # (dividend: BINT or num_str, divisor: BINT or num_str) return | |
1701 | # (BINT,BINT) (quo,rem) or BINT (only rem) | |
f9a08e12 JH |
1702 | |
1703 | # set up parameters | |
1704 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
1705 | # objectify is costly, so avoid it | |
1706 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1707 | { | |
1708 | ($self,$x,$y,@r) = objectify(2,@_); | |
1709 | } | |
58cde26e JH |
1710 | |
1711 | return $x if $x->modify('bdiv'); | |
1712 | ||
dccbb853 JH |
1713 | return $self->_div_inf($x,$y) |
1714 | if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero()); | |
58cde26e | 1715 | |
9393ace2 JH |
1716 | return $upgrade->bdiv($upgrade->new($x),$upgrade->new($y),@r) |
1717 | if defined $upgrade; | |
58cde26e | 1718 | |
990fb837 RGS |
1719 | $r[3] = $y; # no push! |
1720 | ||
58cde26e | 1721 | # calc new sign and in case $y == +/- 1, return $x |
dccbb853 | 1722 | my $xsign = $x->{sign}; # keep |
58cde26e | 1723 | $x->{sign} = ($x->{sign} ne $y->{sign} ? '-' : '+'); |
58cde26e | 1724 | |
58cde26e JH |
1725 | if (wantarray) |
1726 | { | |
394e6ffb JH |
1727 | my $rem = $self->bzero(); |
1728 | ($x->{value},$rem->{value}) = $CALC->_div($x->{value},$y->{value}); | |
1729 | $x->{sign} = '+' if $CALC->_is_zero($x->{value}); | |
f9a08e12 JH |
1730 | $rem->{_a} = $x->{_a}; |
1731 | $rem->{_p} = $x->{_p}; | |
b68b7ab1 | 1732 | $x->round(@r); |
dccbb853 JH |
1733 | if (! $CALC->_is_zero($rem->{value})) |
1734 | { | |
1735 | $rem->{sign} = $y->{sign}; | |
990fb837 | 1736 | $rem = $y->copy()->bsub($rem) if $xsign ne $y->{sign}; # one of them '-' |
dccbb853 JH |
1737 | } |
1738 | else | |
1739 | { | |
1740 | $rem->{sign} = '+'; # dont leave -0 | |
1741 | } | |
b68b7ab1 | 1742 | $rem->round(@r); |
990fb837 | 1743 | return ($x,$rem); |
58cde26e | 1744 | } |
394e6ffb JH |
1745 | |
1746 | $x->{value} = $CALC->_div($x->{value},$y->{value}); | |
1747 | $x->{sign} = '+' if $CALC->_is_zero($x->{value}); | |
f9a08e12 | 1748 | |
b68b7ab1 | 1749 | $x->round(@r); |
58cde26e JH |
1750 | } |
1751 | ||
d614cd8b JH |
1752 | ############################################################################### |
1753 | # modulus functions | |
1754 | ||
dccbb853 JH |
1755 | sub bmod |
1756 | { | |
1757 | # modulus (or remainder) | |
1758 | # (BINT or num_str, BINT or num_str) return BINT | |
f9a08e12 JH |
1759 | |
1760 | # set up parameters | |
1761 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
1762 | # objectify is costly, so avoid it | |
1763 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1764 | { | |
1765 | ($self,$x,$y,@r) = objectify(2,@_); | |
1766 | } | |
28df3e88 | 1767 | |
dccbb853 | 1768 | return $x if $x->modify('bmod'); |
61f5c3f5 | 1769 | $r[3] = $y; # no push! |
dccbb853 JH |
1770 | if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero()) |
1771 | { | |
1772 | my ($d,$r) = $self->_div_inf($x,$y); | |
f9a08e12 JH |
1773 | $x->{sign} = $r->{sign}; |
1774 | $x->{value} = $r->{value}; | |
1775 | return $x->round(@r); | |
dccbb853 JH |
1776 | } |
1777 | ||
9b924220 RGS |
1778 | # calc new sign and in case $y == +/- 1, return $x |
1779 | $x->{value} = $CALC->_mod($x->{value},$y->{value}); | |
1780 | if (!$CALC->_is_zero($x->{value})) | |
dccbb853 | 1781 | { |
b68b7ab1 T |
1782 | $x->{value} = $CALC->_sub($y->{value},$x->{value},1) # $y-$x |
1783 | if ($x->{sign} ne $y->{sign}); | |
9b924220 | 1784 | $x->{sign} = $y->{sign}; |
dccbb853 | 1785 | } |
9b924220 | 1786 | else |
b3abae2a | 1787 | { |
9b924220 | 1788 | $x->{sign} = '+'; # dont leave -0 |
b3abae2a | 1789 | } |
b68b7ab1 | 1790 | $x->round(@r); |
dccbb853 JH |
1791 | } |
1792 | ||
07d34614 | 1793 | sub bmodinv |
d614cd8b | 1794 | { |
487de07a PJA |
1795 | # Return modular multiplicative inverse: z is the modular inverse of x (mod |
1796 | # y) if and only if x*z (mod y) = 1 (mod y). If the modulus y is larger than | |
1797 | # one, x and z are relative primes (i.e., their greatest common divisor is | |
1798 | # one). | |
1799 | # | |
1800 | # If no modular multiplicative inverse exists, NaN is returned. | |
d614cd8b | 1801 | |
f9a08e12 | 1802 | # set up parameters |
b68b7ab1 | 1803 | my ($self,$x,$y,@r) = (undef,@_); |
56d9de68 | 1804 | # objectify is costly, so avoid it |
f9a08e12 JH |
1805 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) |
1806 | { | |
1807 | ($self,$x,$y,@r) = objectify(2,@_); | |
56d9de68 | 1808 | } |
d614cd8b | 1809 | |
f9a08e12 | 1810 | return $x if $x->modify('bmodinv'); |
d614cd8b | 1811 | |
487de07a PJA |
1812 | # Return NaN if one or both arguments is +inf, -inf, or nan. |
1813 | ||
1814 | return $x->bnan() if ($y->{sign} !~ /^[+-]$/ || | |
1815 | $x->{sign} !~ /^[+-]$/); | |
1816 | ||
1817 | # Return NaN if $y is zero; 1 % 0 makes no sense. | |
1818 | ||
1819 | return $x->bnan() if $y->is_zero(); | |
1820 | ||
1821 | # Return 0 in the trivial case. $x % 1 or $x % -1 is zero for all finite | |
1822 | # integers $x. | |
1823 | ||
1824 | return $x->bzero() if ($y->is_one() || | |
1825 | $y->is_one('-')); | |
1826 | ||
1827 | # Return NaN if $x = 0, or $x modulo $y is zero. The only valid case when | |
1828 | # $x = 0 is when $y = 1 or $y = -1, but that was covered above. | |
1829 | # | |
1830 | # Note that computing $x modulo $y here affects the value we'll feed to | |
1831 | # $CALC->_modinv() below when $x and $y have opposite signs. E.g., if $x = | |
1832 | # 5 and $y = 7, those two values are fed to _modinv(), but if $x = -5 and | |
1833 | # $y = 7, the values fed to _modinv() are $x = 2 (= -5 % 7) and $y = 7. | |
1834 | # The value if $x is affected only when $x and $y have opposite signs. | |
1835 | ||
1836 | $x->bmod($y); | |
1837 | return $x->bnan() if $x->is_zero(); | |
1838 | ||
1839 | # Compute the modular multiplicative inverse of the absolute values. We'll | |
1840 | # correct for the signs of $x and $y later. Return NaN if no GCD is found. | |
1841 | ||
1842 | ($x->{value}, $x->{sign}) = $CALC->_modinv($x->{value}, $y->{value}); | |
1843 | return $x->bnan() if !defined $x->{value}; | |
1844 | ||
db2e1fb3 PJA |
1845 | # Library inconsistency workaround: _modinv() in Math::BigInt::GMP versions |
1846 | # <= 1.32 return undef rather than a "+" for the sign. | |
1847 | ||
1848 | $x->{sign} = '+' unless defined $x->{sign}; | |
1849 | ||
487de07a PJA |
1850 | # When one or both arguments are negative, we have the following |
1851 | # relations. If x and y are positive: | |
1852 | # | |
1853 | # modinv(-x, -y) = -modinv(x, y) | |
1854 | # modinv(-x, y) = y - modinv(x, y) = -modinv(x, y) (mod y) | |
1855 | # modinv( x, -y) = modinv(x, y) - y = modinv(x, y) (mod -y) | |
1856 | ||
1857 | # We must swap the sign of the result if the original $x is negative. | |
1858 | # However, we must compensate for ignoring the signs when computing the | |
1859 | # inverse modulo. The net effect is that we must swap the sign of the | |
1860 | # result if $y is negative. | |
1861 | ||
1862 | $x -> bneg() if $y->{sign} eq '-'; | |
1863 | ||
1864 | # Compute $x modulo $y again after correcting the sign. | |
1865 | ||
1866 | $x -> bmod($y) if $x->{sign} ne $y->{sign}; | |
1867 | ||
1868 | return $x; | |
d614cd8b JH |
1869 | } |
1870 | ||
07d34614 | 1871 | sub bmodpow |
d614cd8b | 1872 | { |
6c29054c PJA |
1873 | # Modular exponentiation. Raises a very large number to a very large exponent |
1874 | # in a given very large modulus quickly, thanks to binary exponentiation. | |
1875 | # Supports negative exponents. | |
d614cd8b JH |
1876 | my ($self,$num,$exp,$mod,@r) = objectify(3,@_); |
1877 | ||
1878 | return $num if $num->modify('bmodpow'); | |
1879 | ||
116f6d6b PJA |
1880 | # When the exponent 'e' is negative, use the following relation, which is |
1881 | # based on finding the multiplicative inverse 'd' of 'b' modulo 'm': | |
1882 | # | |
1883 | # b^(-e) (mod m) = d^e (mod m) where b*d = 1 (mod m) | |
d614cd8b | 1884 | |
116f6d6b | 1885 | $num->bmodinv($mod) if ($exp->{sign} eq '-'); |
07d34614 | 1886 | |
116f6d6b PJA |
1887 | # Check for valid input. All operands must be finite, and the modulus must be |
1888 | # non-zero. | |
d614cd8b | 1889 | |
116f6d6b PJA |
1890 | return $num->bnan() if ($num->{sign} =~ /NaN|inf/ || # NaN, -inf, +inf |
1891 | $exp->{sign} =~ /NaN|inf/ || # NaN, -inf, +inf | |
1892 | $mod->{sign} =~ /NaN|inf/ || # NaN, -inf, +inf | |
1893 | $mod->is_zero()); | |
d614cd8b | 1894 | |
116f6d6b PJA |
1895 | # Compute 'a (mod m)', ignoring the signs on 'a' and 'm'. If the resulting |
1896 | # value is zero, the output is also zero, regardless of the signs on 'a' and | |
1897 | # 'm'. | |
1898 | ||
1899 | my $value = $CALC->_modpow($num->{value}, $exp->{value}, $mod->{value}); | |
1900 | my $sign = '+'; | |
1901 | ||
1902 | # If the resulting value is non-zero, we have four special cases, depending | |
1903 | # on the signs on 'a' and 'm'. | |
1904 | ||
6c29054c | 1905 | unless ($CALC->_is_zero($value)) { |
116f6d6b PJA |
1906 | |
1907 | # There is a negative sign on 'a' (= $num**$exp) only if the number we | |
1908 | # are exponentiating ($num) is negative and the exponent ($exp) is odd. | |
1909 | ||
1910 | if ($num->{sign} eq '-' && $exp->is_odd()) { | |
1911 | ||
1912 | # When both the number 'a' and the modulus 'm' have a negative sign, | |
1913 | # use this relation: | |
1914 | # | |
1915 | # -a (mod -m) = -(a (mod m)) | |
1916 | ||
1917 | if ($mod->{sign} eq '-') { | |
1918 | $sign = '-'; | |
1919 | } | |
1920 | ||
1921 | # When only the number 'a' has a negative sign, use this relation: | |
1922 | # | |
1923 | # -a (mod m) = m - (a (mod m)) | |
1924 | ||
1925 | else { | |
1926 | # Use copy of $mod since _sub() modifies the first argument. | |
1927 | my $mod = $CALC->_copy($mod->{value}); | |
6c29054c | 1928 | $value = $CALC->_sub($mod, $value); |
116f6d6b PJA |
1929 | $sign = '+'; |
1930 | } | |
1931 | ||
1932 | } else { | |
1933 | ||
1934 | # When only the modulus 'm' has a negative sign, use this relation: | |
1935 | # | |
1936 | # a (mod -m) = (a (mod m)) - m | |
1937 | # = -(m - (a (mod m))) | |
1938 | ||
1939 | if ($mod->{sign} eq '-') { | |
6c29054c | 1940 | # Use copy of $mod since _sub() modifies the first argument. |
116f6d6b | 1941 | my $mod = $CALC->_copy($mod->{value}); |
6c29054c | 1942 | $value = $CALC->_sub($mod, $value); |
116f6d6b PJA |
1943 | $sign = '-'; |
1944 | } | |
1945 | ||
1946 | # When neither the number 'a' nor the modulus 'm' have a negative | |
1947 | # sign, directly return the already computed value. | |
1948 | # | |
1949 | # (a (mod m)) | |
1950 | ||
1951 | } | |
1952 | ||
1953 | } | |
1954 | ||
1955 | $num->{value} = $value; | |
1956 | $num->{sign} = $sign; | |
1957 | ||
1958 | return $num; | |
d614cd8b JH |
1959 | } |
1960 | ||
1961 | ############################################################################### | |
1962 | ||
b3abae2a JH |
1963 | sub bfac |
1964 | { | |
1965 | # (BINT or num_str, BINT or num_str) return BINT | |
091c87b1 | 1966 | # compute factorial number from $x, modify $x in place |
b68b7ab1 | 1967 | my ($self,$x,@r) = ref($_[0]) ? (undef,@_) : objectify(1,@_); |
b3abae2a | 1968 | |
b68b7ab1 T |
1969 | return $x if $x->modify('bfac') || $x->{sign} eq '+inf'; # inf => inf |
1970 | return $x->bnan() if $x->{sign} ne '+'; # NaN, <0 etc => NaN | |
b3abae2a | 1971 | |
9b924220 RGS |
1972 | $x->{value} = $CALC->_fac($x->{value}); |
1973 | $x->round(@r); | |
b3abae2a JH |
1974 | } |
1975 | ||
58cde26e JH |
1976 | sub bpow |
1977 | { | |
1978 | # (BINT or num_str, BINT or num_str) return BINT | |
1979 | # compute power of two numbers -- stolen from Knuth Vol 2 pg 233 | |
1980 | # modifies first argument | |
aef458a0 | 1981 | |
f9a08e12 JH |
1982 | # set up parameters |
1983 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
1984 | # objectify is costly, so avoid it | |
1985 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
1986 | { | |
1987 | ($self,$x,$y,@r) = objectify(2,@_); | |
1988 | } | |
58cde26e JH |
1989 | |
1990 | return $x if $x->modify('bpow'); | |
9393ace2 | 1991 | |
2d2b2744 T |
1992 | return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan; |
1993 | ||
1994 | # inf handling | |
1995 | if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/)) | |
1996 | { | |
1997 | if (($x->{sign} =~ /^[+-]inf$/) && ($y->{sign} =~ /^[+-]inf$/)) | |
1998 | { | |
1999 | # +-inf ** +-inf | |
2000 | return $x->bnan(); | |
2001 | } | |
2002 | # +-inf ** Y | |
2003 | if ($x->{sign} =~ /^[+-]inf/) | |
2004 | { | |
2005 | # +inf ** 0 => NaN | |
2006 | return $x->bnan() if $y->is_zero(); | |
2007 | # -inf ** -1 => 1/inf => 0 | |
2008 | return $x->bzero() if $y->is_one('-') && $x->is_negative(); | |
2009 | ||
2010 | # +inf ** Y => inf | |
2011 | return $x if $x->{sign} eq '+inf'; | |
2012 | ||
2013 | # -inf ** Y => -inf if Y is odd | |
2014 | return $x if $y->is_odd(); | |
2015 | return $x->babs(); | |
2016 | } | |
2017 | # X ** +-inf | |
2018 | ||
2019 | # 1 ** +inf => 1 | |
2020 | return $x if $x->is_one(); | |
2021 | ||
2022 | # 0 ** inf => 0 | |
2023 | return $x if $x->is_zero() && $y->{sign} =~ /^[+]/; | |
2024 | ||
2025 | # 0 ** -inf => inf | |
2026 | return $x->binf() if $x->is_zero(); | |
2027 | ||
2028 | # -1 ** -inf => NaN | |
2029 | return $x->bnan() if $x->is_one('-') && $y->{sign} =~ /^[-]/; | |
2030 | ||
2031 | # -X ** -inf => 0 | |
2032 | return $x->bzero() if $x->{sign} eq '-' && $y->{sign} =~ /^[-]/; | |
2033 | ||
2034 | # -1 ** inf => NaN | |
2035 | return $x->bnan() if $x->{sign} eq '-'; | |
2036 | ||
2037 | # X ** inf => inf | |
2038 | return $x->binf() if $y->{sign} =~ /^[+]/; | |
2039 | # X ** -inf => 0 | |
2040 | return $x->bzero(); | |
2041 | } | |
2042 | ||
9393ace2 | 2043 | return $upgrade->bpow($upgrade->new($x),$y,@r) |
7b29e1e6 | 2044 | if defined $upgrade && (!$y->isa($self) || $y->{sign} eq '-'); |
9393ace2 | 2045 | |
61f5c3f5 | 2046 | $r[3] = $y; # no push! |
b282a552 T |
2047 | |
2048 | # cases 0 ** Y, X ** 0, X ** 1, 1 ** Y are handled by Calc or Emu | |
2049 | ||
9b924220 RGS |
2050 | my $new_sign = '+'; |
2051 | $new_sign = $y->is_odd() ? '-' : '+' if ($x->{sign} ne '+'); | |
2052 | ||
2053 | # 0 ** -7 => ( 1 / (0 ** 7)) => 1 / 0 => +inf | |
2054 | return $x->binf() | |
2055 | if $y->{sign} eq '-' && $x->{sign} eq '+' && $CALC->_is_zero($x->{value}); | |
574bacfe JH |
2056 | # 1 ** -y => 1 / (1 ** |y|) |
2057 | # so do test for negative $y after above's clause | |
9b924220 | 2058 | return $x->bnan() if $y->{sign} eq '-' && !$CALC->_is_one($x->{value}); |
027dc388 | 2059 | |
9b924220 RGS |
2060 | $x->{value} = $CALC->_pow($x->{value},$y->{value}); |
2061 | $x->{sign} = $new_sign; | |
2062 | $x->{sign} = '+' if $CALC->_is_zero($y->{value}); | |
b68b7ab1 | 2063 | $x->round(@r); |
58cde26e JH |
2064 | } |
2065 | ||
2066 | sub blsft | |
2067 | { | |
2068 | # (BINT or num_str, BINT or num_str) return BINT | |
2069 | # compute x << y, base n, y >= 0 | |
f9a08e12 JH |
2070 | |
2071 | # set up parameters | |
2072 | my ($self,$x,$y,$n,@r) = (ref($_[0]),@_); | |
2073 | # objectify is costly, so avoid it | |
2074 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
2075 | { | |
2076 | ($self,$x,$y,$n,@r) = objectify(2,@_); | |
2077 | } | |
2078 | ||
58cde26e JH |
2079 | return $x if $x->modify('blsft'); |
2080 | return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/); | |
f9a08e12 | 2081 | return $x->round(@r) if $y->is_zero(); |
58cde26e | 2082 | |
574bacfe JH |
2083 | $n = 2 if !defined $n; return $x->bnan() if $n <= 0 || $y->{sign} eq '-'; |
2084 | ||
9b924220 RGS |
2085 | $x->{value} = $CALC->_lsft($x->{value},$y->{value},$n); |
2086 | $x->round(@r); | |
58cde26e JH |
2087 | } |
2088 | ||
2089 | sub brsft | |
2090 | { | |
2091 | # (BINT or num_str, BINT or num_str) return BINT | |
2092 | # compute x >> y, base n, y >= 0 | |
f9a08e12 JH |
2093 | |
2094 | # set up parameters | |
2095 | my ($self,$x,$y,$n,@r) = (ref($_[0]),@_); | |
2096 | # objectify is costly, so avoid it | |
2097 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
2098 | { | |
2099 | ($self,$x,$y,$n,@r) = objectify(2,@_); | |
2100 | } | |
58cde26e JH |
2101 | |
2102 | return $x if $x->modify('brsft'); | |
2103 | return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/); | |
f9a08e12 JH |
2104 | return $x->round(@r) if $y->is_zero(); |
2105 | return $x->bzero(@r) if $x->is_zero(); # 0 => 0 | |
58cde26e JH |
2106 | |
2107 | $n = 2 if !defined $n; return $x->bnan() if $n <= 0 || $y->{sign} eq '-'; | |
574bacfe | 2108 | |
b3abae2a JH |
2109 | # this only works for negative numbers when shifting in base 2 |
2110 | if (($x->{sign} eq '-') && ($n == 2)) | |
2111 | { | |
f9a08e12 | 2112 | return $x->round(@r) if $x->is_one('-'); # -1 => -1 |
b3abae2a JH |
2113 | if (!$y->is_one()) |
2114 | { | |
2115 | # although this is O(N*N) in calc (as_bin!) it is O(N) in Pari et al | |
2116 | # but perhaps there is a better emulation for two's complement shift... | |
2117 | # if $y != 1, we must simulate it by doing: | |
2118 | # convert to bin, flip all bits, shift, and be done | |
2119 | $x->binc(); # -3 => -2 | |
2120 | my $bin = $x->as_bin(); | |
2121 | $bin =~ s/^-0b//; # strip '-0b' prefix | |
2122 | $bin =~ tr/10/01/; # flip bits | |
2123 | # now shift | |
a0ac753d | 2124 | if ($y >= CORE::length($bin)) |
b3abae2a JH |
2125 | { |
2126 | $bin = '0'; # shifting to far right creates -1 | |
2127 | # 0, because later increment makes | |
2128 | # that 1, attached '-' makes it '-1' | |
2129 | # because -1 >> x == -1 ! | |
2130 | } | |
2131 | else | |
2132 | { | |
2133 | $bin =~ s/.{$y}$//; # cut off at the right side | |
2134 | $bin = '1' . $bin; # extend left side by one dummy '1' | |
2135 | $bin =~ tr/10/01/; # flip bits back | |
2136 | } | |
2137 | my $res = $self->new('0b'.$bin); # add prefix and convert back | |
2138 | $res->binc(); # remember to increment | |
2139 | $x->{value} = $res->{value}; # take over value | |
f9a08e12 | 2140 | return $x->round(@r); # we are done now, magic, isn't? |
b3abae2a | 2141 | } |
b282a552 | 2142 | # x < 0, n == 2, y == 1 |
b3abae2a JH |
2143 | $x->bdec(); # n == 2, but $y == 1: this fixes it |
2144 | } | |
2145 | ||
9b924220 RGS |
2146 | $x->{value} = $CALC->_rsft($x->{value},$y->{value},$n); |
2147 | $x->round(@r); | |
58cde26e JH |
2148 | } |
2149 | ||
2150 | sub band | |
2151 | { | |
2152 | #(BINT or num_str, BINT or num_str) return BINT | |
2153 | # compute x & y | |
f9a08e12 JH |
2154 | |
2155 | # set up parameters | |
2156 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
2157 | # objectify is costly, so avoid it | |
2158 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
2159 | { | |
2160 | ($self,$x,$y,@r) = objectify(2,@_); | |
2161 | } | |
58cde26e JH |
2162 | |
2163 | return $x if $x->modify('band'); | |
2164 | ||
f9a08e12 | 2165 | $r[3] = $y; # no push! |
b3abae2a | 2166 | |
58cde26e | 2167 | return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/); |
0716bf9b | 2168 | |
b282a552 T |
2169 | my $sx = $x->{sign} eq '+' ? 1 : -1; |
2170 | my $sy = $y->{sign} eq '+' ? 1 : -1; | |
574bacfe | 2171 | |
9b924220 | 2172 | if ($sx == 1 && $sy == 1) |
0716bf9b | 2173 | { |
574bacfe | 2174 | $x->{value} = $CALC->_and($x->{value},$y->{value}); |
f9a08e12 | 2175 | return $x->round(@r); |
0716bf9b | 2176 | } |
091c87b1 T |
2177 | |
2178 | if ($CAN{signed_and}) | |
2179 | { | |
2180 | $x->{value} = $CALC->_signed_and($x->{value},$y->{value},$sx,$sy); | |
2181 | return $x->round(@r); | |
2182 | } | |
b282a552 T |
2183 | |
2184 | require $EMU_LIB; | |
2185 | __emu_band($self,$x,$y,$sx,$sy,@r); | |
58cde26e JH |
2186 | } |
2187 | ||
2188 | sub bior | |
2189 | { | |
2190 | #(BINT or num_str, BINT or num_str) return BINT | |
2191 | # compute x | y | |
f9a08e12 JH |
2192 | |
2193 | # set up parameters | |
2194 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
2195 | # objectify is costly, so avoid it | |
2196 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
2197 | { | |
2198 | ($self,$x,$y,@r) = objectify(2,@_); | |
2199 | } | |
58cde26e JH |
2200 | |
2201 | return $x if $x->modify('bior'); | |
f9a08e12 | 2202 | $r[3] = $y; # no push! |
58cde26e JH |
2203 | |
2204 | return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/); | |
574bacfe | 2205 | |
b282a552 T |
2206 | my $sx = $x->{sign} eq '+' ? 1 : -1; |
2207 | my $sy = $y->{sign} eq '+' ? 1 : -1; | |
574bacfe | 2208 | |
091c87b1 T |
2209 | # the sign of X follows the sign of X, e.g. sign of Y irrelevant for bior() |
2210 | ||
574bacfe | 2211 | # don't use lib for negative values |
9b924220 | 2212 | if ($sx == 1 && $sy == 1) |
0716bf9b | 2213 | { |
574bacfe | 2214 | $x->{value} = $CALC->_or($x->{value},$y->{value}); |
f9a08e12 | 2215 | return $x->round(@r); |
0716bf9b JH |
2216 | } |
2217 | ||
b282a552 | 2218 | # if lib can do negative values, let it handle this |
091c87b1 T |
2219 | if ($CAN{signed_or}) |
2220 | { | |
2221 | $x->{value} = $CALC->_signed_or($x->{value},$y->{value},$sx,$sy); | |
2222 | return $x->round(@r); | |
2223 | } | |
2224 | ||
b282a552 T |
2225 | require $EMU_LIB; |
2226 | __emu_bior($self,$x,$y,$sx,$sy,@r); | |
58cde26e JH |
2227 | } |
2228 | ||
2229 | sub bxor | |
2230 | { | |
2231 | #(BINT or num_str, BINT or num_str) return BINT | |
2232 | # compute x ^ y | |
f9a08e12 JH |
2233 | |
2234 | # set up parameters | |
2235 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
2236 | # objectify is costly, so avoid it | |
2237 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
2238 | { | |
2239 | ($self,$x,$y,@r) = objectify(2,@_); | |
2240 | } | |
58cde26e JH |
2241 | |
2242 | return $x if $x->modify('bxor'); | |
f9a08e12 | 2243 | $r[3] = $y; # no push! |
58cde26e | 2244 | |
0716bf9b | 2245 | return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/); |
0716bf9b | 2246 | |
b282a552 T |
2247 | my $sx = $x->{sign} eq '+' ? 1 : -1; |
2248 | my $sy = $y->{sign} eq '+' ? 1 : -1; | |
574bacfe JH |
2249 | |
2250 | # don't use lib for negative values | |
9b924220 | 2251 | if ($sx == 1 && $sy == 1) |
0716bf9b | 2252 | { |
574bacfe | 2253 | $x->{value} = $CALC->_xor($x->{value},$y->{value}); |
f9a08e12 | 2254 | return $x->round(@r); |
0716bf9b | 2255 | } |
091c87b1 | 2256 | |
b282a552 | 2257 | # if lib can do negative values, let it handle this |
091c87b1 T |
2258 | if ($CAN{signed_xor}) |
2259 | { | |
2260 | $x->{value} = $CALC->_signed_xor($x->{value},$y->{value},$sx,$sy); | |
2261 | return $x->round(@r); | |
2262 | } | |
0716bf9b | 2263 | |
b282a552 T |
2264 | require $EMU_LIB; |
2265 | __emu_bxor($self,$x,$y,$sx,$sy,@r); | |
58cde26e JH |
2266 | } |
2267 | ||
2268 | sub length | |
2269 | { | |
b282a552 | 2270 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
58cde26e | 2271 | |
0716bf9b | 2272 | my $e = $CALC->_len($x->{value}); |
091c87b1 | 2273 | wantarray ? ($e,0) : $e; |
58cde26e JH |
2274 | } |
2275 | ||
2276 | sub digit | |
2277 | { | |
0716bf9b | 2278 | # return the nth decimal digit, negative values count backward, 0 is right |
ef9466ea | 2279 | my ($self,$x,$n) = ref($_[0]) ? (undef,@_) : objectify(1,@_); |
58cde26e | 2280 | |
ef9466ea | 2281 | $n = $n->numify() if ref($n); |
f9a08e12 | 2282 | $CALC->_digit($x->{value},$n||0); |
58cde26e JH |
2283 | } |
2284 | ||
2285 | sub _trailing_zeros | |
2286 | { | |
b282a552 | 2287 | # return the amount of trailing zeros in $x (as scalar) |
58cde26e JH |
2288 | my $x = shift; |
2289 | $x = $class->new($x) unless ref $x; | |
2290 | ||
9b924220 | 2291 | return 0 if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf etc |
0716bf9b | 2292 | |
9b924220 | 2293 | $CALC->_zeros($x->{value}); # must handle odd values, 0 etc |
58cde26e JH |
2294 | } |
2295 | ||
2296 | sub bsqrt | |
2297 | { | |
990fb837 | 2298 | # calculate square root of $x |
b68b7ab1 | 2299 | my ($self,$x,@r) = ref($_[0]) ? (undef,@_) : objectify(1,@_); |
58cde26e | 2300 | |
b3abae2a JH |
2301 | return $x if $x->modify('bsqrt'); |
2302 | ||
990fb837 RGS |
2303 | return $x->bnan() if $x->{sign} !~ /^\+/; # -x or -inf or NaN => NaN |
2304 | return $x if $x->{sign} eq '+inf'; # sqrt(+inf) == inf | |
b3abae2a | 2305 | |
f9a08e12 | 2306 | return $upgrade->bsqrt($x,@r) if defined $upgrade; |
58cde26e | 2307 | |
9b924220 RGS |
2308 | $x->{value} = $CALC->_sqrt($x->{value}); |
2309 | $x->round(@r); | |
58cde26e JH |
2310 | } |
2311 | ||
990fb837 RGS |
2312 | sub broot |
2313 | { | |
2314 | # calculate $y'th root of $x | |
c38b2de2 | 2315 | |
990fb837 RGS |
2316 | # set up parameters |
2317 | my ($self,$x,$y,@r) = (ref($_[0]),@_); | |
c38b2de2 JH |
2318 | |
2319 | $y = $self->new(2) unless defined $y; | |
2320 | ||
990fb837 | 2321 | # objectify is costly, so avoid it |
c38b2de2 | 2322 | if ((!ref($x)) || (ref($x) ne ref($y))) |
990fb837 | 2323 | { |
3a427a11 | 2324 | ($self,$x,$y,@r) = objectify(2,$self || $class,@_); |
990fb837 RGS |
2325 | } |
2326 | ||
2327 | return $x if $x->modify('broot'); | |
2328 | ||
2329 | # NaN handling: $x ** 1/0, x or y NaN, or y inf/-inf or y == 0 | |
2330 | return $x->bnan() if $x->{sign} !~ /^\+/ || $y->is_zero() || | |
2331 | $y->{sign} !~ /^\+$/; | |
2332 | ||
2333 | return $x->round(@r) | |
2334 | if $x->is_zero() || $x->is_one() || $x->is_inf() || $y->is_one(); | |
2335 | ||
c38b2de2 | 2336 | return $upgrade->new($x)->broot($upgrade->new($y),@r) if defined $upgrade; |
990fb837 | 2337 | |
9b924220 RGS |
2338 | $x->{value} = $CALC->_root($x->{value},$y->{value}); |
2339 | $x->round(@r); | |
990fb837 RGS |
2340 | } |
2341 | ||
58cde26e JH |
2342 | sub exponent |
2343 | { | |
2344 | # return a copy of the exponent (here always 0, NaN or 1 for $m == 0) | |
ee15d750 | 2345 | my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_); |
58cde26e | 2346 | |
ee15d750 JH |
2347 | if ($x->{sign} !~ /^[+-]$/) |
2348 | { | |
b282a552 T |
2349 | my $s = $x->{sign}; $s =~ s/^[+-]//; # NaN, -inf,+inf => NaN or inf |
2350 | return $self->new($s); | |
ee15d750 | 2351 | } |
b282a552 T |
2352 | return $self->bone() if $x->is_zero(); |
2353 | ||
7d193e39 T |
2354 | # 12300 => 2 trailing zeros => exponent is 2 |
2355 | $self->new( $CALC->_zeros($x->{value}) ); | |
58cde26e JH |
2356 | } |
2357 | ||
2358 | sub mantissa | |
2359 | { | |
ee15d750 JH |
2360 | # return the mantissa (compatible to Math::BigFloat, e.g. reduced) |
2361 | my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_); | |
58cde26e | 2362 | |
ee15d750 JH |
2363 | if ($x->{sign} !~ /^[+-]$/) |
2364 | { | |
b282a552 T |
2365 | # for NaN, +inf, -inf: keep the sign |
2366 | return $self->new($x->{sign}); | |
ee15d750 | 2367 | } |
b282a552 | 2368 | my $m = $x->copy(); delete $m->{_p}; delete $m->{_a}; |
7d193e39 | 2369 | |
b282a552 | 2370 | # that's a bit inefficient: |
7d193e39 | 2371 | my $zeros = $CALC->_zeros($m->{value}); |
56b9c951 | 2372 | $m->brsft($zeros,10) if $zeros != 0; |
56b9c951 | 2373 | $m; |
58cde26e JH |
2374 | } |
2375 | ||
2376 | sub parts | |
2377 | { | |
ee15d750 | 2378 | # return a copy of both the exponent and the mantissa |
091c87b1 | 2379 | my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); |
58cde26e | 2380 | |
091c87b1 | 2381 | ($x->mantissa(),$x->exponent()); |
58cde26e JH |
2382 | } |
2383 | ||
2384 | ############################################################################## | |
2385 | # rounding functions | |
2386 | ||
2387 | sub bfround | |
2388 | { | |
2389 | # precision: round to the $Nth digit left (+$n) or right (-$n) from the '.' | |
ee15d750 | 2390 | # $n == 0 || $n == 1 => round to integer |
ef9466ea | 2391 | my $x = shift; my $self = ref($x) || $x; $x = $self->new($x) unless ref $x; |
b282a552 | 2392 | |
b68b7ab1 | 2393 | my ($scale,$mode) = $x->_scale_p(@_); |
b282a552 T |
2394 | |
2395 | return $x if !defined $scale || $x->modify('bfround'); # no-op | |
58cde26e JH |
2396 | |
2397 | # no-op for BigInts if $n <= 0 | |
b282a552 | 2398 | $x->bround( $x->length()-$scale, $mode) if $scale > 0; |
58cde26e | 2399 | |
ef9466ea T |
2400 | delete $x->{_a}; # delete to save memory |
2401 | $x->{_p} = $scale; # store new _p | |
ee15d750 | 2402 | $x; |
58cde26e JH |
2403 | } |
2404 | ||
2405 | sub _scan_for_nonzero | |
2406 | { | |
ae161977 RGS |
2407 | # internal, used by bround() to scan for non-zeros after a '5' |
2408 | my ($x,$pad,$xs,$len) = @_; | |
58cde26e | 2409 | |
ae161977 | 2410 | return 0 if $len == 1; # "5" is trailed by invisible zeros |
58cde26e JH |
2411 | my $follow = $pad - 1; |
2412 | return 0 if $follow > $len || $follow < 1; | |
0716bf9b | 2413 | |
ae161977 RGS |
2414 | # use the string form to check whether only '0's follow or not |
2415 | substr ($xs,-$follow) =~ /[^0]/ ? 1 : 0; | |
58cde26e JH |
2416 | } |
2417 | ||
2418 | sub fround | |
2419 | { | |
091c87b1 T |
2420 | # Exists to make life easier for switch between MBF and MBI (should we |
2421 | # autoload fxxx() like MBF does for bxxx()?) | |
b68b7ab1 | 2422 | my $x = shift; $x = $class->new($x) unless ref $x; |
091c87b1 | 2423 | $x->bround(@_); |
58cde26e JH |
2424 | } |
2425 | ||
2426 | sub bround | |
2427 | { | |
2428 | # accuracy: +$n preserve $n digits from left, | |
2429 | # -$n preserve $n digits from right (f.i. for 0.1234 style in MBF) | |
2430 | # no-op for $n == 0 | |
2431 | # and overwrite the rest with 0's, return normalized number | |
2432 | # do not return $x->bnorm(), but $x | |
61f5c3f5 | 2433 | |
58cde26e | 2434 | my $x = shift; $x = $class->new($x) unless ref $x; |
b68b7ab1 T |
2435 | my ($scale,$mode) = $x->_scale_a(@_); |
2436 | return $x if !defined $scale || $x->modify('bround'); # no-op | |
58cde26e | 2437 | |
61f5c3f5 T |
2438 | if ($x->is_zero() || $scale == 0) |
2439 | { | |
2440 | $x->{_a} = $scale if !defined $x->{_a} || $x->{_a} > $scale; # 3 > 2 | |
2441 | return $x; | |
2442 | } | |
2443 | return $x if $x->{sign} !~ /^[+-]$/; # inf, NaN | |
58cde26e JH |
2444 | |
2445 | # we have fewer digits than we want to scale to | |
2446 | my $len = $x->length(); | |
56d9de68 T |
2447 | # convert $scale to a scalar in case it is an object (put's a limit on the |
2448 | # number length, but this would already limited by memory constraints), makes | |
2449 | # it faster | |
2450 | $scale = $scale->numify() if ref ($scale); | |
2451 | ||
ee15d750 JH |
2452 | # scale < 0, but > -len (not >=!) |
2453 | if (($scale < 0 && $scale < -$len-1) || ($scale >= $len)) | |
2454 | { | |
61f5c3f5 | 2455 | $x->{_a} = $scale if !defined $x->{_a} || $x->{_a} > $scale; # 3 > 2 |
ee15d750 JH |
2456 | return $x; |
2457 | } | |
58cde26e JH |
2458 | |
2459 | # count of 0's to pad, from left (+) or right (-): 9 - +6 => 3, or |-6| => 6 | |
2460 | my ($pad,$digit_round,$digit_after); | |
2461 | $pad = $len - $scale; | |
ee15d750 JH |
2462 | $pad = abs($scale-1) if $scale < 0; |
2463 | ||
ae161977 RGS |
2464 | # do not use digit(), it is very costly for binary => decimal |
2465 | # getting the entire string is also costly, but we need to do it only once | |
0716bf9b JH |
2466 | my $xs = $CALC->_str($x->{value}); |
2467 | my $pl = -$pad-1; | |
56d9de68 | 2468 | |
0716bf9b JH |
2469 | # pad: 123: 0 => -1, at 1 => -2, at 2 => -3, at 3 => -4 |
2470 | # pad+1: 123: 0 => 0, at 1 => -1, at 2 => -2, at 3 => -3 | |
9b924220 | 2471 | $digit_round = '0'; $digit_round = substr($xs,$pl,1) if $pad <= $len; |
0716bf9b | 2472 | $pl++; $pl ++ if $pad >= $len; |
9b924220 | 2473 | $digit_after = '0'; $digit_after = substr($xs,$pl,1) if $pad > 0; |
ee15d750 | 2474 | |
58cde26e JH |
2475 | # in case of 01234 we round down, for 6789 up, and only in case 5 we look |
2476 | # closer at the remaining digits of the original $x, remember decision | |
2477 | my $round_up = 1; # default round up | |
2478 | $round_up -- if | |
2479 | ($mode eq 'trunc') || # trunc by round down | |
2480 | ($digit_after =~ /[01234]/) || # round down anyway, | |
2481 | # 6789 => round up | |
2482 | ($digit_after eq '5') && # not 5000...0000 | |
ae161977 | 2483 | ($x->_scan_for_nonzero($pad,$xs,$len) == 0) && |
58cde26e JH |
2484 | ( |
2485 | ($mode eq 'even') && ($digit_round =~ /[24680]/) || | |
2486 | ($mode eq 'odd') && ($digit_round =~ /[13579]/) || | |
2487 | ($mode eq '+inf') && ($x->{sign} eq '-') || | |
2488 | ($mode eq '-inf') && ($x->{sign} eq '+') || | |
2489 | ($mode eq 'zero') # round down if zero, sign adjusted below | |
2490 | ); | |
61f5c3f5 T |
2491 | my $put_back = 0; # not yet modified |
2492 | ||
61f5c3f5 T |
2493 | if (($pad > 0) && ($pad <= $len)) |
2494 | { | |
ae161977 RGS |
2495 | substr($xs,-$pad,$pad) = '0' x $pad; # replace with '00...' |
2496 | $put_back = 1; # need to put back | |
58cde26e | 2497 | } |
61f5c3f5 T |
2498 | elsif ($pad > $len) |
2499 | { | |
2500 | $x->bzero(); # round to '0' | |
2501 | } | |
2502 | ||
58cde26e JH |
2503 | if ($round_up) # what gave test above? |
2504 | { | |
ae161977 | 2505 | $put_back = 1; # need to put back |
9b924220 | 2506 | $pad = $len, $xs = '0' x $pad if $scale < 0; # tlr: whack 0.51=>1.0 |
61f5c3f5 T |
2507 | |
2508 | # we modify directly the string variant instead of creating a number and | |
f9a08e12 | 2509 | # adding it, since that is faster (we already have the string) |
61f5c3f5 T |
2510 | my $c = 0; $pad ++; # for $pad == $len case |
2511 | while ($pad <= $len) | |
2512 | { | |
9b924220 RGS |
2513 | $c = substr($xs,-$pad,1) + 1; $c = '0' if $c eq '10'; |
2514 | substr($xs,-$pad,1) = $c; $pad++; | |
61f5c3f5 T |
2515 | last if $c != 0; # no overflow => early out |
2516 | } | |
9b924220 | 2517 | $xs = '1'.$xs if $c == 0; |
61f5c3f5 | 2518 | |
58cde26e | 2519 | } |
ae161977 | 2520 | $x->{value} = $CALC->_new($xs) if $put_back == 1; # put back, if needed |
ee15d750 JH |
2521 | |
2522 | $x->{_a} = $scale if $scale >= 0; | |
2523 | if ($scale < 0) | |
2524 | { | |
2525 | $x->{_a} = $len+$scale; | |
2526 | $x->{_a} = 0 if $scale < -$len; | |
2527 | } | |
58cde26e JH |
2528 | $x; |
2529 | } | |
2530 | ||
2531 | sub bfloor | |
2532 | { | |
091c87b1 T |
2533 | # return integer less or equal then number; no-op since it's already integer |
2534 | my ($self,$x,@r) = ref($_[0]) ? (undef,@_) : objectify(1,@_); | |
58cde26e | 2535 | |
f9a08e12 | 2536 | $x->round(@r); |
58cde26e JH |
2537 | } |
2538 | ||
2539 | sub bceil | |
2540 | { | |
091c87b1 T |
2541 | # return integer greater or equal then number; no-op since it's already int |
2542 | my ($self,$x,@r) = ref($_[0]) ? (undef,@_) : objectify(1,@_); | |
58cde26e | 2543 | |
f9a08e12 | 2544 | $x->round(@r); |
58cde26e JH |
2545 | } |
2546 | ||
091c87b1 T |
2547 | sub as_number |
2548 | { | |
2549 | # An object might be asked to return itself as bigint on certain overloaded | |
7b29e1e6 | 2550 | # operations. This does exactly this, so that sub classes can simple inherit |
091c87b1 T |
2551 | # it or override with their own integer conversion routine. |
2552 | $_[0]->copy(); | |
2553 | } | |
58cde26e | 2554 | |
091c87b1 | 2555 | sub as_hex |
58cde26e | 2556 | { |
091c87b1 T |
2557 | # return as hex string, with prefixed 0x |
2558 | my $x = shift; $x = $class->new($x) if !ref($x); | |
2559 | ||
2560 | return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc | |
2561 | ||
b282a552 | 2562 | my $s = ''; |
091c87b1 | 2563 | $s = $x->{sign} if $x->{sign} eq '-'; |
9b924220 | 2564 | $s . $CALC->_as_hex($x->{value}); |
58cde26e JH |
2565 | } |
2566 | ||
091c87b1 | 2567 | sub as_bin |
58cde26e | 2568 | { |
091c87b1 T |
2569 | # return as binary string, with prefixed 0b |
2570 | my $x = shift; $x = $class->new($x) if !ref($x); | |
2571 | ||
2572 | return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc | |
2573 | ||
b282a552 | 2574 | my $s = ''; $s = $x->{sign} if $x->{sign} eq '-'; |
9b924220 | 2575 | return $s . $CALC->_as_bin($x->{value}); |
58cde26e JH |
2576 | } |
2577 | ||
7b29e1e6 T |
2578 | sub as_oct |
2579 | { | |
2580 | # return as octal string, with prefixed 0 | |
2581 | my $x = shift; $x = $class->new($x) if !ref($x); | |
2582 | ||
2583 | return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc | |
2584 | ||
2585 | my $s = ''; $s = $x->{sign} if $x->{sign} eq '-'; | |
2586 | return $s . $CALC->_as_oct($x->{value}); | |
2587 | } | |
2588 | ||
091c87b1 T |
2589 | ############################################################################## |
2590 | # private stuff (internal use only) | |
2591 | ||
66a04958 PJA |
2592 | sub objectify { |
2593 | # Convert strings and "foreign objects" to the objects we want. | |
2594 | ||
2595 | # The first argument, $count, is the number of following arguments that | |
2596 | # objectify() looks at and converts to objects. The first is a classname. | |
2597 | # If the given count is 0, all arguments will be used. | |
2598 | ||
2599 | # After the count is read, objectify obtains the name of the class to which | |
2600 | # the following arguments are converted. If the second argument is a | |
2601 | # reference, use the reference type as the class name. Otherwise, if it is | |
2602 | # a string that looks like a class name, use that. Otherwise, use $class. | |
2603 | ||
2604 | # Caller: Gives us: | |
2605 | # | |
2606 | # $x->badd(1); => ref x, scalar y | |
2607 | # Class->badd(1,2); => classname x (scalar), scalar x, scalar y | |
2608 | # Class->badd(Class->(1),2); => classname x (scalar), ref x, scalar y | |
2609 | # Math::BigInt::badd(1,2); => scalar x, scalar y | |
2610 | ||
2611 | # A shortcut for the common case $x->unary_op(): | |
2612 | ||
2613 | return (ref($_[1]), $_[1]) if (@_ == 2) && ($_[0]||0 == 1) && ref($_[1]); | |
2614 | ||
2615 | # Check the context. | |
2616 | ||
2617 | unless (wantarray) { | |
2618 | require Carp; | |
2619 | Carp::croak ("${class}::objectify() needs list context"); | |
58cde26e | 2620 | } |
66a04958 PJA |
2621 | |
2622 | # Get the number of arguments to objectify. | |
2623 | ||
2624 | my $count = shift; | |
2625 | $count ||= @_; | |
2626 | ||
2627 | # Initialize the output array. | |
2628 | ||
2629 | my @a = @_; | |
2630 | ||
2631 | # If the first argument is a reference, use that reference type as our | |
2632 | # class name. Otherwise, if the first argument looks like a class name, | |
2633 | # then use that as our class name. Otherwise, use the default class name. | |
2634 | ||
58cde26e | 2635 | { |
66a04958 PJA |
2636 | if (ref($a[0])) { # reference? |
2637 | unshift @a, ref($a[0]); | |
2638 | last; | |
2639 | } | |
2640 | if ($a[0] =~ /^[A-Z].*::/) { # string with class name? | |
2641 | last; | |
2642 | } | |
2643 | unshift @a, $class; # default class name | |
58cde26e | 2644 | } |
8f675a64 | 2645 | |
66a04958 PJA |
2646 | no strict 'refs'; |
2647 | ||
2648 | # What we upgrade to, if anything. | |
2649 | ||
2650 | my $up = ${"$a[0]::upgrade"}; | |
2651 | ||
2652 | # Disable downgrading, because Math::BigFloat -> foo('1.0','2.0') needs | |
2653 | # floats. | |
2654 | ||
2655 | my $down; | |
2656 | if (defined ${"$a[0]::downgrade"}) { | |
2657 | $down = ${"$a[0]::downgrade"}; | |
2658 | ${"$a[0]::downgrade"} = undef; | |
9393ace2 JH |
2659 | } |
2660 | ||
66a04958 PJA |
2661 | for my $i (1 .. $count) { |
2662 | my $ref = ref $a[$i]; | |
2663 | ||
2664 | # If it is an object of the right class, all is fine. | |
2665 | ||
2666 | if ($ref eq $a[0]) { | |
2667 | next; | |
58cde26e | 2668 | } |
66a04958 PJA |
2669 | |
2670 | # Don't do anything with undefs. | |
2671 | ||
2672 | unless (defined($a[$i])) { | |
2673 | next; | |
58cde26e | 2674 | } |
66a04958 PJA |
2675 | |
2676 | # Perl scalars are fed to the appropriate constructor. | |
2677 | ||
2678 | unless ($ref) { | |
2679 | $a[$i] = $a[0] -> new($a[$i]); | |
2680 | next; | |
2681 | } | |
2682 | ||
2683 | # Upgrading is OK, so skip further tests if the argument is upgraded. | |
2684 | ||
2685 | if (defined $up && $ref eq $up) { | |
2686 | next; | |
2687 | } | |
2688 | ||
2689 | # If we want a Math::BigInt, see if the object can become one. | |
2690 | # Support the old misnomer as_number(). | |
2691 | ||
2692 | if ($a[0] eq 'Math::BigInt') { | |
2693 | if ($a[$i] -> can('as_int')) { | |
2694 | $a[$i] = $a[$i] -> as_int(); | |
2695 | next; | |
2696 | } | |
2697 | if ($a[$i] -> can('as_number')) { | |
2698 | $a[$i] = $a[$i] -> as_number(); | |
2699 | next; | |
2700 | } | |
2701 | } | |
2702 | ||
2703 | # If we want a Math::BigFloat, see if the object can become one. | |
2704 | ||
2705 | if ($a[0] eq 'Math::BigFloat') { | |
2706 | if ($a[$i] -> can('as_float')) { | |
2707 | $a[$i] = $a[$i] -> as_float(); | |
2708 | next; | |
2709 | } | |
2710 | } | |
2711 | ||
2712 | # Last resort. | |
2713 | ||
2714 | $a[$i] = $a[0] -> new($a[$i]); | |
990fb837 | 2715 | } |
66a04958 PJA |
2716 | |
2717 | # Reset the downgrading. | |
2718 | ||
2719 | ${"$a[0]::downgrade"} = $down; | |
2720 | ||
2721 | return @a; | |
2722 | } | |
58cde26e | 2723 | |
b68b7ab1 T |
2724 | sub _register_callback |
2725 | { | |
2726 | my ($class,$callback) = @_; | |
2727 | ||
2728 | if (ref($callback) ne 'CODE') | |
2729 | { | |
2730 | require Carp; | |
2731 | Carp::croak ("$callback is not a coderef"); | |
2732 | } | |
2733 | $CALLBACKS{$class} = $callback; | |
2734 | } | |
2735 | ||
58cde26e JH |
2736 | sub import |
2737 | { | |
2738 | my $self = shift; | |
61f5c3f5 | 2739 | |
091c87b1 | 2740 | $IMPORT++; # remember we did import() |
8f675a64 | 2741 | my @a; my $l = scalar @_; |
7b29e1e6 | 2742 | my $warn_or_die = 0; # 0 - no warn, 1 - warn, 2 - die |
8f675a64 | 2743 | for ( my $i = 0; $i < $l ; $i++ ) |
58cde26e | 2744 | { |
0716bf9b | 2745 | if ($_[$i] eq ':constant') |
58cde26e | 2746 | { |
0716bf9b | 2747 | # this causes overlord er load to step in |
091c87b1 T |
2748 | overload::constant |
2749 | integer => sub { $self->new(shift) }, | |
2750 | binary => sub { $self->new(shift) }; | |
0716bf9b | 2751 | } |
b3abae2a JH |
2752 | elsif ($_[$i] eq 'upgrade') |
2753 | { | |
2754 | # this causes upgrading | |
2755 | $upgrade = $_[$i+1]; # or undef to disable | |
8f675a64 | 2756 | $i++; |
b3abae2a | 2757 | } |
7b29e1e6 | 2758 | elsif ($_[$i] =~ /^(lib|try|only)\z/) |
0716bf9b JH |
2759 | { |
2760 | # this causes a different low lib to take care... | |
61f5c3f5 | 2761 | $CALC = $_[$i+1] || ''; |
7b29e1e6 T |
2762 | # lib => 1 (warn on fallback), try => 0 (no warn), only => 2 (die on fallback) |
2763 | $warn_or_die = 1 if $_[$i] eq 'lib'; | |
2764 | $warn_or_die = 2 if $_[$i] eq 'only'; | |
8f675a64 JH |
2765 | $i++; |
2766 | } | |
2767 | else | |
2768 | { | |
2769 | push @a, $_[$i]; | |
58cde26e JH |
2770 | } |
2771 | } | |
2772 | # any non :constant stuff is handled by our parent, Exporter | |
b68b7ab1 T |
2773 | if (@a > 0) |
2774 | { | |
2775 | require Exporter; | |
2776 | ||
2777 | $self->SUPER::import(@a); # need it for subclasses | |
2778 | $self->export_to_level(1,$self,@a); # need it for MBF | |
2779 | } | |
58cde26e | 2780 | |
574bacfe JH |
2781 | # try to load core math lib |
2782 | my @c = split /\s*,\s*/,$CALC; | |
b68b7ab1 T |
2783 | foreach (@c) |
2784 | { | |
2785 | $_ =~ tr/a-zA-Z0-9://cd; # limit to sane characters | |
2786 | } | |
a90064ab | 2787 | push @c, \'Calc' # if all fail, try these |
7b29e1e6 | 2788 | if $warn_or_die < 2; # but not for "only" |
61f5c3f5 | 2789 | $CALC = ''; # signal error |
7b29e1e6 | 2790 | foreach my $l (@c) |
574bacfe | 2791 | { |
7b29e1e6 T |
2792 | # fallback libraries are "marked" as \'string', extract string if nec. |
2793 | my $lib = $l; $lib = $$l if ref($l); | |
2794 | ||
07d34614 | 2795 | next if ($lib || '') eq ''; |
574bacfe JH |
2796 | $lib = 'Math::BigInt::'.$lib if $lib !~ /^Math::BigInt/i; |
2797 | $lib =~ s/\.pm$//; | |
61f5c3f5 | 2798 | if ($] < 5.006) |
574bacfe | 2799 | { |
b68b7ab1 T |
2800 | # Perl < 5.6.0 dies with "out of memory!" when eval("") and ':constant' is |
2801 | # used in the same script, or eval("") inside import(). | |
07d34614 T |
2802 | my @parts = split /::/, $lib; # Math::BigInt => Math BigInt |
2803 | my $file = pop @parts; $file .= '.pm'; # BigInt => BigInt.pm | |
2804 | require File::Spec; | |
2805 | $file = File::Spec->catfile (@parts, $file); | |
2806 | eval { require "$file"; $lib->import( @c ); } | |
574bacfe JH |
2807 | } |
2808 | else | |
2809 | { | |
61f5c3f5 | 2810 | eval "use $lib qw/@c/;"; |
574bacfe | 2811 | } |
9b924220 RGS |
2812 | if ($@ eq '') |
2813 | { | |
2814 | my $ok = 1; | |
2815 | # loaded it ok, see if the api_version() is high enough | |
2816 | if ($lib->can('api_version') && $lib->api_version() >= 1.0) | |
2817 | { | |
2818 | $ok = 0; | |
2819 | # api_version matches, check if it really provides anything we need | |
2820 | for my $method (qw/ | |
2821 | one two ten | |
2822 | str num | |
2823 | add mul div sub dec inc | |
2824 | acmp len digit is_one is_zero is_even is_odd | |
2825 | is_two is_ten | |
7b29e1e6 T |
2826 | zeros new copy check |
2827 | from_hex from_oct from_bin as_hex as_bin as_oct | |
9b924220 RGS |
2828 | rsft lsft xor and or |
2829 | mod sqrt root fac pow modinv modpow log_int gcd | |
2830 | /) | |
2831 | { | |
2832 | if (!$lib->can("_$method")) | |
2833 | { | |
2834 | if (($WARN{$lib}||0) < 2) | |
2835 | { | |
2836 | require Carp; | |
2837 | Carp::carp ("$lib is missing method '_$method'"); | |
2838 | $WARN{$lib} = 1; # still warn about the lib | |
2839 | } | |
2840 | $ok++; last; | |
2841 | } | |
2842 | } | |
2843 | } | |
2844 | if ($ok == 0) | |
2845 | { | |
2846 | $CALC = $lib; | |
7b29e1e6 T |
2847 | if ($warn_or_die > 0 && ref($l)) |
2848 | { | |
2849 | require Carp; | |
2850 | my $msg = "Math::BigInt: couldn't load specified math lib(s), fallback to $lib"; | |
2851 | Carp::carp ($msg) if $warn_or_die == 1; | |
2852 | Carp::croak ($msg) if $warn_or_die == 2; | |
2853 | } | |
9b924220 RGS |
2854 | last; # found a usable one, break |
2855 | } | |
2856 | else | |
2857 | { | |
2858 | if (($WARN{$lib}||0) < 2) | |
2859 | { | |
a87115f0 | 2860 | my $ver = eval "\$$lib\::VERSION" || 'unknown'; |
9b924220 RGS |
2861 | require Carp; |
2862 | Carp::carp ("Cannot load outdated $lib v$ver, please upgrade"); | |
2863 | $WARN{$lib} = 2; # never warn again | |
2864 | } | |
2865 | } | |
2866 | } | |
574bacfe | 2867 | } |
990fb837 RGS |
2868 | if ($CALC eq '') |
2869 | { | |
2870 | require Carp; | |
7b29e1e6 T |
2871 | if ($warn_or_die == 2) |
2872 | { | |
2873 | Carp::croak ("Couldn't load specified math lib(s) and fallback disallowed"); | |
2874 | } | |
2875 | else | |
2876 | { | |
2877 | Carp::croak ("Couldn't load any math lib(s), not even fallback to Calc.pm"); | |
2878 | } | |
091c87b1 | 2879 | } |
091c87b1 | 2880 | |
b68b7ab1 T |
2881 | # notify callbacks |
2882 | foreach my $class (keys %CALLBACKS) | |
2883 | { | |
2884 | &{$CALLBACKS{$class}}($CALC); | |
2885 | } | |
2886 | ||
2887 | # Fill $CAN with the results of $CALC->can(...) for emulating lower math lib | |
2888 | # functions | |
091c87b1 T |
2889 | |
2890 | %CAN = (); | |
b68b7ab1 | 2891 | for my $method (qw/ signed_and signed_or signed_xor /) |
091c87b1 T |
2892 | { |
2893 | $CAN{$method} = $CALC->can("_$method") ? 1 : 0; | |
990fb837 | 2894 | } |
b68b7ab1 T |
2895 | |
2896 | # import done | |
58cde26e JH |
2897 | } |
2898 | ||
de1ac46b PJA |
2899 | sub from_hex { |
2900 | # Create a bigint from a hexadecimal string. | |
7b29e1e6 | 2901 | |
de1ac46b | 2902 | my ($self, $str) = @_; |
7b29e1e6 | 2903 | |
de1ac46b PJA |
2904 | if ($str =~ s/ |
2905 | ^ | |
2906 | ( [+-]? ) | |
2907 | (0?x)? | |
2908 | ( | |
2909 | [0-9a-fA-F]* | |
2910 | ( _ [0-9a-fA-F]+ )* | |
2911 | ) | |
2912 | $ | |
2913 | //x) | |
2914 | { | |
2915 | # Get a "clean" version of the string, i.e., non-emtpy and with no | |
2916 | # underscores or invalid characters. | |
7b29e1e6 | 2917 | |
de1ac46b PJA |
2918 | my $sign = $1; |
2919 | my $chrs = $3; | |
2920 | $chrs =~ tr/_//d; | |
2921 | $chrs = '0' unless CORE::length $chrs; | |
7b29e1e6 | 2922 | |
de1ac46b | 2923 | # Initialize output. |
7b29e1e6 | 2924 | |
de1ac46b | 2925 | my $x = Math::BigInt->bzero(); |
7b29e1e6 | 2926 | |
de1ac46b | 2927 | # The library method requires a prefix. |
7b29e1e6 | 2928 | |
de1ac46b | 2929 | $x->{value} = $CALC->_from_hex('0x' . $chrs); |
7b29e1e6 | 2930 | |
de1ac46b | 2931 | # Place the sign. |
7b29e1e6 | 2932 | |
de1ac46b PJA |
2933 | if ($sign eq '-' && ! $CALC->_is_zero($x->{value})) { |
2934 | $x->{sign} = '-'; | |
2935 | } | |
7b29e1e6 | 2936 | |
de1ac46b PJA |
2937 | return $x; |
2938 | } | |
7b29e1e6 | 2939 | |
de1ac46b PJA |
2940 | # CORE::hex() parses as much as it can, and ignores any trailing garbage. |
2941 | # For backwards compatibility, we return NaN. | |
7b29e1e6 | 2942 | |
de1ac46b PJA |
2943 | return $self->bnan(); |
2944 | } | |
58cde26e | 2945 | |
de1ac46b PJA |
2946 | sub from_oct { |
2947 | # Create a bigint from an octal string. | |
58cde26e | 2948 | |
de1ac46b | 2949 | my ($self, $str) = @_; |
58cde26e | 2950 | |
de1ac46b PJA |
2951 | if ($str =~ s/ |
2952 | ^ | |
2953 | ( [+-]? ) | |
2954 | ( | |
2955 | [0-7]* | |
2956 | ( _ [0-7]+ )* | |
2957 | ) | |
2958 | $ | |
2959 | //x) | |
2960 | { | |
2961 | # Get a "clean" version of the string, i.e., non-emtpy and with no | |
2962 | # underscores or invalid characters. | |
58cde26e | 2963 | |
de1ac46b PJA |
2964 | my $sign = $1; |
2965 | my $chrs = $2; | |
2966 | $chrs =~ tr/_//d; | |
2967 | $chrs = '0' unless CORE::length $chrs; | |
58cde26e | 2968 | |
de1ac46b | 2969 | # Initialize output. |
7b29e1e6 | 2970 | |
de1ac46b | 2971 | my $x = Math::BigInt->bzero(); |
58cde26e | 2972 | |
de1ac46b | 2973 | # The library method requires a prefix. |
9b924220 | 2974 | |
de1ac46b PJA |
2975 | $x->{value} = $CALC->_from_oct('0' . $chrs); |
2976 | ||
2977 | # Place the sign. | |
2978 | ||
2979 | if ($sign eq '-' && ! $CALC->_is_zero($x->{value})) { | |
2980 | $x->{sign} = '-'; | |
2981 | } | |
2982 | ||
2983 | return $x; | |
2984 | } | |
2985 | ||
2986 | # CORE::oct() parses as much as it can, and ignores any trailing garbage. | |
2987 | # For backwards compatibility, we return NaN. | |
2988 | ||
2989 | return $self->bnan(); | |
2990 | } | |
2991 | ||
2992 | sub from_bin { | |
2993 | # Create a bigint from a binary string. | |
2994 | ||
2995 | my ($self, $str) = @_; | |
2996 | ||
2997 | if ($str =~ s/ | |
2998 | ^ | |
2999 | ( [+-]? ) | |
3000 | (0?b)? | |
3001 | ( | |
3002 | [01]* | |
3003 | ( _ [01]+ )* | |
3004 | ) | |
3005 | $ | |
3006 | //x) | |
3007 | { | |
3008 | # Get a "clean" version of the string, i.e., non-emtpy and with no | |
3009 | # underscores or invalid characters. | |
3010 | ||
3011 | my $sign = $1; | |
3012 | my $chrs = $3; | |
3013 | $chrs =~ tr/_//d; | |
3014 | $chrs = '0' unless CORE::length $chrs; | |
3015 | ||
3016 | # Initialize output. | |
3017 | ||
3018 | my $x = Math::BigInt->bzero(); | |
3019 | ||
3020 | # The library method requires a prefix. | |
3021 | ||
3022 | $x->{value} = $CALC->_from_bin('0b' . $chrs); | |
3023 | ||
3024 | # Place the sign. | |
3025 | ||
3026 | if ($sign eq '-' && ! $CALC->_is_zero($x->{value})) { | |
3027 | $x->{sign} = '-'; | |
3028 | } | |
3029 | ||
3030 | return $x; | |
3031 | } | |
3032 | ||
3033 | # For consistency with from_hex() and from_oct(), we return NaN when the | |
3034 | # input is invalid. | |
3035 | ||
3036 | return $self->bnan(); | |
3037 | } | |
58cde26e JH |
3038 | |
3039 | sub _split | |
3040 | { | |
b68b7ab1 T |
3041 | # input: num_str; output: undef for invalid or |
3042 | # (\$mantissa_sign,\$mantissa_value,\$mantissa_fraction,\$exp_sign,\$exp_value) | |
3043 | # Internal, take apart a string and return the pieces. | |
3044 | # Strip leading/trailing whitespace, leading zeros, underscore and reject | |
3045 | # invalid input. | |
58cde26e JH |
3046 | my $x = shift; |
3047 | ||
c4a6f826 | 3048 | # strip white space at front, also extraneous leading zeros |
7b29e1e6 T |
3049 | $x =~ s/^\s*([-]?)0*([0-9])/$1$2/g; # will not strip ' .2' |
3050 | $x =~ s/^\s+//; # but this will | |
3051 | $x =~ s/\s+$//g; # strip white space at end | |
58cde26e | 3052 | |
574bacfe | 3053 | # shortcut, if nothing to split, return early |
7b29e1e6 | 3054 | if ($x =~ /^[+-]?[0-9]+\z/) |
574bacfe | 3055 | { |
9b924220 RGS |
3056 | $x =~ s/^([+-])0*([0-9])/$2/; my $sign = $1 || '+'; |
3057 | return (\$sign, \$x, \'', \'', \0); | |
574bacfe | 3058 | } |
58cde26e | 3059 | |
574bacfe | 3060 | # invalid starting char? |
9b924220 | 3061 | return if $x !~ /^[+-]?(\.?[0-9]|0b[0-1]|0x[0-9a-fA-F])/; |
58cde26e | 3062 | |
de1ac46b PJA |
3063 | return Math::BigInt->from_hex($x) if $x =~ /^[+-]?0x/; # hex string |
3064 | return Math::BigInt->from_bin($x) if $x =~ /^[+-]?0b/; # binary string | |
3065 | ||
394e6ffb | 3066 | # strip underscores between digits |
7b29e1e6 T |
3067 | $x =~ s/([0-9])_([0-9])/$1$2/g; |
3068 | $x =~ s/([0-9])_([0-9])/$1$2/g; # do twice for 1_2_3 | |
574bacfe | 3069 | |
58cde26e JH |
3070 | # some possible inputs: |
3071 | # 2.1234 # 0.12 # 1 # 1E1 # 2.134E1 # 434E-10 # 1.02009E-2 | |
aef458a0 | 3072 | # .2 # 1_2_3.4_5_6 # 1.4E1_2_3 # 1e3 # +.2 # 0e999 |
58cde26e | 3073 | |
9b924220 | 3074 | my ($m,$e,$last) = split /[Ee]/,$x; |
56d9de68 | 3075 | return if defined $last; # last defined => 1e2E3 or others |
58cde26e | 3076 | $e = '0' if !defined $e || $e eq ""; |
56d9de68 | 3077 | |
58cde26e JH |
3078 | # sign,value for exponent,mantint,mantfrac |
3079 | my ($es,$ev,$mis,$miv,$mfv); | |
3080 | # valid exponent? | |
7b29e1e6 | 3081 | if ($e =~ /^([+-]?)0*([0-9]+)$/) # strip leading zeros |
58cde26e JH |
3082 | { |
3083 | $es = $1; $ev = $2; | |
58cde26e JH |
3084 | # valid mantissa? |
3085 | return if $m eq '.' || $m eq ''; | |
56d9de68 | 3086 | my ($mi,$mf,$lastf) = split /\./,$m; |
8df1e0a2 | 3087 | return if defined $lastf; # lastf defined => 1.2.3 or others |
58cde26e JH |
3088 | $mi = '0' if !defined $mi; |
3089 | $mi .= '0' if $mi =~ /^[\-\+]?$/; | |
3090 | $mf = '0' if !defined $mf || $mf eq ''; | |
7b29e1e6 | 3091 | if ($mi =~ /^([+-]?)0*([0-9]+)$/) # strip leading zeros |
58cde26e JH |
3092 | { |
3093 | $mis = $1||'+'; $miv = $2; | |
7b29e1e6 | 3094 | return unless ($mf =~ /^([0-9]*?)0*$/); # strip trailing zeros |
58cde26e | 3095 | $mfv = $1; |
aef458a0 JH |
3096 | # handle the 0e999 case here |
3097 | $ev = 0 if $miv eq '0' && $mfv eq ''; | |
58cde26e JH |
3098 | return (\$mis,\$miv,\$mfv,\$es,\$ev); |
3099 | } | |
3100 | } | |
3101 | return; # NaN, not a number | |
3102 | } | |
3103 | ||
58cde26e | 3104 | ############################################################################## |
0716bf9b | 3105 | # internal calculation routines (others are in Math::BigInt::Calc etc) |
58cde26e | 3106 | |
dccbb853 | 3107 | sub __lcm |
58cde26e JH |
3108 | { |
3109 | # (BINT or num_str, BINT or num_str) return BINT | |
3110 | # does modify first argument | |
3111 | # LCM | |
3112 | ||
b68b7ab1 | 3113 | my ($x,$ty) = @_; |
58cde26e | 3114 | return $x->bnan() if ($x->{sign} eq $nan) || ($ty->{sign} eq $nan); |
b68b7ab1 T |
3115 | my $method = ref($x) . '::bgcd'; |
3116 | no strict 'refs'; | |
3117 | $x * $ty / &$method($x,$ty); | |
58cde26e JH |
3118 | } |
3119 | ||
58cde26e | 3120 | ############################################################################### |
fdb4b05f T |
3121 | # trigonometric functions |
3122 | ||
3123 | sub bpi | |
3124 | { | |
3125 | # Calculate PI to N digits. Unless upgrading is in effect, returns the | |
3126 | # result truncated to an integer, that is, always returns '3'. | |
3127 | my ($self,$n) = @_; | |
3128 | if (@_ == 1) | |
3129 | { | |
3130 | # called like Math::BigInt::bpi(10); | |
3131 | $n = $self; $self = $class; | |
3132 | } | |
3133 | $self = ref($self) if ref($self); | |
3134 | ||
3135 | return $upgrade->new($n) if defined $upgrade; | |
3136 | ||
3137 | # hard-wired to "3" | |
3138 | $self->new(3); | |
3139 | } | |
3140 | ||
60a1aa19 T |
3141 | sub bcos |
3142 | { | |
3143 | # Calculate cosinus(x) to N digits. Unless upgrading is in effect, returns the | |
3144 | # result truncated to an integer. | |
3145 | my ($self,$x,@r) = ref($_[0]) ? (undef,@_) : objectify(1,@_); | |
3146 | ||
3147 | return $x if $x->modify('bcos'); | |
3148 | ||
3149 | return $x->bnan() if $x->{sign} !~ /^[+-]\z/; # -inf +inf or NaN => NaN | |
3150 | ||
3151 | return $upgrade->new($x)->bcos(@r) if defined $upgrade; | |
3152 | ||
20e2035c | 3153 | require Math::BigFloat; |
60a1aa19 T |
3154 | # calculate the result and truncate it to integer |
3155 | my $t = Math::BigFloat->new($x)->bcos(@r)->as_int(); | |
3156 | ||
3157 | $x->bone() if $t->is_one(); | |
3158 | $x->bzero() if $t->is_zero(); | |
3159 | $x->round(@r); | |
3160 | } | |
3161 | ||
3162 | sub bsin | |
3163 | { | |
3164 | # Calculate sinus(x) to N digits. Unless upgrading is in effect, returns the | |
3165 | # result truncated to an integer. | |
3166 | my ($self,$x,@r) = ref($_[0]) ? (undef,@_) : objectify(1,@_); | |
3167 | ||
3168 | return $x if $x->modify('bsin'); | |
3169 | ||
3170 | return $x->bnan() if $x->{sign} !~ /^[+-]\z/; # -inf +inf or NaN => NaN | |
3171 | ||
3172 | return $upgrade->new($x)->bsin(@r) if defined $upgrade; | |
3173 | ||
20e2035c | 3174 | require Math::BigFloat; |
60a1aa19 T |
3175 | # calculate the result and truncate it to integer |
3176 | my $t = Math::BigFloat->new($x)->bsin(@r)->as_int(); | |
3177 | ||
3178 | $x->bone() if $t->is_one(); | |
3179 | $x->bzero() if $t->is_zero(); | |
3180 | $x->round(@r); | |
3181 | } | |
3182 | ||
20e2035c T |
3183 | sub batan2 |
3184 | { | |
30afc38d | 3185 | # calculate arcus tangens of ($y/$x) |
20e2035c T |
3186 | |
3187 | # set up parameters | |
30afc38d | 3188 | my ($self,$y,$x,@r) = (ref($_[0]),@_); |
20e2035c T |
3189 | # objectify is costly, so avoid it |
3190 | if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) | |
3191 | { | |
30afc38d | 3192 | ($self,$y,$x,@r) = objectify(2,@_); |
20e2035c T |
3193 | } |
3194 | ||
30afc38d | 3195 | return $y if $y->modify('batan2'); |
20e2035c | 3196 | |
30afc38d T |
3197 | return $y->bnan() if ($y->{sign} eq $nan) || ($x->{sign} eq $nan); |
3198 | ||
0dceeee6 RGS |
3199 | # Y X |
3200 | # != 0 -inf result is +- pi | |
3201 | if ($x->is_inf() || $y->is_inf()) | |
3202 | { | |
3203 | # upgrade to BigFloat etc. | |
3204 | return $upgrade->new($y)->batan2($upgrade->new($x),@r) if defined $upgrade; | |
3205 | if ($y->is_inf()) | |
3206 | { | |
3207 | if ($x->{sign} eq '-inf') | |
3208 | { | |
3209 | # calculate 3 pi/4 => 2.3.. => 2 | |
3210 | $y->bone( substr($y->{sign},0,1) ); | |
3211 | $y->bmul($self->new(2)); | |
3212 | } | |
3213 | elsif ($x->{sign} eq '+inf') | |
3214 | { | |
3215 | # calculate pi/4 => 0.7 => 0 | |
3216 | $y->bzero(); | |
3217 | } | |
3218 | else | |
3219 | { | |
3220 | # calculate pi/2 => 1.5 => 1 | |
3221 | $y->bone( substr($y->{sign},0,1) ); | |
3222 | } | |
3223 | } | |
3224 | else | |
3225 | { | |
3226 | if ($x->{sign} eq '+inf') | |
3227 | { | |
3228 | # calculate pi/4 => 0.7 => 0 | |
3229 | $y->bzero(); | |
3230 | } | |
3231 | else | |
3232 | { | |
3233 | # PI => 3.1415.. => 3 | |
3234 | $y->bone( substr($y->{sign},0,1) ); | |
3235 | $y->bmul($self->new(3)); | |
3236 | } | |
3237 | } | |
3238 | return $y; | |
3239 | } | |
20e2035c | 3240 | |
30afc38d | 3241 | return $upgrade->new($y)->batan2($upgrade->new($x),@r) if defined $upgrade; |
20e2035c T |
3242 | |
3243 | require Math::BigFloat; | |
30afc38d | 3244 | my $r = Math::BigFloat->new($y)->batan2(Math::BigFloat->new($x),@r)->as_int(); |
20e2035c T |
3245 | |
3246 | $x->{value} = $r->{value}; | |
3247 | $x->{sign} = $r->{sign}; | |
3248 | ||
3249 | $x; | |
3250 | } | |
3251 | ||
60a1aa19 T |
3252 | sub batan |
3253 | { | |
3254 | # Calculate arcus tangens of x to N digits. Unless upgrading is in effect, returns the | |
3255 | # result truncated to an integer. | |
3256 | my ($self,$x,@r) = ref($_[0]) ? (undef,@_) : objectify(1,@_); | |
3257 | ||
3258 | return $x if $x->modify('batan'); | |
3259 | ||
3260 | return $x->bnan() if $x->{sign} !~ /^[+-]\z/; # -inf +inf or NaN => NaN | |
3261 | ||
3262 | return $upgrade->new($x)->batan(@r) if defined $upgrade; | |
3263 | ||
3264 | # calculate the result and truncate it to integer | |
3265 | my $t = Math::BigFloat->new($x)->batan(@r); | |
3266 | ||
3267 | $x->{value} = $CALC->_new( $x->as_int()->bstr() ); | |
3268 | $x->round(@r); | |
3269 | } | |
3270 | ||
fdb4b05f | 3271 | ############################################################################### |
b68b7ab1 | 3272 | # this method returns 0 if the object can be modified, or 1 if not. |
b282a552 | 3273 | # We use a fast constant sub() here, to avoid costly calls. Subclasses |
58cde26e JH |
3274 | # may override it with special code (f.i. Math::BigInt::Constant does so) |
3275 | ||
0716bf9b | 3276 | sub modify () { 0; } |
e16b8f49 | 3277 | |
a0d0e21e | 3278 | 1; |
a5f75d66 AD |
3279 | __END__ |
3280 | ||
233f7bc0 T |
3281 | =pod |
3282 | ||
a5f75d66 AD |
3283 | =head1 NAME |
3284 | ||
233f7bc0 | 3285 | Math::BigInt - Arbitrary size integer/float math package |
a5f75d66 AD |
3286 | |
3287 | =head1 SYNOPSIS | |
3288 | ||
3289 | use Math::BigInt; | |
58cde26e | 3290 | |
0dceeee6 RGS |
3291 | # or make it faster with huge numbers: install (optional) |
3292 | # Math::BigInt::GMP and always use (it will fall back to | |
3293 | # pure Perl if the GMP library is not installed): | |
3294 | # (See also the L<MATH LIBRARY> section!) | |
990fb837 | 3295 | |
7b29e1e6 | 3296 | # will warn if Math::BigInt::GMP cannot be found |
990fb837 RGS |
3297 | use Math::BigInt lib => 'GMP'; |
3298 | ||
9681bfa6 | 3299 | # to suppress the warning use this: |
7b29e1e6 T |
3300 | # use Math::BigInt try => 'GMP'; |
3301 | ||
0dceeee6 RGS |
3302 | # dies if GMP cannot be loaded: |
3303 | # use Math::BigInt only => 'GMP'; | |
3304 | ||
9b924220 RGS |
3305 | my $str = '1234567890'; |
3306 | my @values = (64,74,18); | |
3307 | my $n = 1; my $sign = '-'; | |
3308 | ||
58cde26e | 3309 | # Number creation |
fdb4b05f T |
3310 | my $x = Math::BigInt->new($str); # defaults to 0 |
3311 | my $y = $x->copy(); # make a true copy | |
3312 | my $nan = Math::BigInt->bnan(); # create a NotANumber | |
3313 | my $zero = Math::BigInt->bzero(); # create a +0 | |
3314 | my $inf = Math::BigInt->binf(); # create a +inf | |
3315 | my $inf = Math::BigInt->binf('-'); # create a -inf | |
3316 | my $one = Math::BigInt->bone(); # create a +1 | |
3317 | my $mone = Math::BigInt->bone('-'); # create a -1 | |
3318 | ||
3319 | my $pi = Math::BigInt->bpi(); # returns '3' | |
3320 | # see Math::BigFloat::bpi() | |
58cde26e | 3321 | |
7b29e1e6 T |
3322 | $h = Math::BigInt->new('0x123'); # from hexadecimal |
3323 | $b = Math::BigInt->new('0b101'); # from binary | |
3324 | $o = Math::BigInt->from_oct('0101'); # from octal | |
3325 | ||
56d9de68 T |
3326 | # Testing (don't modify their arguments) |
3327 | # (return true if the condition is met, otherwise false) | |
3328 | ||
3329 | $x->is_zero(); # if $x is +0 | |
3330 | $x->is_nan(); # if $x is NaN | |
3331 | $x->is_one(); # if $x is +1 | |
3332 | $x->is_one('-'); # if $x is -1 | |
3333 | $x->is_odd(); # if $x is odd | |
3334 | $x->is_even(); # if $x is even | |
4af46cb8 FR |
3335 | $x->is_pos(); # if $x > 0 |
3336 | $x->is_neg(); # if $x < 0 | |
9b924220 | 3337 | $x->is_inf($sign); # if $x is +inf, or -inf (sign is default '+') |
56d9de68 T |
3338 | $x->is_int(); # if $x is an integer (not a float) |
3339 | ||
3c4b39be | 3340 | # comparing and digit/sign extraction |
56d9de68 T |
3341 | $x->bcmp($y); # compare numbers (undef,<0,=0,>0) |
3342 | $x->bacmp($y); # compare absolutely (undef,<0,=0,>0) | |
3343 | $x->sign(); # return the sign, either +,- or NaN | |
3344 | $x->digit($n); # return the nth digit, counting from right | |
3345 | $x->digit(-$n); # return the nth digit, counting from left | |
58cde26e | 3346 | |
80df1b84 FC |
3347 | # The following all modify their first argument. If you want to pre- |
3348 | # serve $x, use $z = $x->copy()->bXXX($y); See under L<CAVEATS> for | |
3349 | # why this is necessary when mixing $a = $b assignments with non-over- | |
3350 | # loaded math. | |
58cde26e | 3351 | |
56d9de68 T |
3352 | $x->bzero(); # set $x to 0 |
3353 | $x->bnan(); # set $x to NaN | |
3354 | $x->bone(); # set $x to +1 | |
3355 | $x->bone('-'); # set $x to -1 | |
3356 | $x->binf(); # set $x to inf | |
3357 | $x->binf('-'); # set $x to -inf | |
3358 | ||
3359 | $x->bneg(); # negation | |
3360 | $x->babs(); # absolute value | |
7833bfdd | 3361 | $x->bsgn(); # sign function (-1, 0, 1, or NaN) |
56d9de68 T |
3362 | $x->bnorm(); # normalize (no-op in BigInt) |
3363 | $x->bnot(); # two's complement (bit wise not) | |
3364 | $x->binc(); # increment $x by 1 | |
3365 | $x->bdec(); # decrement $x by 1 | |
53ea20b1 | 3366 | |
56d9de68 T |
3367 | $x->badd($y); # addition (add $y to $x) |
3368 | $x->bsub($y); # subtraction (subtract $y from $x) | |
3369 | $x->bmul($y); # multiplication (multiply $x by $y) | |
3370 | $x->bdiv($y); # divide, set $x to quotient | |
3371 | # return (quo,rem) or quo if scalar | |
3372 | ||
80365507 T |
3373 | $x->bmuladd($y,$z); # $x = $x * $y + $z |
3374 | ||
56d9de68 | 3375 | $x->bmod($y); # modulus (x % y) |
116f6d6b PJA |
3376 | $x->bmodpow($y,$mod); # modular exponentiation (($x ** $y) % $mod) |
3377 | $x->bmodinv($mod); # modular multiplicative inverse | |
56d9de68 | 3378 | $x->bpow($y); # power of arguments (x ** y) |
7d193e39 T |
3379 | $x->blsft($y); # left shift in base 2 |
3380 | $x->brsft($y); # right shift in base 2 | |
80df1b84 FC |
3381 | # returns (quo,rem) or quo if in sca- |
3382 | # lar context | |
7b29e1e6 T |
3383 | $x->blsft($y,$n); # left shift by $y places in base $n |
3384 | $x->brsft($y,$n); # right shift by $y places in base $n | |
80df1b84 FC |
3385 | # returns (quo,rem) or quo if in sca- |
3386 | # lar context | |
53ea20b1 | 3387 | |
56d9de68 T |
3388 | $x->band($y); # bitwise and |
3389 | $x->bior($y); # bitwise inclusive or | |
3390 | $x->bxor($y); # bitwise exclusive or | |
3391 | $x->bnot(); # bitwise not (two's complement) | |
3392 | ||
3393 | $x->bsqrt(); # calculate square-root | |
990fb837 | 3394 | $x->broot($y); # $y'th root of $x (e.g. $y == 3 => cubic root) |
56d9de68 | 3395 | $x->bfac(); # factorial of $x (1*2*3*4*..$x) |
58cde26e | 3396 | |
50109ad0 RGS |
3397 | $x->bnok($y); # x over y (binomial coefficient n over k) |
3398 | ||
7d193e39 T |
3399 | $x->blog(); # logarithm of $x to base e (Euler's number) |
3400 | $x->blog($base); # logarithm of $x to base $base (f.i. 2) | |
3401 | $x->bexp(); # calculate e ** $x where e is Euler's number | |
53ea20b1 | 3402 | |
80df1b84 FC |
3403 | $x->round($A,$P,$mode); # round to accuracy or precision using |
3404 | # mode $mode | |
9b924220 | 3405 | $x->bround($n); # accuracy: preserve $n digits |
d5351619 T |
3406 | $x->bfround($n); # $n > 0: round $nth digits, |
3407 | # $n < 0: round to the $nth digit after the | |
3408 | # dot, no-op for BigInts | |
58cde26e | 3409 | |
990fb837 | 3410 | # The following do not modify their arguments in BigInt (are no-ops), |
56d9de68 | 3411 | # but do so in BigFloat: |
58cde26e | 3412 | |
56d9de68 T |
3413 | $x->bfloor(); # return integer less or equal than $x |
3414 | $x->bceil(); # return integer greater or equal than $x | |
fdd59300 | 3415 | |
58cde26e JH |
3416 | # The following do not modify their arguments: |
3417 | ||
9b924220 RGS |
3418 | # greatest common divisor (no OO style) |
3419 | my $gcd = Math::BigInt::bgcd(@values); | |
fdd59300 FR |
3420 | # lowest common multiple (no OO style) |
3421 | my $lcm = Math::BigInt::blcm(@values); | |
3422 | ||
56d9de68 | 3423 | $x->length(); # return number of digits in number |
80df1b84 FC |
3424 | ($xl,$f) = $x->length(); # length of number and length of fraction |
3425 | # part, latter is always 0 digits long | |
3426 | # for BigInts | |
56d9de68 | 3427 | |
80df1b84 FC |
3428 | $x->exponent(); # return exponent as BigInt |
3429 | $x->mantissa(); # return (signed) mantissa as BigInt | |
3430 | $x->parts(); # return (mantissa,exponent) as BigInt | |
3431 | $x->copy(); # make a true copy of $x (unlike $y = $x;) | |
3432 | $x->as_int(); # return as BigInt (in BigInt: same as copy()) | |
3433 | $x->numify(); # return as scalar (might overflow!) | |
53ea20b1 | 3434 | |
9681bfa6 | 3435 | # conversion to string (do not modify their argument) |
80df1b84 FC |
3436 | $x->bstr(); # normalized string (e.g. '3') |
3437 | $x->bsstr(); # norm. string in scientific notation (e.g. '3E0') | |
3438 | $x->as_hex(); # as signed hexadecimal string with prefixed 0x | |
3439 | $x->as_bin(); # as signed binary string with prefixed 0b | |
3440 | $x->as_oct(); # as signed octal string with prefixed 0 | |
b282a552 | 3441 | |
bd05a461 | 3442 | |
f9a08e12 | 3443 | # precision and accuracy (see section about rounding for more) |
80df1b84 FC |
3444 | $x->precision(); # return P of $x (or global, if P of $x undef) |
3445 | $x->precision($n); # set P of $x to $n | |
3446 | $x->accuracy(); # return A of $x (or global, if A of $x undef) | |
3447 | $x->accuracy($n); # set A $x to $n | |
f9a08e12 | 3448 | |
56d9de68 | 3449 | # Global methods |
80df1b84 FC |
3450 | Math::BigInt->precision(); # get/set global P for all BigInt objects |
3451 | Math::BigInt->accuracy(); # get/set global A for all BigInt objects | |
3452 | Math::BigInt->round_mode(); # get/set global round mode, one of | |
3453 | # 'even', 'odd', '+inf', '-inf', 'zero', | |
3454 | # 'trunc' or 'common' | |
3455 | Math::BigInt->config(); # return hash containing configuration | |
f9a08e12 | 3456 | |
a5f75d66 AD |