File Coverage

blib/lib/Math/BigRat.pm
Criterion Covered Total %
statement 921 1684 54.6
branch 582 1376 42.3
condition 273 628 43.4
subroutine 93 158 58.8
pod 97 98 98.9
total 1966 3944 49.8


line stmt bran cond sub pod time code
1             #
2             # "Tax the rat farms." - Lord Vetinari
3             #
4              
5             # The following hash values are used:
6              
7             # sign : "+", "-", "+inf", "-inf", or "NaN"
8             # _d : denominator
9             # _n : numerator (value = _n/_d)
10             # accuracy : accuracy
11             # precision : precision
12              
13             # You should not look at the innards of a BigRat - use the methods for this.
14              
15             package Math::BigRat;
16              
17 16     16   1354522 use 5.006;
  16         67  
18 16     16   104 use strict;
  16         67  
  16         597  
19 16     16   81 use warnings;
  16         33  
  16         2456  
20              
21 16     16   122 use Carp qw< carp croak >;
  16         36  
  16         1406  
22 16     16   113 use Scalar::Util qw< blessed >;
  16         27  
  16         1029  
23 16     16   16530 use Math::BigFloat qw<>;
  16         51  
  16         26327  
24              
25             our $VERSION = '2.005003';
26             $VERSION =~ tr/_//d;
27              
28             require Exporter;
29             our @ISA = qw< Math::BigFloat >;
30              
31             use overload
32              
33             # overload key: with_assign
34              
35 190     190   3277 '+' => sub { $_[0] -> copy() -> badd($_[1]); },
36              
37 204     204   4017 '-' => sub { my $c = $_[0] -> copy;
38 204 50       849 $_[2] ? $c -> bneg() -> badd( $_[1])
39             : $c -> bsub($_[1]); },
40              
41 208     208   5157 '*' => sub { $_[0] -> copy() -> bmul($_[1]); },
42              
43 186 50   186   4492 '/' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bfdiv($_[0])
44             : $_[0] -> copy() -> bfdiv($_[1]); },
45              
46 75 50   75   1829 '%' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bfmod($_[0])
47             : $_[0] -> copy() -> bfmod($_[1]); },
48              
49 1 50   1   14 '**' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bpow($_[0])
50             : $_[0] -> copy() -> bpow($_[1]); },
51              
52 0 0   0   0 '<<' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bblsft($_[0])
53             : $_[0] -> copy() -> bblsft($_[1]); },
54              
55 0 0   0   0 '>>' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bbrsft($_[0])
56             : $_[0] -> copy() -> bbrsft($_[1]); },
57              
58             # overload key: assign
59              
60 1     1   12 '+=' => sub { $_[0] -> badd($_[1]); },
61              
62 1     1   447 '-=' => sub { $_[0] -> bsub($_[1]); },
63              
64 1     1   14 '*=' => sub { $_[0] -> bmul($_[1]); },
65              
66 0     0   0 '/=' => sub { scalar $_[0] -> bfdiv($_[1]); },
67              
68 0     0   0 '%=' => sub { $_[0] -> bfmod($_[1]); },
69              
70 0     0   0 '**=' => sub { $_[0] -> bpow($_[1]); },
71              
72 0     0   0 '<<=' => sub { $_[0] -> bblsft($_[1]); },
73              
74 0     0   0 '>>=' => sub { $_[0] -> bbrsft($_[1]); },
75              
76             # 'x=' => sub { },
77              
78             # '.=' => sub { },
79              
80             # overload key: num_comparison
81              
82 64 50   64   448 '<' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> blt($_[0])
83             : $_[0] -> blt($_[1]); },
84              
85 0 0   0   0 '<=' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> ble($_[0])
86             : $_[0] -> ble($_[1]); },
87              
88 84 50   84   667 '>' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bgt($_[0])
89             : $_[0] -> bgt($_[1]); },
90              
91 0 0   0   0 '>=' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bge($_[0])
92             : $_[0] -> bge($_[1]); },
93              
94 19     19   416 '==' => sub { $_[0] -> beq($_[1]); },
95              
96 0     0   0 '!=' => sub { $_[0] -> bne($_[1]); },
97              
98             # overload key: 3way_comparison
99              
100 0     0   0 '<=>' => sub { my $cmp = $_[0] -> bcmp($_[1]);
101 0 0 0     0 defined($cmp) && $_[2] ? -$cmp : $cmp; },
102              
103 3525 50   3525   1625607 'cmp' => sub { $_[2] ? "$_[1]" cmp $_[0] -> bstr()
104             : $_[0] -> bstr() cmp "$_[1]"; },
105              
106             # overload key: str_comparison
107              
108             # 'lt' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrlt($_[0])
109             # : $_[0] -> bstrlt($_[1]); },
110             #
111             # 'le' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrle($_[0])
112             # : $_[0] -> bstrle($_[1]); },
113             #
114             # 'gt' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrgt($_[0])
115             # : $_[0] -> bstrgt($_[1]); },
116             #
117             # 'ge' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrge($_[0])
118             # : $_[0] -> bstrge($_[1]); },
119             #
120             # 'eq' => sub { $_[0] -> bstreq($_[1]); },
121             #
122             # 'ne' => sub { $_[0] -> bstrne($_[1]); },
123              
124             # overload key: binary
125              
126 289 50   289   36243 '&' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> band($_[0])
127             : $_[0] -> copy() -> band($_[1]); },
128              
129 0     0   0 '&=' => sub { $_[0] -> band($_[1]); },
130              
131 289 50   289   33587 '|' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bior($_[0])
132             : $_[0] -> copy() -> bior($_[1]); },
133              
134 0     0   0 '|=' => sub { $_[0] -> bior($_[1]); },
135              
136 289 50   289   34234 '^' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bxor($_[0])
137             : $_[0] -> copy() -> bxor($_[1]); },
138              
139 0     0   0 '^=' => sub { $_[0] -> bxor($_[1]); },
140              
141             # '&.' => sub { },
142              
143             # '&.=' => sub { },
144              
145             # '|.' => sub { },
146              
147             # '|.=' => sub { },
148              
149             # '^.' => sub { },
150              
151             # '^.=' => sub { },
152              
153             # overload key: unary
154              
155 0     0   0 'neg' => sub { $_[0] -> copy() -> bneg(); },
156              
157             # '!' => sub { },
158              
159 0     0   0 '~' => sub { $_[0] -> copy() -> bnot(); },
160              
161             # '~.' => sub { },
162              
163             # overload key: mutators
164              
165 20     20   367 '++' => sub { $_[0] -> binc() },
166              
167 20     20   376 '--' => sub { $_[0] -> bdec() },
168              
169             # overload key: func
170              
171 0 0   0   0 'atan2' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> batan2($_[0])
172             : $_[0] -> copy() -> batan2($_[1]); },
173              
174 0     0   0 'cos' => sub { $_[0] -> copy() -> bcos(); },
175              
176 0     0   0 'sin' => sub { $_[0] -> copy() -> bsin(); },
177              
178 0     0   0 'exp' => sub { $_[0] -> copy() -> bexp($_[1]); },
179              
180 0     0   0 'abs' => sub { $_[0] -> copy() -> babs(); },
181              
182 28     28   518 'log' => sub { $_[0] -> copy() -> blog(); },
183              
184 0     0   0 'sqrt' => sub { $_[0] -> copy() -> bsqrt(); },
185              
186 2     2   19 'int' => sub { $_[0] -> copy() -> bint(); },
187              
188             # overload key: conversion
189              
190 0 0   0   0 'bool' => sub { $_[0] -> is_zero() ? '' : 1; },
191              
192 3972     3972   338604 '""' => sub { $_[0] -> bstr(); },
193              
194 6     6   52 '0+' => sub { $_[0] -> numify(); },
195              
196 0     0   0 '=' => sub { $_[0]->copy(); },
197              
198 16     16   181 ;
  16         31  
  16         1366  
199              
200             BEGIN {
201 16     16   10321 *objectify = \&Math::BigInt::objectify;
202              
203 16         41 *AUTOLOAD = \&Math::BigFloat::AUTOLOAD; # can't inherit AUTOLOAD
204 16         56 *as_number = \&as_int;
205 16         56 *is_pos = \&is_positive;
206 16         70256 *is_neg = \&is_negative;
207             }
208              
209             ##############################################################################
210             # Global constants and flags. Access these only via the accessor methods!
211              
212             our $accuracy = undef;
213             our $precision = undef;
214             our $round_mode = 'even';
215             our $div_scale = 40;
216              
217             our $upgrade = undef;
218             our $downgrade = undef;
219              
220             our $_trap_nan = 0; # croak on NaNs?
221             our $_trap_inf = 0; # croak on Infs?
222              
223             my $nan = 'NaN'; # constant for easier life
224              
225             my $LIB = Math::BigInt -> config('lib'); # math backend library
226              
227             # Has import() been called yet? This variable is needed to make "require" work.
228              
229             my $IMPORT = 0;
230              
231             # Compare the following function with @ISA above. This inheritance mess needs a
232             # clean up. When doing so, also consider the BEGIN block and the AUTOLOAD code.
233             # Fixme!
234              
235             sub isa {
236 3409 100   3409 0 771922 return 0 if $_[1] =~ /^Math::Big(Int|Float)/; # we aren't
237 1192         6127 UNIVERSAL::isa(@_);
238             }
239              
240             ##############################################################################
241              
242             sub new {
243             # Create a new Math::BigFloat object from a string or another Math::BigInt,
244             # Math::BigFloat, or Math::BigRat object. See hash keys documented at top.
245              
246 9958     9958 1 4640404 my $self = shift;
247 9958         17789 my $selfref = ref $self;
248 9958   33     39209 my $class = $selfref || $self;
249              
250             # Make "require" work.
251              
252 9958 50       23342 $class -> import() if $IMPORT == 0;
253              
254 9958 50       22234 if (@_ > 2) {
255 0         0 carp("Superfluous arguments to new() ignored.");
256             }
257              
258             # Calling new() with no input arguments has been discouraged for more than
259             # 10 years, but people apparently still use it, so we still support it.
260             # Also, if any of the arguments is undefined, return zero.
261              
262 9958 50 66     66213 if (@_ == 0 ||
      33        
      33        
      66        
      33        
263             @_ == 1 && !defined($_[0]) ||
264             @_ == 2 && (!defined($_[0]) || !defined($_[1])))
265             {
266             #carp("Use of uninitialized value in new()");
267 0         0 return $class -> bzero();
268             }
269              
270 9958         23530 my @args = @_;
271              
272             # Initialize a new object.
273              
274 9958         26436 $self = bless {}, $class;
275              
276             # Special cases for speed and to avoid infinite recursion. The methods
277             # Math::BigInt->as_rat() and Math::BigFloat->as_rat() call
278             # Math::BigRat->as_rat() (i.e., this method) with a scalar (non-ref)
279             # integer argument.
280              
281 9958 100 100     35602 if (@args == 1 && !ref($args[0])) {
282              
283             # "3", "+3", "-3", "+001_2_3e+4"
284              
285 9942 100       72648 if ($args[0] =~ m{
286             ^
287             \s*
288              
289             # optional sign
290             ( [+-]? )
291              
292             # integer mantissa with optional leading zeros
293             0* ( [1-9] \d* (?: _ \d+ )* | 0 )
294              
295             # optional non-negative exponent
296             (?: [eE] \+? ( \d+ (?: _ \d+ )* ) )?
297              
298             \s*
299             $
300             }x)
301             {
302 5299         13269 my $sign = $1;
303 5299         13569 (my $mant = $2) =~ tr/_//d;
304 5299         10600 my $expo = $3;
305 5299 100 66     13267 $mant .= "0" x $expo if defined($expo) && $mant ne "0";
306              
307 5299         21022 $self -> {_n} = $LIB -> _new($mant);
308 5299         14933 $self -> {_d} = $LIB -> _one();
309 5299 100 100     20917 $self -> {sign} = $sign eq "-" && $mant ne "0" ? "-" : "+";
310 5299         17943 $self -> _dng();
311 5299         40647 return $self;
312             }
313              
314             # "3/5", "+3/5", "-3/5", "+001_2_3e+4 / 05_6e7"
315              
316 4643 100       23248 if ($args[0] =~ m{
317             ^
318             \s*
319              
320             # optional leading sign
321             ( [+-]? )
322              
323             # integer mantissa with optional leading zeros
324             0* ( [1-9] \d* (?: _ \d+ )* | 0 )
325              
326             # optional non-negative exponent
327             (?: [eE] \+? ( \d+ (?: _ \d+ )* ) )?
328              
329             # fraction
330             \s* / \s*
331              
332             # non-zero integer mantissa with optional leading zeros
333             0* ( [1-9] \d* (?: _ \d+ )* )
334              
335             # optional non-negative exponent
336             (?: [eE] \+? ( \d+ (?: _ \d+ )* ) )?
337              
338             \s*
339             $
340             }x)
341             {
342 2074         5926 my $sign = $1;
343              
344 2074         5963 (my $mant1 = $2) =~ tr/_//d;
345 2074         4870 my $expo1 = $3;
346 2074 100 66     6021 $mant1 .= "0" x $expo1 if defined($expo1) && $mant1 ne "0";
347              
348 2074         4962 (my $mant2 = $4) =~ tr/_//d;
349 2074         3948 my $expo2 = $5;
350 2074 100 66     5452 $mant2 .= "0" x $expo2 if defined($expo2) && $mant2 ne "0";
351              
352 2074         8275 $self -> {_n} = $LIB -> _new($mant1);
353 2074         5563 $self -> {_d} = $LIB -> _new($mant2);
354 2074 100 100     9393 $self -> {sign} = $sign eq "-" && $mant1 ne "0" ? "-" : "+";
355              
356             my $gcd = $LIB -> _gcd($LIB -> _copy($self -> {_n}),
357 2074         6624 $self -> {_d});
358 2074 100       6834 unless ($LIB -> _is_one($gcd)) {
359 174         940 $self -> {_n} = $LIB -> _div($self->{_n}, $gcd);
360 174         585 $self -> {_d} = $LIB -> _div($self->{_d}, $gcd);
361             }
362              
363 2074 100       6793 $self -> _dng() if $self -> is_int();
364 2074         17516 return $self;
365             }
366              
367             }
368              
369             # If given exactly one argument which is a string that looks like a
370             # fraction, replace this argument with the fraction's numerator and
371             # denominator.
372              
373 2585 100 100     15352 if (@args == 1 && !ref($args[0]) &&
      100        
374             $args[0] =~ m{ ^ \s* ( \S+ ) \s* / \s* ( \S+ ) \s* $ }x)
375             {
376 92         402 @args = ($1, $2);
377             }
378              
379             # Now get the numerator and denominator either by calling as_rat() or by
380             # letting Math::BigFloat->new() parse the argument as a string.
381              
382 2585         4887 my ($n, $d);
383              
384 2585 50       6054 if (@args >= 1) {
385 2585 100 66     7913 if (ref($args[0]) && $args[0] -> can('as_rat')) {
386 16         65 $n = $args[0] -> as_rat();
387             } else {
388 2569         12534 $n = Math::BigFloat -> new($args[0], undef, undef) -> as_rat();
389             }
390             }
391              
392 2571 100       13742 if (@args >= 2) {
393 92 100 66     407 if (ref($args[1]) && $args[1] -> can('as_rat')) {
394 4         9 $d = $args[1] -> as_rat();
395             } else {
396 88         360 $d = Math::BigFloat -> new($args[1], undef, undef) -> as_rat();
397             }
398             }
399              
400 2571 100       5976 $n -> bdiv($d) if defined $d;
401              
402 2571         6888 $self -> {sign} = $n -> {sign};
403 2571         5277 $self -> {_n} = $n -> {_n};
404 2571         4691 $self -> {_d} = $n -> {_d};
405              
406 2571 100 100     5277 $self -> _dng() if ($self -> is_int() ||
      100        
407             $self -> is_inf() ||
408             $self -> is_nan());
409 2571         27710 return $self;
410             }
411              
412             # Create a Math::BigRat from a decimal string. This is an equivalent to
413             # from_hex(), from_oct(), and from_bin(). It is like new() except that it does
414             # not accept anything but a string representing a finite decimal number.
415              
416             sub from_dec {
417 0     0 1 0 my $self = shift;
418 0         0 my $selfref = ref $self;
419 0   0     0 my $class = $selfref || $self;
420              
421             # Make "require" work.
422              
423 0 0       0 $class -> import() if $IMPORT == 0;
424              
425             # Don't modify constant (read-only) objects.
426              
427 0 0 0     0 return $self if $selfref && $self -> modify('from_dec');
428              
429 0         0 my $str = shift;
430 0         0 my @r = @_;
431              
432 0 0       0 if (my @parts = $class -> _dec_str_to_flt_lib_parts($str)) {
433              
434             # If called as a class method, initialize a new object.
435              
436 0 0       0 unless ($selfref) {
437 0         0 $self = bless {}, $class;
438 0         0 $self -> _init();
439             }
440              
441 0         0 my ($mant_sgn, $mant_abs, $expo_sgn, $expo_abs) = @parts;
442              
443 0         0 $self->{sign} = $mant_sgn;
444 0         0 $self->{_n} = $mant_abs;
445              
446 0 0       0 if ($expo_sgn eq "+") {
447 0         0 $self->{_n} = $LIB -> _lsft($self->{_n}, $expo_abs, 10);
448 0         0 $self->{_d} = $LIB -> _one();
449             } else {
450 0         0 $self->{_d} = $LIB -> _1ex($expo_abs);
451             }
452              
453 0         0 my $gcd = $LIB -> _gcd($LIB -> _copy($self->{_n}), $self->{_d});
454 0 0       0 if (!$LIB -> _is_one($gcd)) {
455 0         0 $self->{_n} = $LIB -> _div($self->{_n}, $gcd);
456 0         0 $self->{_d} = $LIB -> _div($self->{_d}, $gcd);
457             }
458              
459 0 0       0 $self -> _dng() if $self -> is_int();
460 0         0 return $self;
461             }
462              
463 0         0 return $self -> bnan(@r);
464             }
465              
466             sub from_hex {
467 3     3 1 1479 my $self = shift;
468 3         9 my $selfref = ref $self;
469 3   33     28 my $class = $selfref || $self;
470              
471             # Make "require" work.
472              
473 3 50       12 $class -> import() if $IMPORT == 0;
474              
475             # Don't modify constant (read-only) objects.
476              
477 3 50 33     11 return $self if $selfref && $self -> modify('from_hex');
478              
479 3         8 my $str = shift;
480 3         8 my @r = @_;
481              
482 3 50       29 if (my @parts = $class -> _hex_str_to_flt_lib_parts($str)) {
483              
484             # If called as a class method, initialize a new object.
485              
486 3 50       13 unless ($selfref) {
487 3         7 $self = bless {}, $class;
488 3         19 $self -> _init();
489             }
490              
491 3         9 my ($mant_sgn, $mant_abs, $expo_sgn, $expo_abs) = @parts;
492              
493 3         7 $self->{sign} = $mant_sgn;
494 3         9 $self->{_n} = $mant_abs;
495              
496 3 50       10 if ($expo_sgn eq "+") {
497              
498             # e.g., 345e+2 => 34500/1
499 3         15 $self->{_n} = $LIB -> _lsft($self->{_n}, $expo_abs, 10);
500 3         10 $self->{_d} = $LIB -> _one();
501              
502             } else {
503              
504             # e.g., 345e-2 => 345/100
505 0         0 $self->{_d} = $LIB -> _1ex($expo_abs);
506              
507             # e.g., 345/100 => 69/20
508 0         0 my $gcd = $LIB -> _gcd($LIB -> _copy($self->{_n}), $self->{_d});
509 0 0       0 unless ($LIB -> _is_one($gcd)) {
510 0         0 $self->{_n} = $LIB -> _div($self->{_n}, $gcd);
511 0         0 $self->{_d} = $LIB -> _div($self->{_d}, $gcd);
512             }
513             }
514              
515 3 50       12 $self -> _dng() if $self -> is_int();
516 3         15 return $self;
517             }
518              
519 0         0 return $self -> bnan(@r);
520             }
521              
522             sub from_oct {
523 3     3 1 1838 my $self = shift;
524 3         9 my $selfref = ref $self;
525 3   33     51 my $class = $selfref || $self;
526              
527             # Make "require" work.
528              
529 3 50       15 $class -> import() if $IMPORT == 0;
530              
531             # Don't modify constant (read-only) objects.
532              
533 3 50 33     12 return $self if $selfref && $self -> modify('from_oct');
534              
535 3         9 my $str = shift;
536 3         11 my @r = @_;
537              
538 3 50       29 if (my @parts = $class -> _oct_str_to_flt_lib_parts($str)) {
539              
540             # If called as a class method, initialize a new object.
541              
542 3 50       22 unless ($selfref) {
543 3         8 $self = bless {}, $class;
544 3         10 $self -> _init();
545             }
546              
547 3         10 my ($mant_sgn, $mant_abs, $expo_sgn, $expo_abs) = @parts;
548              
549 3         6 $self->{sign} = $mant_sgn;
550 3         7 $self->{_n} = $mant_abs;
551              
552 3 50       9 if ($expo_sgn eq "+") {
553              
554             # e.g., 345e+2 => 34500/1
555 3         13 $self->{_n} = $LIB -> _lsft($self->{_n}, $expo_abs, 10);
556 3         10 $self->{_d} = $LIB -> _one();
557              
558             } else {
559              
560             # e.g., 345e-2 => 345/100
561 0         0 $self->{_d} = $LIB -> _1ex($expo_abs);
562              
563             # e.g., 345/100 => 69/20
564 0         0 my $gcd = $LIB -> _gcd($LIB -> _copy($self->{_n}), $self->{_d});
565 0 0       0 unless ($LIB -> _is_one($gcd)) {
566 0         0 $self->{_n} = $LIB -> _div($self->{_n}, $gcd);
567 0         0 $self->{_d} = $LIB -> _div($self->{_d}, $gcd);
568             }
569             }
570              
571 3 50       10 $self -> _dng() if $self -> is_int();
572 3         15 return $self;
573             }
574              
575 0         0 return $self -> bnan(@r);
576             }
577              
578             sub from_bin {
579 3     3 1 1870 my $self = shift;
580 3         7 my $selfref = ref $self;
581 3   33     19 my $class = $selfref || $self;
582              
583             # Make "require" work.
584              
585 3 50       13 $class -> import() if $IMPORT == 0;
586              
587             # Don't modify constant (read-only) objects.
588              
589 3 50 33     11 return $self if $selfref && $self -> modify('from_bin');
590              
591 3         9 my $str = shift;
592 3         7 my @r = @_;
593              
594 3 50       24 if (my @parts = $class -> _bin_str_to_flt_lib_parts($str)) {
595              
596             # If called as a class method, initialize a new object.
597              
598 3 50       9 unless ($selfref) {
599 3         8 $self = bless {}, $class;
600 3         10 $self -> _init();
601             }
602              
603 3         10 my ($mant_sgn, $mant_abs, $expo_sgn, $expo_abs) = @parts;
604              
605 3         7 $self->{sign} = $mant_sgn;
606 3         6 $self->{_n} = $mant_abs;
607              
608 3 50       11 if ($expo_sgn eq "+") {
609              
610             # e.g., 345e+2 => 34500/1
611 3         13 $self->{_n} = $LIB -> _lsft($self->{_n}, $expo_abs, 10);
612 3         9 $self->{_d} = $LIB -> _one();
613              
614             } else {
615              
616             # e.g., 345e-2 => 345/100
617 0         0 $self->{_d} = $LIB -> _1ex($expo_abs);
618              
619             # e.g., 345/100 => 69/20
620 0         0 my $gcd = $LIB -> _gcd($LIB -> _copy($self->{_n}), $self->{_d});
621 0 0       0 unless ($LIB -> _is_one($gcd)) {
622 0         0 $self->{_n} = $LIB -> _div($self->{_n}, $gcd);
623 0         0 $self->{_d} = $LIB -> _div($self->{_d}, $gcd);
624             }
625             }
626              
627 3 50       11 $self -> _dng() if $self -> is_int();
628 3         15 return $self;
629             }
630              
631 0         0 return $self -> bnan(@r);
632             }
633              
634             sub from_bytes {
635 0     0 1 0 my $self = shift;
636 0         0 my $selfref = ref $self;
637 0   0     0 my $class = $selfref || $self;
638              
639             # Make "require" work.
640              
641 0 0       0 $class -> import() if $IMPORT == 0;
642              
643             # Don't modify constant (read-only) objects.
644              
645 0 0 0     0 return $self if $selfref && $self -> modify('from_bytes');
646              
647 0         0 my $str = shift;
648 0         0 my @r = @_;
649              
650             # If called as a class method, initialize a new object.
651              
652 0 0       0 $self = $class -> bzero(@r) unless $selfref;
653              
654 0         0 $self -> {sign} = "+";
655 0         0 $self -> {_n} = $LIB -> _from_bytes($str);
656 0         0 $self -> {_d} = $LIB -> _one();
657              
658 0         0 $self -> _dng();
659 0         0 return $self;
660             }
661              
662             sub from_ieee754 {
663 0     0 1 0 my $self = shift;
664 0         0 my $selfref = ref $self;
665 0   0     0 my $class = $selfref || $self;
666              
667             # Make "require" work.
668              
669 0 0       0 $class -> import() if $IMPORT == 0;
670              
671             # Don't modify constant (read-only) objects.
672              
673 0 0 0     0 return $self if $selfref && $self -> modify('from_ieee754');
674              
675 0         0 my $in = shift;
676 0         0 my $format = shift;
677 0         0 my @r = @_;
678              
679 0         0 my $tmp = Math::BigFloat -> from_ieee754($in, $format, @r);
680              
681 0         0 $tmp = $tmp -> as_rat();
682              
683             # If called as a class method, initialize a new object.
684              
685 0 0       0 $self = $class -> bzero(@r) unless $selfref;
686 0         0 $self -> {sign} = $tmp -> {sign};
687 0         0 $self -> {_n} = $tmp -> {_n};
688 0         0 $self -> {_d} = $tmp -> {_d};
689              
690 0 0       0 $self -> _dng() if $self -> is_int();
691 0         0 return $self;
692             }
693              
694             sub from_fp80 {
695 0     0 1 0 my $self = shift;
696 0         0 my $selfref = ref $self;
697 0   0     0 my $class = $selfref || $self;
698              
699             # Make "require" work.
700              
701 0 0       0 $class -> import() if $IMPORT == 0;
702              
703             # Don't modify constant (read-only) objects.
704              
705 0 0 0     0 return $self if $selfref && $self -> modify('from_fp80');
706              
707 0         0 my $in = shift;
708 0         0 my @r = @_;
709              
710 0         0 my $tmp = Math::BigFloat -> from_fp80($in, @r);
711              
712 0         0 $tmp = $tmp -> as_rat();
713              
714             # If called as a class method, initialize a new object.
715              
716 0 0       0 $self = $class -> bzero(@r) unless $selfref;
717 0         0 $self -> {sign} = $tmp -> {sign};
718 0         0 $self -> {_n} = $tmp -> {_n};
719 0         0 $self -> {_d} = $tmp -> {_d};
720              
721 0 0       0 $self -> _dng() if $self -> is_int();
722 0         0 return $self;
723             }
724              
725             sub from_base {
726 0     0 1 0 my $self = shift;
727 0         0 my $selfref = ref $self;
728 0   0     0 my $class = $selfref || $self;
729              
730             # Make "require" work.
731              
732 0 0       0 $class -> import() if $IMPORT == 0;
733              
734             # Don't modify constant (read-only) objects.
735              
736 0 0 0     0 return $self if $selfref && $self -> modify('from_base');
737              
738 0         0 my ($str, $base, $cs, @r) = @_; # $cs is the collation sequence
739              
740 0 0       0 $base = $class -> new($base) unless ref($base);
741              
742 0 0 0     0 croak("the base must be a finite integer >= 2")
743             if $base < 2 || ! $base -> is_int();
744              
745             # If called as a class method, initialize a new object.
746              
747 0 0       0 $self = $class -> bzero() unless $selfref;
748              
749             # If no collating sequence is given, pass some of the conversions to
750             # methods optimized for those cases.
751              
752 0 0       0 unless (defined $cs) {
753 0 0       0 return $self -> from_bin($str, @r) if $base == 2;
754 0 0       0 return $self -> from_oct($str, @r) if $base == 8;
755 0 0       0 return $self -> from_hex($str, @r) if $base == 16;
756 0 0       0 return $self -> from_dec($str, @r) if $base == 10;
757             }
758              
759 0 0       0 croak("from_base() requires a newer version of the $LIB library.")
760             unless $LIB -> can('_from_base');
761              
762 0         0 $self -> {sign} = '+';
763             $self -> {_n} = $LIB->_from_base($str, $base -> {_n},
764 0 0       0 defined($cs) ? $cs : ());
765 0         0 $self -> {_d} = $LIB->_one();
766 0         0 $self -> bnorm();
767              
768 0         0 $self -> _dng();
769 0         0 return $self;
770             }
771              
772             sub bzero {
773 152     152 1 6334 my $self = shift;
774 152         337 my $selfref = ref $self;
775 152   66     460 my $class = $selfref || $self;
776              
777             # Make "require" work.
778              
779 152 50       486 $class -> import() if $IMPORT == 0;
780              
781             # Don't modify constant (read-only) objects.
782              
783 152 50 66     892 return $self if $selfref && $self -> modify('bzero');
784              
785             # Downgrade?
786              
787 152         458 my $dng = $class -> downgrade();
788 152 100 66     479 if ($dng && $dng ne $class) {
789 2 100       8 return $self -> _dng() -> bzero(@_) if $selfref;
790 1         6 return $dng -> bzero(@_);
791             }
792              
793             # Get the rounding parameters, if any.
794              
795 150         347 my @r = @_;
796              
797             # If called as a class method, initialize a new object.
798              
799 150 100       362 $self = bless {}, $class unless $selfref;
800              
801 150         449 $self -> {sign} = '+';
802 150         541 $self -> {_n} = $LIB -> _zero();
803 150         436 $self -> {_d} = $LIB -> _one();
804              
805             # If rounding parameters are given as arguments, use them. If no rounding
806             # parameters are given, and if called as a class method initialize the new
807             # instance with the class variables.
808              
809             #return $self -> round(@r); # this should work, but doesnt; fixme!
810              
811 150 50       404 if (@r) {
812 0 0 0     0 if (@r >= 2 && defined($r[0]) && defined($r[1])) {
      0        
813 0         0 carp "can't specify both accuracy and precision";
814 0         0 return $self -> bnan();
815             }
816 0         0 $self->{accuracy} = $r[0];
817 0         0 $self->{precision} = $r[1];
818             } else {
819 150 100       377 unless($selfref) {
820 2         9 $self->{accuracy} = $class -> accuracy();
821 2         8 $self->{precision} = $class -> precision();
822             }
823             }
824              
825 150         2038 return $self;
826             }
827              
828             sub bone {
829 64     64 1 19308 my $self = shift;
830 64         144 my $selfref = ref $self;
831 64   66     929 my $class = $selfref || $self;
832              
833             # Make "require" work.
834              
835 64 50       230 $class -> import() if $IMPORT == 0;
836              
837             # Don't modify constant (read-only) objects.
838              
839 64 50 66     578 return $self if $selfref && $self -> modify('bone');
840              
841             # Downgrade?
842              
843 64         226 my $dng = $class -> downgrade();
844 64 100 66     223 if ($dng && $dng ne $class) {
845 1 50       3 return $self -> _dng() -> bone(@_) if $selfref;
846 1         4 return $dng -> bone(@_);
847             }
848              
849             # Get the sign.
850              
851 63         134 my $sign = '+'; # default is to return +1
852 63 100 100     350 if (defined($_[0]) && $_[0] =~ /^\s*([+-])\s*$/) {
853 20         47 $sign = $1;
854 20         33 shift;
855             }
856              
857             # Get the rounding parameters, if any.
858              
859 63         149 my @r = @_;
860              
861             # If called as a class method, initialize a new object.
862              
863 63 100       156 $self = bless {}, $class unless $selfref;
864              
865 63         187 $self -> {sign} = $sign;
866 63         248 $self -> {_n} = $LIB -> _one();
867 63         180 $self -> {_d} = $LIB -> _one();
868              
869             # If rounding parameters are given as arguments, use them. If no rounding
870             # parameters are given, and if called as a class method initialize the new
871             # instance with the class variables.
872              
873             #return $self -> round(@r); # this should work, but doesnt; fixme!
874              
875 63 100       163 if (@r) {
876 16 0 33     52 if (@r >= 2 && defined($r[0]) && defined($r[1])) {
      33        
877 0         0 carp "can't specify both accuracy and precision";
878 0         0 return $self -> bnan();
879             }
880 16         37 $self->{accuracy} = $r[0];
881 16         39 $self->{precision} = $r[1];
882             } else {
883 47 100       152 unless($selfref) {
884 4         52 $self->{accuracy} = $class -> accuracy();
885 4         25 $self->{precision} = $class -> precision();
886             }
887             }
888              
889 63         721 return $self;
890             }
891              
892             sub binf {
893 1073     1073 1 2953 my $self = shift;
894 1073         1830 my $selfref = ref $self;
895 1073   66     3422 my $class = $selfref || $self;
896              
897             {
898 16     16   187 no strict 'refs';
  16         30  
  16         7951  
  1073         1569  
899 1073 100       1460 if (${"${class}::_trap_inf"}) {
  1073         7162  
900 3         712 croak("Tried to create +-inf in $class->binf()");
901             }
902             }
903              
904             # Make "require" work.
905              
906 1070 50       2341 $class -> import() if $IMPORT == 0;
907              
908             # Don't modify constant (read-only) objects.
909              
910 1070 50 66     3378 return $self if $selfref && $self -> modify('binf');
911              
912             # Get the sign.
913              
914 1070         2233 my $sign = '+'; # default is to return positive infinity
915 1070 100 100     7358 if (defined($_[0]) && $_[0] =~ /^\s*([+-])(inf|$)/i) {
916 1015         2763 $sign = $1;
917 1015         1754 shift;
918             }
919              
920             # Get the rounding parameters, if any.
921              
922 1070         1977 my @r = @_;
923              
924             # Downgrade?
925              
926 1070         2911 my $dng = $class -> downgrade();
927 1070 100 66     7065 if ($dng && $dng ne $class) {
928 6 100       29 return $self -> _dng() -> binf($sign, @r) if $selfref;
929 1         6 return $dng -> binf($sign, @r);
930             }
931              
932             # If called as a class method, initialize a new object.
933              
934 1064 100       3001 $self = bless {}, $class unless $selfref;
935              
936 1064         3681 $self -> {sign} = $sign . 'inf';
937 1064         3678 $self -> {_n} = $LIB -> _zero();
938 1064         2990 $self -> {_d} = $LIB -> _one();
939              
940             # If rounding parameters are given as arguments, use them. If no rounding
941             # parameters are given, and if called as a class method initialize the new
942             # instance with the class variables.
943              
944             #return $self -> round(@r); # this should work, but doesnt; fixme!
945              
946 1064 100       2103 if (@r) {
947 4 0 33     26 if (@r >= 2 && defined($r[0]) && defined($r[1])) {
      33        
948 0         0 carp "can't specify both accuracy and precision";
949 0         0 return $self -> bnan();
950             }
951 4         15 $self->{accuracy} = $r[0];
952 4         17 $self->{precision} = $r[1];
953             } else {
954 1060 100       2177 unless($selfref) {
955 868         2724 $self->{accuracy} = $class -> accuracy();
956 868         2683 $self->{precision} = $class -> precision();
957             }
958             }
959              
960 1064         5166 return $self;
961             }
962              
963             sub bnan {
964 1179     1179 1 3499 my $self = shift;
965 1179         1957 my $selfref = ref $self;
966 1179   66     3304 my $class = $selfref || $self;
967              
968             {
969 16     16   128 no strict 'refs';
  16         42  
  16         318582  
  1179         1895  
970 1179 100       1706 if (${"${class}::_trap_nan"}) {
  1179         4426  
971 3         746 croak("Tried to create NaN in $class->bnan()");
972             }
973             }
974              
975             # Make "require" work.
976              
977 1176 50       2476 $class -> import() if $IMPORT == 0;
978              
979             # Don't modify constant (read-only) objects.
980              
981 1176 50 66     3898 return $self if $selfref && $self -> modify('bnan');
982              
983 1176         3030 my $dng = $class -> downgrade();
984 1176 100 66     3079 if ($dng && $dng ne $class) {
985 9 100       45 return $self -> _dng() -> bnan(@_) if $selfref;
986 1         6 return $dng -> bnan(@_);
987             }
988              
989             # Get the rounding parameters, if any.
990              
991 1167         2207 my @r = @_;
992              
993             # If called as a class method, initialize a new object.
994              
995 1167 100       3010 $self = bless {}, $class unless $selfref;
996              
997 1167         3337 $self -> {sign} = $nan;
998 1167         3754 $self -> {_n} = $LIB -> _zero();
999 1167         3002 $self -> {_d} = $LIB -> _one();
1000              
1001             # If rounding parameters are given as arguments, use them. If no rounding
1002             # parameters are given, and if called as a class method initialize the new
1003             # instance with the class variables.
1004              
1005             #return $self -> round(@r); # this should work, but doesnt; fixme!
1006              
1007 1167 50       2540 if (@r) {
1008 0 0 0     0 if (@r >= 2 && defined($r[0]) && defined($r[1])) {
      0        
1009 0         0 carp "can't specify both accuracy and precision";
1010 0         0 return $self -> bnan();
1011             }
1012 0         0 $self->{accuracy} = $r[0];
1013 0         0 $self->{precision} = $r[1];
1014             } else {
1015 1167 100       2499 unless($selfref) {
1016 655         2247 $self->{accuracy} = $class -> accuracy();
1017 655         1933 $self->{precision} = $class -> precision();
1018             }
1019             }
1020              
1021 1167         8476 return $self;
1022             }
1023              
1024             sub bpi {
1025 0     0 1 0 my $self = shift;
1026 0         0 my $selfref = ref $self;
1027 0   0     0 my $class = $selfref || $self;
1028 0         0 my @r = @_; # rounding paramters
1029              
1030             # Make "require" work.
1031              
1032 0 0       0 $class -> import() if $IMPORT == 0;
1033              
1034             # Don't modify constant (read-only) objects.
1035              
1036 0 0 0     0 return $self if $selfref && $self -> modify('bpi');
1037              
1038             # If called as a class method, initialize a new object.
1039              
1040 0 0       0 $self = bless {}, $class unless $selfref;
1041              
1042 0         0 ($self, @r) = $self -> _find_round_parameters(@r);
1043              
1044             # The accuracy, i.e., the number of digits. Pi has one digit before the
1045             # dot, so a precision of 4 digits is equivalent to an accuracy of 5 digits.
1046              
1047 0 0       0 my $n = defined $r[0] ? $r[0]
    0          
1048             : defined $r[1] ? 1 - $r[1]
1049             : $self -> div_scale();
1050              
1051             # The algorithm below creates a fraction from a floating point number. The
1052             # worst case is the number (1 + sqrt(5))/2 (golden ratio), which takes
1053             # almost 2.4*N iterations to find a fraction that is accurate to N digits,
1054             # i.e., the relative error is less than 10**(-N).
1055             #
1056             # This algorithm might be useful in general, so it should probably be moved
1057             # out to a method of its own. XXX
1058              
1059 0         0 my $max_iter = $n * 2.4;
1060              
1061 0         0 my $x = Math::BigFloat -> bpi($n + 10);
1062              
1063 0         0 my $tol = $class -> new("1/10") -> bpow("$n") -> bmul($x);
1064              
1065 0         0 my $n0 = $class -> bzero();
1066 0         0 my $d0 = $class -> bone();
1067              
1068 0         0 my $n1 = $class -> bone();
1069 0         0 my $d1 = $class -> bzero();
1070              
1071 0         0 my ($n2, $d2);
1072              
1073 0         0 my $xtmp = $x -> copy();
1074              
1075 0         0 for (my $iter = 0 ; $iter <= $max_iter ; $iter++) {
1076 0         0 my $t = $xtmp -> copy() -> bint();
1077              
1078 0         0 $n2 = $n1 -> copy() -> bmul($t) -> badd($n0);
1079 0         0 $d2 = $d1 -> copy() -> bmul($t) -> badd($d0);
1080              
1081 0         0 my $err = $n2 -> copy() -> bdiv($d2) -> bsub($x);
1082 0 0       0 last if $err -> copy() -> babs() -> ble($tol);
1083              
1084 0         0 $xtmp -> bsub($t);
1085 0 0       0 last if $xtmp -> is_zero();
1086 0         0 $xtmp -> binv();
1087              
1088 0         0 ($n1, $n0) = ($n2, $n1);
1089 0         0 ($d1, $d0) = ($d2, $d1);
1090             }
1091              
1092 0         0 my $mbr = $n2 -> bdiv($d2);
1093 0         0 %$self = %$mbr;
1094 0         0 return $self;
1095             }
1096              
1097             sub copy {
1098 4080     4080 1 113346 my $self = shift;
1099 4080         6394 my $selfref = ref $self;
1100 4080   33     8889 my $class = $selfref || $self;
1101              
1102             # If called as a class method, the object to copy is the next argument.
1103              
1104 4080 50       7294 $self = shift() unless $selfref;
1105              
1106 4080         8817 my $copy = bless {}, $class;
1107              
1108 4080         11206 $copy->{sign} = $self->{sign};
1109 4080         13030 $copy->{_d} = $LIB->_copy($self->{_d});
1110 4080         9921 $copy->{_n} = $LIB->_copy($self->{_n});
1111 4080 50       9410 $copy->{accuracy} = $self->{accuracy} if defined $self->{accuracy};
1112 4080 50       7949 $copy->{precision} = $self->{precision} if defined $self->{precision};
1113              
1114             #($copy, $copy->{accuracy}, $copy->{precision})
1115             # = $copy->_find_round_parameters(@_);
1116              
1117 4080         13428 return $copy;
1118             }
1119              
1120             sub as_int {
1121 1792 50   1792 1 5354 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1122              
1123             # Temporarily disable upgrading and downgrading.
1124              
1125 1792         4612 my $upg = Math::BigInt -> upgrade();
1126 1792         3984 my $dng = Math::BigInt -> downgrade();
1127 1792         4384 Math::BigInt -> upgrade(undef);
1128 1792         4211 Math::BigInt -> downgrade(undef);
1129              
1130 1792         2283 my $y;
1131 1792 50       3855 if ($x -> isa("Math::BigInt")) {
1132 0         0 $y = $x -> copy();
1133             } else {
1134 1792 100       4631 if ($x -> is_inf()) {
    100          
1135 16         61 $y = Math::BigInt -> binf($x -> sign());
1136             } elsif ($x -> is_nan()) {
1137 8         38 $y = Math::BigInt -> bnan();
1138             } else {
1139 1768         3529 $y = Math::BigInt -> new($x -> copy() -> bint() -> bdstr());
1140             }
1141              
1142             # Copy the remaining instance variables.
1143              
1144 1792         10184 ($y->{accuracy}, $y->{precision}) = ($x->{accuracy}, $x->{precision});
1145             }
1146              
1147 1792         4626 $y -> round(@r);
1148              
1149             # Restore upgrading and downgrading.
1150              
1151 1792         5100 Math::BigInt -> upgrade($upg);
1152 1792         4646 Math::BigInt -> downgrade($dng);
1153              
1154 1792         7073 return $y;
1155             }
1156              
1157             sub as_rat {
1158 2 50   2 1 9 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1159              
1160             # Temporarily disable upgrading and downgrading.
1161              
1162 2         31 require Math::BigRat;
1163 2         12 my $upg = Math::BigRat -> upgrade();
1164 2         6 my $dng = Math::BigRat -> downgrade();
1165 2         8 Math::BigRat -> upgrade(undef);
1166 2         18 Math::BigRat -> downgrade(undef);
1167              
1168 2         3 my $y;
1169 2 50       6 if ($x -> isa("Math::BigRat")) {
1170 2         6 $y = $x -> copy();
1171             } else {
1172              
1173 0 0       0 if ($x -> is_inf()) {
    0          
1174 0         0 $y = Math::BigRat -> binf($x -> sign());
1175             } elsif ($x -> is_nan()) {
1176 0         0 $y = Math::BigRat -> bnan();
1177             } else {
1178 0         0 $y = Math::BigRat -> new($x -> bfstr());
1179             }
1180              
1181             # Copy the remaining instance variables.
1182              
1183 0         0 ($y->{accuracy}, $y->{precision}) = ($x->{accuracy}, $x->{precision});
1184             }
1185              
1186 2         11 $y -> round(@r);
1187              
1188             # Restore upgrading and downgrading.
1189              
1190 2         7 Math::BigRat -> upgrade($upg);
1191 2         6 Math::BigRat -> downgrade($dng);
1192              
1193 2         5 return $y;
1194             }
1195              
1196             sub as_float {
1197 9 50   9 1 51 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1198              
1199             # Disable upgrading and downgrading.
1200              
1201 9         51 require Math::BigFloat;
1202 9         30 my $upg = Math::BigFloat -> upgrade();
1203 9         24 my $dng = Math::BigFloat -> downgrade();
1204 9         257 Math::BigFloat -> upgrade(undef);
1205 9         29 Math::BigFloat -> downgrade(undef);
1206              
1207 9         14 my $y;
1208 9 50       27 if ($x -> isa("Math::BigFloat")) {
1209 0         0 $y = $x -> copy();
1210             } else {
1211 9 50       31 if ($x -> is_inf()) {
    50          
1212 0         0 $y = Math::BigFloat -> binf($x -> sign());
1213             } elsif ($x -> is_nan()) {
1214 0         0 $y = Math::BigFloat -> bnan();
1215             } else {
1216 9 50       20 if ($x -> isa("Math::BigRat")) {
1217 9 100       24 if ($x -> is_int()) {
1218 7         30 $y = Math::BigFloat -> new($x -> bdstr());
1219             } else {
1220 2         8 my ($num, $den) = $x -> fparts();
1221 2         8 my $str = $num -> as_float() -> bdiv($den, @r) -> bdstr();
1222 2         12 $y = Math::BigFloat -> new($str);
1223             }
1224             } else {
1225 0         0 $y = Math::BigFloat -> new($x -> bdstr());
1226             }
1227             }
1228              
1229             # Copy the remaining instance variables.
1230              
1231 9         45 ($y->{accuracy}, $y->{precision}) = ($x->{accuracy}, $x->{precision});
1232             }
1233              
1234 9         31 $y -> round(@r);
1235              
1236             # Restore upgrading and downgrading.
1237              
1238 9         32 Math::BigFloat -> upgrade($upg);
1239 9         31 Math::BigFloat -> downgrade($dng);
1240              
1241 9         36 return $y;
1242             }
1243              
1244             sub is_zero {
1245             # return true if arg (BRAT or num_str) is zero
1246 2095 50   2095 1 6864 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1247              
1248 2095 100 100     9722 return 1 if $x->{sign} eq '+' && $LIB->_is_zero($x->{_n});
1249 1826         6063 return 0;
1250             }
1251              
1252             sub is_one {
1253             # return true if arg (BRAT or num_str) is +1 or -1 if signis given
1254 1148 50   1148 1 5690 my (undef, $x, $sign) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
1255              
1256 1148 100       2342 if (defined($sign)) {
1257 742 50 66     3379 croak 'is_one(): sign argument must be "+" or "-"'
1258             unless $sign eq '+' || $sign eq '-';
1259             } else {
1260 406         748 $sign = '+';
1261             }
1262              
1263 1148 100       4612 return 0 if $x->{sign} ne $sign;
1264 637 100 100     2636 return 1 if $LIB->_is_one($x->{_n}) && $LIB->_is_one($x->{_d});
1265 483         1955 return 0;
1266             }
1267              
1268             sub is_odd {
1269             # return true if arg (BFLOAT or num_str) is odd or false if even
1270 100 50   100 1 1233 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1271              
1272 100 100       402 return 0 unless $x -> is_finite();
1273 84 100 100     352 return 1 if $LIB->_is_one($x->{_d}) && $LIB->_is_odd($x->{_n});
1274 44         343 return 0;
1275             }
1276              
1277             sub is_even {
1278             # return true if arg (BINT or num_str) is even or false if odd
1279 72 50   72 1 1619 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1280              
1281 72 100       504 return 0 unless $x -> is_finite();
1282 60 100 100     386 return 1 if $LIB->_is_one($x->{_d}) && $LIB->_is_even($x->{_n});
1283 36         530 return 0;
1284             }
1285              
1286             sub is_int {
1287             # return true if arg (BRAT or num_str) is an integer
1288 15376 50   15376 1 35441 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1289              
1290 15376 100 100     35524 return 1 if $x -> is_finite() && $LIB->_is_one($x->{_d});
1291 7841         23225 return 0;
1292             }
1293              
1294             ##############################################################################
1295              
1296             sub config {
1297 217     217 1 1145808 my $self = shift;
1298 217   50     1131 my $class = ref($self) || $self || __PACKAGE__;
1299              
1300             # Getter/accessor.
1301              
1302 217 100 100     937 if (@_ == 1 && ref($_[0]) ne 'HASH') {
1303 155         296 my $param = shift;
1304 155 100       315 return $class if $param eq 'class';
1305 154 50       309 return $LIB if $param eq 'with';
1306 154         550 return $self -> SUPER::config($param);
1307             }
1308              
1309             # Setter.
1310              
1311 62         330 my $cfg = $self -> SUPER::config(@_);
1312              
1313             # We need only to override the ones that are different from our parent.
1314              
1315 60 100       197 unless (ref($self)) {
1316 48         136 $cfg->{class} = $class;
1317 48         86 $cfg->{with} = $LIB;
1318             }
1319              
1320 60         313 $cfg;
1321             }
1322              
1323             ##############################################################################
1324             # comparing
1325              
1326             sub bcmp {
1327             # compare two signed numbers
1328              
1329             # set up parameters
1330 200 100 66 200 1 1306 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
1331             ? (ref($_[0]), @_)
1332             : objectify(2, @_);
1333              
1334 200 50       462 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
1335              
1336 200 100 66     730 if (!$x -> is_finite() || !$y -> is_finite()) {
1337             # $x is NaN and/or $y is NaN
1338 16 50 33     49 return if $x -> is_nan() || $y -> is_nan();
1339             # $x and $y are both either +inf or -inf
1340 16 50 33     60 return 0 if $x->{sign} eq $y->{sign} && $x -> is_inf();
1341             # $x = +inf and $y < +inf
1342 16 100       64 return +1 if $x -> is_inf("+");
1343             # $x = -inf and $y > -inf
1344 8 50       32 return -1 if $x -> is_inf("-");
1345             # $x < +inf and $y = +inf
1346 0 0       0 return -1 if $y -> is_inf("+");
1347             # $x > -inf and $y = -inf
1348 0         0 return +1;
1349             }
1350              
1351             # $x >= 0 and $y < 0
1352 184 100 100     894 return 1 if $x->{sign} eq '+' && $y->{sign} eq '-';
1353             # $x < 0 and $y >= 0
1354 128 100 100     592 return -1 if $x->{sign} eq '-' && $y->{sign} eq '+';
1355              
1356             # At this point, we know that $x and $y have the same sign.
1357              
1358             # shortcut
1359 109         486 my $xz = $LIB->_is_zero($x->{_n});
1360 109         393 my $yz = $LIB->_is_zero($y->{_n});
1361 109 50 66     468 return 0 if $xz && $yz; # 0 <=> 0
1362 109 100 66     424 return -1 if $xz && $y->{sign} eq '+'; # 0 <=> +y
1363 97 100 66     376 return 1 if $yz && $x->{sign} eq '+'; # +x <=> 0
1364              
1365 89         364 my $t = $LIB->_mul($LIB->_copy($x->{_n}), $y->{_d});
1366 89         288 my $u = $LIB->_mul($LIB->_copy($y->{_n}), $x->{_d});
1367              
1368 89         460 my $cmp = $LIB->_acmp($t, $u); # signs are equal
1369 89 100       305 $cmp = -$cmp if $x->{sign} eq '-'; # both are '-' => reverse
1370 89         383 $cmp;
1371             }
1372              
1373             sub bacmp {
1374             # compare two numbers (as unsigned)
1375              
1376             # set up parameters
1377 197 50 33 197 1 4194 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
1378             ? (ref($_[0]), @_)
1379             : objectify(2, @_);
1380              
1381 197 50       499 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
1382              
1383             # handle +-inf and NaN
1384 197 100 100     473 if (!$x -> is_finite() || !$y -> is_finite()) {
1385 140 100 100     343 return if ($x -> is_nan() || $y -> is_nan());
1386 112 100 100     239 return 0 if $x -> is_inf() && $y -> is_inf();
1387 96 100 66     190 return 1 if $x -> is_inf() && !$y -> is_inf();
1388 48         591 return -1;
1389             }
1390              
1391 57         216 my $t = $LIB->_mul($LIB->_copy($x->{_n}), $y->{_d});
1392 57         159 my $u = $LIB->_mul($LIB->_copy($y->{_n}), $x->{_d});
1393 57         206 $LIB->_acmp($t, $u); # ignore signs
1394             }
1395              
1396             ##############################################################################
1397             # sign manipulation
1398              
1399             sub bneg {
1400             # (BRAT or num_str) return BRAT
1401             # negate number or make a negated number from string
1402 87 50   87 1 1322 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1403              
1404             # Don't modify constant (read-only) objects.
1405              
1406 87 50       355 return $x if $x -> modify('bneg');
1407              
1408             # for +0 do not negate (to have always normalized +0). Does nothing for 'NaN'
1409             $x->{sign} =~ tr/+-/-+/
1410 87 100 100     548 unless ($x->{sign} eq '+' && $LIB->_is_zero($x->{_n}));
1411              
1412 87         319 $x -> round(@r);
1413 87 100 100     198 $x -> _dng() if $x -> is_int() || $x -> is_inf() || $x -> is_nan();
      100        
1414 87         1216 return $x;
1415             }
1416              
1417             sub bnorm {
1418             # reduce the number to the shortest form
1419 1292 100   1292 1 8843 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1420              
1421             # Both parts must be objects of whatever we are using today.
1422 1292 50       3883 if (my $c = $LIB->_check($x->{_n})) {
1423 0         0 croak("n did not pass the self-check ($c) in bnorm()");
1424             }
1425 1292 50       3541 if (my $c = $LIB->_check($x->{_d})) {
1426 0         0 croak("d did not pass the self-check ($c) in bnorm()");
1427             }
1428              
1429             # no normalize for NaN, inf etc.
1430 1292 100       3626 if (!$x -> is_finite()) {
1431 51         140 $x -> _dng();
1432 51         688 return $x;
1433             }
1434              
1435             # normalize zeros to 0/1
1436 1241 100       3657 if ($LIB->_is_zero($x->{_n})) {
1437 155         346 $x->{sign} = '+'; # never leave a -0
1438 155 100       482 $x->{_d} = $LIB->_one() unless $LIB->_is_one($x->{_d});
1439 155         544 $x -> _dng();
1440 155         769 return $x;
1441             }
1442              
1443             # n/1
1444 1086 100       3197 if ($LIB->_is_one($x->{_d})) {
1445 581         1757 $x -> _dng();
1446 581         3469 return $x; # no need to reduce
1447             }
1448              
1449             # Compute the GCD.
1450 505         1608 my $gcd = $LIB->_gcd($LIB->_copy($x->{_n}), $x->{_d});
1451 505 100       1464 if (!$LIB->_is_one($gcd)) {
1452 152         736 $x->{_n} = $LIB->_div($x->{_n}, $gcd);
1453 152         452 $x->{_d} = $LIB->_div($x->{_d}, $gcd);
1454             }
1455              
1456 505         1869 $x;
1457             }
1458              
1459             sub binc {
1460             # increment value (add 1)
1461 27 50   27 1 123 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1462              
1463             # Don't modify constant (read-only) objects.
1464              
1465 27 50       107 return $x if $x -> modify('binc');
1466              
1467 27 100       96 if (!$x -> is_finite()) { # NaN, inf, -inf
1468 6         57 $x -> round(@r);
1469 6         20 $x -> _dng();
1470 6         118 return $x;
1471             }
1472              
1473 21 100       61 if ($x->{sign} eq '-') {
1474 12 100       62 if ($LIB->_acmp($x->{_n}, $x->{_d}) < 0) {
1475             # -1/3 ++ => 2/3 (overflow at 0)
1476 8         34 $x->{_n} = $LIB->_sub($LIB->_copy($x->{_d}), $x->{_n});
1477 8         23 $x->{sign} = '+';
1478             } else {
1479 4         25 $x->{_n} = $LIB->_sub($x->{_n}, $x->{_d}); # -5/2 => -3/2
1480             }
1481             } else {
1482 9         59 $x->{_n} = $LIB->_add($x->{_n}, $x->{_d}); # 5/2 => 7/2
1483             }
1484              
1485 21         75 $x -> bnorm(); # is this necessary? check! XXX
1486 21         85 $x -> round(@r);
1487 21 50 66     49 $x -> _dng() if $x -> is_int() || $x -> is_inf() || $x -> is_nan();
      66        
1488 21         232 return $x;
1489             }
1490              
1491             sub bdec {
1492             # decrement value (subtract 1)
1493 27 50   27 1 139 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1494              
1495             # Don't modify constant (read-only) objects.
1496              
1497 27 50       111 return $x if $x -> modify('bdec');
1498              
1499 27 100       75 if (!$x -> is_finite()) { # NaN, inf, -inf
1500 6         27 $x -> round(@r);
1501 6         22 $x -> _dng();
1502 6         58 return $x;
1503             }
1504              
1505 21 100       65 if ($x->{sign} eq '-') {
1506 4         27 $x->{_n} = $LIB->_add($x->{_n}, $x->{_d}); # -5/2 => -7/2
1507             } else {
1508 17 100       85 if ($LIB->_acmp($x->{_n}, $x->{_d}) < 0) # n < d?
1509             {
1510             # 1/3 -- => -2/3
1511 9         32 $x->{_n} = $LIB->_sub($LIB->_copy($x->{_d}), $x->{_n});
1512 9         24 $x->{sign} = '-';
1513             } else {
1514 8         47 $x->{_n} = $LIB->_sub($x->{_n}, $x->{_d}); # 5/2 => 3/2
1515             }
1516             }
1517              
1518 21         102 $x -> bnorm(); # is this necessary? check! XXX
1519 21         79 $x -> round(@r);
1520 21 50 66     62 $x -> _dng() if $x -> is_int() || $x -> is_inf() || $x -> is_nan();
      66        
1521 21         220 return $x;
1522             }
1523              
1524             ##############################################################################
1525             # mul/add/div etc
1526              
1527             sub badd {
1528             # add two rational numbers
1529              
1530             # set up parameters
1531 516 100 66 516 1 3089 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
1532             ? (ref($_[0]), @_)
1533             : objectify(2, @_);
1534              
1535             # Don't modify constant (read-only) objects.
1536              
1537 516 50       1358 return $x if $x -> modify('badd');
1538              
1539 516 100 100     1341 unless ($x -> is_finite() && $y -> is_finite()) {
1540 96 100 100     216 if ($x -> is_nan() || $y -> is_nan()) {
    100          
    100          
    50          
    0          
1541 60         150 return $x -> bnan(@r);
1542             } elsif ($x -> is_inf("+")) {
1543 17 100       74 return $x -> bnan(@r) if $y -> is_inf("-");
1544 9         43 return $x -> binf("+", @r);
1545             } elsif ($x -> is_inf("-")) {
1546 17 100       50 return $x -> bnan(@r) if $y -> is_inf("+");
1547 9         42 return $x -> binf("-", @r);
1548             } elsif ($y -> is_inf("+")) {
1549 2         12 return $x -> binf("+", @r);
1550             } elsif ($y -> is_inf("-")) {
1551 0         0 return $x -> binf("-", @r);
1552             }
1553             }
1554              
1555             # 1 1 gcd(3, 4) = 1 1*3 + 1*4 7
1556             # - + - = --------- = --
1557             # 4 3 4*3 12
1558              
1559             # we do not compute the gcd() here, but simple do:
1560             # 5 7 5*3 + 7*4 43
1561             # - + - = --------- = --
1562             # 4 3 4*3 12
1563              
1564             # and bnorm() will then take care of the rest
1565              
1566             # 5 * 3
1567 420         1763 $x->{_n} = $LIB->_mul($x->{_n}, $y->{_d});
1568              
1569             # 7 * 4
1570 420         1360 my $m = $LIB->_mul($LIB->_copy($y->{_n}), $x->{_d});
1571              
1572             # 5 * 3 + 7 * 4
1573 420         1902 ($x->{_n}, $x->{sign}) = $LIB -> _sadd($x->{_n}, $x->{sign}, $m, $y->{sign});
1574              
1575             # 4 * 3
1576 420         1327 $x->{_d} = $LIB->_mul($x->{_d}, $y->{_d});
1577              
1578             # normalize result, and possible round
1579 420         1286 $x -> bnorm() -> round(@r);
1580             }
1581              
1582             sub bsub {
1583             # subtract two rational numbers
1584              
1585             # set up parameters
1586 312 100 66 312 1 1941 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
1587             ? (ref($_[0]), @_)
1588             : objectify(2, @_);
1589              
1590             # Don't modify constant (read-only) objects.
1591              
1592 312 50       1099 return $x if $x -> modify('bsub');
1593              
1594             # flip sign of $x, call badd(), then flip sign of result
1595             $x->{sign} =~ tr/+-/-+/
1596 312 100 100     1265 unless $x->{sign} eq '+' && $x -> is_zero(); # not -0
1597 312         971 $x = $x -> badd($y, @r); # does norm and round
1598             $x->{sign} =~ tr/+-/-+/
1599 312 100 100     1248 unless $x->{sign} eq '+' && $x -> is_zero(); # not -0
1600              
1601 312         866 $x -> bnorm();
1602             }
1603              
1604             sub bmul {
1605             # multiply two rational numbers
1606              
1607             # set up parameters
1608 316 100 66 316 1 2027 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
1609             ? (ref($_[0]), @_)
1610             : objectify(2, @_);
1611              
1612             # Don't modify constant (read-only) objects.
1613              
1614 316 50       1032 return $x if $x -> modify('bmul');
1615              
1616 316 100 100     948 return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
1617              
1618             # inf handling
1619 287 100 100     789 if ($x -> is_inf() || $y -> is_inf()) {
1620 49 50 33     209 return $x -> bnan(@r) if $x -> is_zero() || $y -> is_zero();
1621             # result will always be +-inf:
1622             # +inf * +/+inf => +inf, -inf * -/-inf => +inf
1623             # +inf * -/-inf => -inf, -inf * +/+inf => -inf
1624 49 100 100     434 return $x -> binf(@r) if $x -> is_positive() && $y -> is_positive();
1625 32 100 100     216 return $x -> binf(@r) if $x -> is_negative() && $y -> is_negative();
1626 24         85 return $x -> binf('-', @r);
1627             }
1628              
1629 238 50       758 return $x -> _upg() -> bmul($y, @r) if $class -> upgrade();
1630              
1631 238 100 100     744 if ($x -> is_zero() || $y -> is_zero()) {
1632 33         132 return $x -> bzero(@r);
1633             }
1634              
1635             # According to Knuth, this can be optimized by doing gcd twice (for d
1636             # and n) and reducing in one step.
1637             #
1638             # p s p * s (p / gcd(p, r)) * (s / gcd(s, q))
1639             # - * - = ----- = ---------------------------------
1640             # q r q * r (q / gcd(s, q)) * (r / gcd(p, r))
1641              
1642 205         738 my $gcd_pr = $LIB -> _gcd($LIB -> _copy($x->{_n}), $y->{_d});
1643 205         706 my $gcd_sq = $LIB -> _gcd($LIB -> _copy($y->{_n}), $x->{_d});
1644              
1645             $x->{_n} = $LIB -> _mul(scalar $LIB -> _div($x->{_n}, $gcd_pr),
1646 205         859 scalar $LIB -> _div($LIB -> _copy($y->{_n}),
1647             $gcd_sq));
1648             $x->{_d} = $LIB -> _mul(scalar $LIB -> _div($x->{_d}, $gcd_sq),
1649 205         816 scalar $LIB -> _div($LIB -> _copy($y->{_d}),
1650             $gcd_pr));
1651              
1652             # compute new sign
1653 205 100       789 $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
1654              
1655 205         827 $x -> bnorm(); # this is probably redundant; check XXX
1656 205         759 $x -> round(@r);
1657 205 100       502 $x -> _dng() if $x -> is_int();
1658 205         2734 return $x;
1659             }
1660              
1661             *bdiv = \&bfdiv;
1662             *bmod = \&bfmod;
1663              
1664             sub bfdiv {
1665             # (dividend: BRAT or num_str, divisor: BRAT or num_str) return
1666             # (BRAT, BRAT) (quo, rem) or BRAT (only rem)
1667              
1668             # Set up parameters.
1669 395 100 66 395 1 3342 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
1670             ? (ref($_[0]), @_)
1671             : objectify(2, @_);
1672              
1673             ###########################################################################
1674             # Code for all classes that share the common interface.
1675             ###########################################################################
1676              
1677             # Don't modify constant (read-only) objects.
1678              
1679 395 50       1422 return $x if $x -> modify('bfdiv');
1680              
1681 395         718 my $wantarray = wantarray; # call only once
1682              
1683             # At least one argument is NaN. This is handled the same way as in
1684             # Math::BigInt -> bfdiv().
1685              
1686 395 100 100     1352 if ($x -> is_nan() || $y -> is_nan()) {
1687 22 50       108 return $wantarray ? ($x -> bnan(@r), $class -> bnan(@r))
1688             : $x -> bnan(@r);
1689             }
1690              
1691             # Divide by zero and modulo zero. This is handled the same way as in
1692             # Math::BigInt -> bfdiv(). See the comments in the code implementing that
1693             # method.
1694              
1695 373 100       1223 if ($y -> is_zero()) {
1696 36         1993 my $rem;
1697 36 100       118 if ($wantarray) {
1698 12         41 $rem = $x -> copy() -> round(@r);
1699 12 50       1849 $rem -> _dng() if $rem -> is_int();
1700             }
1701 36 100       99 if ($x -> is_zero()) {
1702 10         53 $x -> bnan(@r);
1703             } else {
1704 26         119 $x -> binf($x -> {sign}, @r);
1705             }
1706 32 100       532 return $wantarray ? ($x, $rem) : $x;
1707             }
1708              
1709             # Numerator (dividend) is +/-inf. This is handled the same way as in
1710             # Math::BigInt -> bfdiv(). See the comment in the code for Math::BigInt ->
1711             # bfdiv() for further details.
1712              
1713 337 100       961 if ($x -> is_inf()) {
1714 20         38 my $rem;
1715 20 50       55 $rem = $class -> bnan(@r) if $wantarray;
1716 20 100       71 if ($y -> is_inf()) {
1717 4         23 $x -> bnan(@r);
1718             } else {
1719 16 100       60 my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
1720 16         58 $x -> binf($sign, @r);
1721             }
1722 20 50       68 return $wantarray ? ($x, $rem) : $x;
1723             }
1724              
1725             # Denominator (divisor) is +/-inf. This is handled the same way as in
1726             # Math::BigFloat -> bfdiv(). See the comments in the code implementing that
1727             # method.
1728              
1729 317 100       712 if ($y -> is_inf()) {
1730 24         47 my $rem;
1731 24 50       68 if ($wantarray) {
1732 0 0 0     0 if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
1733 0         0 $rem = $x -> copy() -> round(@r);
1734 0 0       0 $rem -> _dng() if $rem -> is_int();
1735 0         0 $x -> bzero(@r);
1736             } else {
1737 0         0 $rem = $class -> binf($y -> {sign}, @r);
1738 0         0 $x -> bone('-', @r);
1739             }
1740             } else {
1741 24         136 $x -> bzero(@r);
1742             }
1743 24 50       231 return $wantarray ? ($x, $rem) : $x;
1744             }
1745              
1746             # At this point, both the numerator and denominator are finite, non-zero
1747             # numbers.
1748              
1749             # According to Knuth, this can be optimized by doing gcd twice (for d and n)
1750             # and reducing in one step. This would save us the bnorm().
1751             #
1752             # p r p * s (p / gcd(p, r)) * (s / gcd(s, q))
1753             # - / - = ----- = ---------------------------------
1754             # q s q * r (q / gcd(s, q)) * (r / gcd(p, r))
1755              
1756 293         1305 $x->{_n} = $LIB->_mul($x->{_n}, $y->{_d});
1757 293         969 $x->{_d} = $LIB->_mul($x->{_d}, $y->{_n});
1758              
1759             # compute new sign
1760 293 100       1012 $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
1761              
1762 293         1064 $x -> bnorm();
1763 293 100       747 if ($wantarray) {
1764 28         107 my $rem = $x -> copy();
1765 28         126 $x -> bfloor();
1766 28         91 $x -> round(@r);
1767 28         88 $rem -> bsub($x -> copy()) -> bmul($y);
1768 28 50       155 $x -> _dng() if $x -> is_int();
1769 28 100       91 $rem -> _dng() if $rem -> is_int();
1770 28         168 return $x, $rem;
1771             }
1772              
1773 265 100       871 $x -> _dng() if $x -> is_int();
1774 265         3064 return $x;
1775             }
1776              
1777             sub bfmod {
1778             # This is the remainder after floored division.
1779              
1780             # Set up parameters.
1781 75 50 33 75 1 568 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
1782             ? (ref($_[0]), @_)
1783             : objectify(2, @_);
1784              
1785             ###########################################################################
1786             # Code for all classes that share the common interface.
1787             ###########################################################################
1788              
1789             # Don't modify constant (read-only) objects.
1790              
1791 75 50       306 return $x if $x -> modify('bfmod');
1792              
1793             # At least one argument is NaN. This is handled the same way as in
1794             # Math::BigInt -> bfmod().
1795              
1796 75 100 100     311 if ($x -> is_nan() || $y -> is_nan()) {
1797 8         25 return $x -> bnan();
1798             }
1799              
1800             # Modulo zero. This is handled the same way as in Math::BigInt -> bfmod().
1801              
1802 67 50       268 if ($y -> is_zero()) {
1803 0         0 return $x -> round();
1804             }
1805              
1806             # Numerator (dividend) is +/-inf. This is handled the same way as in
1807             # Math::BigInt -> bfmod().
1808              
1809 67 50       233 if ($x -> is_inf()) {
1810 0         0 return $x -> bnan();
1811             }
1812              
1813             # Denominator (divisor) is +/-inf. This is handled the same way as in
1814             # Math::BigInt -> bfmod().
1815              
1816 67 50       165 if ($y -> is_inf()) {
1817 0 0 0     0 if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
1818 0 0       0 $x -> _dng() if $x -> is_int();
1819 0         0 return $x;
1820             } else {
1821 0         0 return $x -> binf($y -> sign());
1822             }
1823             }
1824              
1825             # At this point, both the numerator and denominator are finite numbers, and
1826             # the denominator (divisor) is non-zero.
1827              
1828 67 50       157 if ($x -> is_zero()) { # 0 / 7 = 0, mod 0
1829 0         0 return $x -> bzero();
1830             }
1831              
1832             # Compute $x - $y * floor($x / $y). This can be optimized by working on the
1833             # library thingies directly. XXX
1834              
1835 67         180 $x -> bsub($x -> copy() -> bfdiv($y) -> bfloor() -> bmul($y));
1836 67         396 return $x -> round(@r);
1837             }
1838              
1839             sub btdiv {
1840             # (dividend: BRAT or num_str, divisor: BRAT or num_str) return
1841             # (BRAT, BRAT) (quo, rem) or BRAT (only rem)
1842              
1843             # Set up parameters.
1844 0 0 0 0 1 0 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
1845             ? (ref($_[0]), @_)
1846             : objectify(2, @_);
1847              
1848             ###########################################################################
1849             # Code for all classes that share the common interface.
1850             ###########################################################################
1851              
1852             # Don't modify constant (read-only) objects.
1853              
1854 0 0       0 return $x if $x -> modify('btdiv');
1855              
1856 0         0 my $wantarray = wantarray; # call only once
1857              
1858             # At least one argument is NaN. This is handled the same way as in
1859             # Math::BigInt -> btdiv().
1860              
1861 0 0 0     0 if ($x -> is_nan() || $y -> is_nan()) {
1862 0 0       0 return $wantarray ? ($x -> bnan(@r), $class -> bnan(@r))
1863             : $x -> bnan(@r);
1864             }
1865              
1866             # Divide by zero and modulo zero. This is handled the same way as in
1867             # Math::BigInt -> btdiv(). See the comments in the code implementing that
1868             # method.
1869              
1870 0 0       0 if ($y -> is_zero()) {
1871 0         0 my $rem;
1872 0 0       0 if ($wantarray) {
1873 0         0 $rem = $x -> copy() -> round(@r);
1874 0 0       0 $rem -> _dng() if $rem -> is_int();
1875             }
1876 0 0       0 if ($x -> is_zero()) {
1877 0         0 $x -> bnan(@r);
1878             } else {
1879 0         0 $x -> binf($x -> {sign}, @r);
1880             }
1881 0 0       0 return $wantarray ? ($x, $rem) : $x;
1882             }
1883              
1884             # Numerator (dividend) is +/-inf. This is handled the same way as in
1885             # Math::BigInt -> btdiv(). See the comment in the code for Math::BigInt ->
1886             # btdiv() for further details.
1887              
1888 0 0       0 if ($x -> is_inf()) {
1889 0         0 my $rem;
1890 0 0       0 $rem = $class -> bnan(@r) if $wantarray;
1891 0 0       0 if ($y -> is_inf()) {
1892 0         0 $x -> bnan(@r);
1893             } else {
1894 0 0       0 my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
1895 0         0 $x -> binf($sign, @r);
1896             }
1897 0 0       0 return $wantarray ? ($x, $rem) : $x;
1898             }
1899              
1900             # Denominator (divisor) is +/-inf. This is handled the same way as in
1901             # Math::BigFloat -> btdiv(). See the comments in the code implementing that
1902             # method.
1903              
1904 0 0       0 if ($y -> is_inf()) {
1905 0         0 my $rem;
1906 0 0       0 if ($wantarray) {
1907 0         0 $rem = $x -> copy();
1908 0 0       0 $rem -> _dng() if $rem -> is_int();
1909 0         0 $x -> bzero();
1910 0         0 return $x, $rem;
1911             } else {
1912 0 0       0 if ($y -> is_inf()) {
1913 0 0 0     0 if ($x -> is_nan() || $x -> is_inf()) {
1914 0         0 return $x -> bnan();
1915             } else {
1916 0         0 return $x -> bzero();
1917             }
1918             }
1919             }
1920             }
1921              
1922 0 0       0 if ($x -> is_zero()) {
1923 0         0 $x -> round(@r);
1924 0 0       0 $x -> _dng() if $x -> is_int();
1925 0 0       0 if ($wantarray) {
1926 0         0 my $rem = $class -> bzero(@r);
1927 0         0 return $x, $rem;
1928             }
1929 0         0 return $x;
1930             }
1931              
1932             # At this point, both the numerator and denominator are finite, non-zero
1933             # numbers.
1934              
1935             # According to Knuth, this can be optimized by doing gcd twice (for d and n)
1936             # and reducing in one step. This would save us the bnorm().
1937             #
1938             # p r p * s (p / gcd(p, r)) * (s / gcd(s, q))
1939             # - / - = ----- = ---------------------------------
1940             # q s q * r (q / gcd(s, q)) * (r / gcd(p, r))
1941              
1942 0         0 $x->{_n} = $LIB->_mul($x->{_n}, $y->{_d});
1943 0         0 $x->{_d} = $LIB->_mul($x->{_d}, $y->{_n});
1944              
1945             # compute new sign
1946 0 0       0 $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
1947              
1948 0         0 $x -> bnorm();
1949 0 0       0 if ($wantarray) {
1950 0         0 my $rem = $x -> copy();
1951 0         0 $x -> bint();
1952 0         0 $x -> round(@r);
1953 0         0 $rem -> bsub($x -> copy()) -> bmul($y);
1954 0 0       0 $x -> _dng() if $x -> is_int();
1955 0 0       0 $rem -> _dng() if $rem -> is_int();
1956 0         0 return $x, $rem;
1957             }
1958              
1959 0 0       0 $x -> _dng() if $x -> is_int();
1960 0         0 return $x;
1961             }
1962              
1963             sub btmod {
1964             # This is the remainder after floored division.
1965              
1966             # Set up parameters.
1967 0 0 0 0 1 0 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
1968             ? (ref($_[0]), @_)
1969             : objectify(2, @_);
1970              
1971             ###########################################################################
1972             # Code for all classes that share the common interface.
1973             ###########################################################################
1974              
1975             # Don't modify constant (read-only) objects.
1976              
1977 0 0       0 return $x if $x -> modify('btmod');
1978              
1979             # At least one argument is NaN. This is handled the same way as in
1980             # Math::BigInt -> btmod().
1981              
1982 0 0 0     0 if ($x -> is_nan() || $y -> is_nan()) {
1983 0         0 return $x -> bnan();
1984             }
1985              
1986             # Modulo zero. This is handled the same way as in Math::BigInt -> btmod().
1987              
1988 0 0       0 if ($y -> is_zero()) {
1989 0         0 return $x -> round();
1990             }
1991              
1992             # Numerator (dividend) is +/-inf. This is handled the same way as in
1993             # Math::BigInt -> btmod().
1994              
1995 0 0       0 if ($x -> is_inf()) {
1996 0         0 return $x -> bnan();
1997             }
1998              
1999             # Denominator (divisor) is +/-inf. This is handled the same way as in
2000             # Math::BigInt -> btmod().
2001              
2002 0 0       0 if ($y -> is_inf()) {
2003 0 0       0 $x -> _dng() if $x -> is_int();
2004 0         0 return $x;
2005             }
2006              
2007             # At this point, both the numerator and denominator are finite numbers, and
2008             # the denominator (divisor) is non-zero.
2009              
2010 0 0       0 if ($x -> is_zero()) { # 0 / 7 = 0, mod 0
2011 0         0 return $x -> bzero();
2012             }
2013              
2014             # Compute $x - $y * int($x / $y).
2015             #
2016             # p r (p * s / gcd(q, s)) mod (r * q / gcd(q, s))
2017             # - mod - = -------------------------------------------
2018             # q s q * s / gcd(q, s)
2019             #
2020             # u mod v u = p * (s / gcd(q, s))
2021             # = ------- where v = r * (q / gcd(q, s))
2022             # w w = q * (s / gcd(q, s))
2023              
2024 0         0 my $p = $x -> {_n};
2025 0         0 my $q = $x -> {_d};
2026 0         0 my $r = $y -> {_n};
2027 0         0 my $s = $y -> {_d};
2028              
2029 0         0 my $gcd_qs = $LIB -> _gcd($LIB -> _copy($q), $s);
2030 0         0 my $s_by_gcd_qs = $LIB -> _div($LIB -> _copy($s), $gcd_qs);
2031 0         0 my $q_by_gcd_qs = $LIB -> _div($LIB -> _copy($q), $gcd_qs);
2032              
2033 0         0 my $u = $LIB -> _mul($LIB -> _copy($p), $s_by_gcd_qs);
2034 0         0 my $v = $LIB -> _mul($LIB -> _copy($r), $q_by_gcd_qs);
2035 0         0 my $w = $LIB -> _mul($LIB -> _copy($q), $s_by_gcd_qs);
2036              
2037 0         0 $x->{_n} = $LIB -> _mod($u, $v);
2038 0         0 $x->{_d} = $w;
2039              
2040 0         0 $x -> bnorm();
2041 0         0 return $x -> round(@r);
2042             }
2043              
2044             sub binv {
2045 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
2046              
2047             # Don't modify constant (read-only) objects.
2048              
2049 0 0       0 return $x if $x -> modify('binv');
2050              
2051 0 0       0 return $x -> round(@r) if $x -> is_nan();
2052 0 0       0 return $x -> bzero(@r) if $x -> is_inf();
2053 0 0       0 return $x -> binf("+", @r) if $x -> is_zero();
2054              
2055 0         0 ($x -> {_n}, $x -> {_d}) = ($x -> {_d}, $x -> {_n});
2056              
2057 0         0 $x -> round(@r);
2058 0 0 0     0 $x -> _dng() if $x -> is_int() || $x -> is_inf() || $x -> is_nan();
      0        
2059 0         0 return $x;
2060             }
2061              
2062             sub bsqrt {
2063 59 50   59 1 1188 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2064              
2065             # Don't modify constant (read-only) objects.
2066              
2067 59 50       220 return $x if $x -> modify('bsqrt');
2068              
2069 59 100       273 return $x -> bnan() if $x->{sign} !~ /^[+]/; # NaN, -inf or < 0
2070 46 100       184 return $x if $x -> is_inf("+"); # sqrt(inf) == inf
2071 42 100 100     145 return $x -> round(@r) if $x -> is_zero() || $x -> is_one();
2072              
2073 34         70 my $n = $x -> {_n};
2074 34         63 my $d = $x -> {_d};
2075              
2076             # Look for an exact solution. For the numerator and the denominator, take
2077             # the square root and square it and see if we got the original value. If we
2078             # did, for both the numerator and the denominator, we have an exact
2079             # solution.
2080              
2081             {
2082 34         58 my $nsqrt = $LIB -> _sqrt($LIB -> _copy($n));
  34         102  
2083 34         112 my $n2 = $LIB -> _mul($LIB -> _copy($nsqrt), $nsqrt);
2084 34 100       118 if ($LIB -> _acmp($n, $n2) == 0) {
2085 32         81 my $dsqrt = $LIB -> _sqrt($LIB -> _copy($d));
2086 32         87 my $d2 = $LIB -> _mul($LIB -> _copy($dsqrt), $dsqrt);
2087 32 100       76 if ($LIB -> _acmp($d, $d2) == 0) {
2088 31         86 $x -> {_n} = $nsqrt;
2089 31         50 $x -> {_d} = $dsqrt;
2090 31         96 return $x -> round(@r);
2091             }
2092             }
2093             }
2094              
2095 3         11 local $Math::BigFloat::upgrade = undef;
2096 3         9 local $Math::BigFloat::downgrade = undef;
2097 3         8 local $Math::BigFloat::precision = undef;
2098 3         176 local $Math::BigFloat::accuracy = undef;
2099 3         9 local $Math::BigInt::upgrade = undef;
2100 3         7 local $Math::BigInt::precision = undef;
2101 3         8 local $Math::BigInt::accuracy = undef;
2102              
2103 3         19 my $xn = Math::BigFloat -> new($LIB -> _str($n));
2104 3         19 my $xd = Math::BigFloat -> new($LIB -> _str($d));
2105              
2106 3         27 my $xtmp = Math::BigRat -> new($xn -> bfdiv($xd) -> bsqrt() -> bfstr());
2107              
2108 3         28 $x -> {sign} = $xtmp -> {sign};
2109 3         13 $x -> {_n} = $xtmp -> {_n};
2110 3         11 $x -> {_d} = $xtmp -> {_d};
2111              
2112 3         25 $x -> round(@r);
2113             }
2114              
2115             sub bpow {
2116             # power ($x ** $y)
2117              
2118             # Set up parameters.
2119 735 100 66 735 1 18560 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
2120             ? (ref($_[0]), @_)
2121             : objectify(2, @_);
2122              
2123             # Don't modify constant (read-only) objects.
2124              
2125 735 50       2646 return $x if $x -> modify('bpow');
2126              
2127             # $x and/or $y is a NaN
2128 735 100 100     2283 return $x -> bnan() if $x -> is_nan() || $y -> is_nan();
2129              
2130             # $x and/or $y is a +/-Inf
2131 619 100       1790 if ($x -> is_inf("-")) {
    100          
    100          
    100          
2132 52 100       435 return $x -> bzero() if $y -> is_negative();
2133 28 100       99 return $x -> bnan() if $y -> is_zero();
2134 24 100       84 return $x if $y -> is_odd();
2135 16         71 return $x -> bneg();
2136             } elsif ($x -> is_inf("+")) {
2137 52 100       438 return $x -> bzero() if $y -> is_negative();
2138 28 100       148 return $x -> bnan() if $y -> is_zero();
2139 24         396 return $x;
2140             } elsif ($y -> is_inf("-")) {
2141 44 100       199 return $x -> bnan() if $x -> is_one("-");
2142 40 100 100     188 return $x -> binf("+") if $x > -1 && $x < 1;
2143 28 100       124 return $x -> bone() if $x -> is_one("+");
2144 24         119 return $x -> bzero();
2145             } elsif ($y -> is_inf("+")) {
2146 44 100       205 return $x -> bnan() if $x -> is_one("-");
2147 40 100 100     230 return $x -> bzero() if $x > -1 && $x < 1;
2148 28 100       110 return $x -> bone() if $x -> is_one("+");
2149 24         93 return $x -> binf("+");
2150             }
2151              
2152 427 100       1761 if ($x -> is_zero()) {
2153 44 100       114 return $x -> bone() if $y -> is_zero();
2154 40 100       379 return $x -> binf() if $y -> is_negative();
2155 20         286 return $x;
2156             }
2157              
2158             # We don't support complex numbers, so upgrade or return NaN.
2159              
2160 383 100 100     3391 if ($x -> is_negative() && !$y -> is_int()) {
2161 80 50       351 return $x -> _upg() -> bpow($y, @r) if $class -> upgrade();
2162 80         336 return $x -> bnan();
2163             }
2164              
2165 303 100 100     989 if ($x -> is_one("+") || $y -> is_one()) {
2166 80         1221 return $x;
2167             }
2168              
2169 223 100       507 if ($x -> is_one("-")) {
2170 24 100       112 return $x if $y -> is_odd();
2171 12         65 return $x -> bneg();
2172             }
2173              
2174             # (a/b)^-(c/d) = (b/a)^(c/d)
2175 199 100       1232 ($x->{_n}, $x->{_d}) = ($x->{_d}, $x->{_n}) if $y -> is_negative();
2176              
2177 199 100       820 unless ($LIB->_is_one($y->{_n})) {
2178 166         794 $x->{_n} = $LIB->_pow($x->{_n}, $y->{_n});
2179 166         574 $x->{_d} = $LIB->_pow($x->{_d}, $y->{_n});
2180 166 100 100     844 $x->{sign} = '+' if $x->{sign} eq '-' && $LIB->_is_even($y->{_n});
2181             }
2182              
2183 199 100       619 unless ($LIB->_is_one($y->{_d})) {
2184 2 100       11 return $x -> bsqrt(@r) if $LIB->_is_two($y->{_d}); # 1/2 => sqrt
2185 1         5 return $x -> broot($LIB->_str($y->{_d}), @r); # 1/N => root(N)
2186             }
2187              
2188 197         656 return $x -> round(@r);
2189             }
2190              
2191             sub broot {
2192             # set up parameters
2193 7 100 66 7 1 80 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
2194             ? (ref($_[0]), @_)
2195             : objectify(2, @_);
2196              
2197             # Don't modify constant (read-only) objects.
2198              
2199 7 50       42 return $x if $x -> modify('broot');
2200              
2201             # Convert $x into a Math::BigFloat.
2202              
2203 7         38 my $xd = Math::BigFloat -> new($LIB -> _str($x->{_d}));
2204 7         41 my $xflt = Math::BigFloat -> new($LIB -> _str($x->{_n})) -> bfdiv($xd);
2205 7         31 $xflt -> {sign} = $x -> {sign};
2206              
2207             # Convert $y into a Math::BigFloat.
2208              
2209 7         38 my $yd = Math::BigFloat -> new($LIB -> _str($y->{_d}));
2210 7         40 my $yflt = Math::BigFloat -> new($LIB -> _str($y->{_n})) -> bfdiv($yd);
2211 7         27 $yflt -> {sign} = $y -> {sign};
2212              
2213             # Compute the root and convert back to a Math::BigRat.
2214              
2215 7         59 $xflt -> broot($yflt, @r);
2216 7         44 my $xtmp = Math::BigRat -> new($xflt -> bfstr());
2217              
2218 7         35 $x -> {sign} = $xtmp -> {sign};
2219 7         31 $x -> {_n} = $xtmp -> {_n};
2220 7         23 $x -> {_d} = $xtmp -> {_d};
2221              
2222 7         179 return $x;
2223             }
2224              
2225             sub bmuladd {
2226             # multiply two numbers and then add the third to the result
2227             # (BINT or num_str, BINT or num_str, BINT or num_str) return BINT
2228              
2229             # set up parameters
2230 0 0 0 0 1 0 my ($class, $x, $y, $z, @r)
2231             = ref($_[0]) && ref($_[0]) eq ref($_[1]) && ref($_[1]) eq ref($_[2])
2232             ? (ref($_[0]), @_)
2233             : objectify(3, @_);
2234              
2235             # Don't modify constant (read-only) objects.
2236              
2237 0 0       0 return $x if $x -> modify('bmuladd');
2238              
2239             # At least one of x, y, and z is a NaN
2240              
2241 0 0 0     0 return $x -> bnan(@r) if ($x -> is_nan() ||
      0        
2242             $y -> is_nan() ||
2243             $z -> is_nan());
2244              
2245             # At least one of x, y, and z is an Inf
2246              
2247 0 0       0 if ($x -> is_inf("-")) {
    0          
    0          
    0          
    0          
2248              
2249 0 0       0 if ($y -> is_neg()) { # x = -inf, y < 0
    0          
2250 0 0       0 if ($z -> is_inf("-")) {
2251 0         0 return $x -> bnan(@r);
2252             } else {
2253 0         0 return $x -> binf("+", @r);
2254             }
2255             } elsif ($y -> is_zero()) { # x = -inf, y = 0
2256 0         0 return $x -> bnan(@r);
2257             } else { # x = -inf, y > 0
2258 0 0       0 if ($z -> is_inf("+")) {
2259 0         0 return $x -> bnan(@r);
2260             } else {
2261 0         0 return $x -> binf("-", @r);
2262             }
2263             }
2264              
2265             } elsif ($x -> is_inf("+")) {
2266              
2267 0 0       0 if ($y -> is_neg()) { # x = +inf, y < 0
    0          
2268 0 0       0 if ($z -> is_inf("+")) {
2269 0         0 return $x -> bnan(@r);
2270             } else {
2271 0         0 return $x -> binf("-", @r);
2272             }
2273             } elsif ($y -> is_zero()) { # x = +inf, y = 0
2274 0         0 return $x -> bnan(@r);
2275             } else { # x = +inf, y > 0
2276 0 0       0 if ($z -> is_inf("-")) {
2277 0         0 return $x -> bnan(@r);
2278             } else {
2279 0         0 return $x -> binf("+", @r);
2280             }
2281             }
2282              
2283             } elsif ($x -> is_neg()) {
2284              
2285 0 0       0 if ($y -> is_inf("-")) { # -inf < x < 0, y = -inf
    0          
2286 0 0       0 if ($z -> is_inf("-")) {
2287 0         0 return $x -> bnan(@r);
2288             } else {
2289 0         0 return $x -> binf("+", @r);
2290             }
2291             } elsif ($y -> is_inf("+")) { # -inf < x < 0, y = +inf
2292 0 0       0 if ($z -> is_inf("+")) {
2293 0         0 return $x -> bnan(@r);
2294             } else {
2295 0         0 return $x -> binf("-", @r);
2296             }
2297             } else { # -inf < x < 0, -inf < y < +inf
2298 0 0       0 if ($z -> is_inf("-")) {
    0          
2299 0         0 return $x -> binf("-", @r);
2300             } elsif ($z -> is_inf("+")) {
2301 0         0 return $x -> binf("+", @r);
2302             }
2303             }
2304              
2305             } elsif ($x -> is_zero()) {
2306              
2307 0 0       0 if ($y -> is_inf("-")) { # x = 0, y = -inf
    0          
2308 0         0 return $x -> bnan(@r);
2309             } elsif ($y -> is_inf("+")) { # x = 0, y = +inf
2310 0         0 return $x -> bnan(@r);
2311             } else { # x = 0, -inf < y < +inf
2312 0 0       0 if ($z -> is_inf("-")) {
    0          
2313 0         0 return $x -> binf("-", @r);
2314             } elsif ($z -> is_inf("+")) {
2315 0         0 return $x -> binf("+", @r);
2316             }
2317             }
2318              
2319             } elsif ($x -> is_pos()) {
2320              
2321 0 0       0 if ($y -> is_inf("-")) { # 0 < x < +inf, y = -inf
    0          
2322 0 0       0 if ($z -> is_inf("+")) {
2323 0         0 return $x -> bnan(@r);
2324             } else {
2325 0         0 return $x -> binf("-", @r);
2326             }
2327             } elsif ($y -> is_inf("+")) { # 0 < x < +inf, y = +inf
2328 0 0       0 if ($z -> is_inf("-")) {
2329 0         0 return $x -> bnan(@r);
2330             } else {
2331 0         0 return $x -> binf("+", @r);
2332             }
2333             } else { # 0 < x < +inf, -inf < y < +inf
2334 0 0       0 if ($z -> is_inf("-")) {
    0          
2335 0         0 return $x -> binf("-", @r);
2336             } elsif ($z -> is_inf("+")) {
2337 0         0 return $x -> binf("+", @r);
2338             }
2339             }
2340             }
2341              
2342             # The code below might be faster if we compute the GCD earlier than in the
2343             # call to bnorm().
2344             #
2345             # xs * xn ys * yn zs * zn / xs: sign of x \
2346             # ------- * ------- + ------- | xn: numerator of x |
2347             # xd yd zd | xd: denominator of x |
2348             # \ ditto for y and z /
2349             # xs * ys * xn * yn zs * zn
2350             # = ----------------- + -------
2351             # xd * yd zd
2352             #
2353             # xs * ys * xn * yn * zd + zs * xd * yd * zn
2354             # = ------------------------------------------
2355             # xd * yd * zd
2356              
2357 0         0 my $xn_yn = $LIB -> _mul($LIB -> _copy($x->{_n}), $y->{_n});
2358 0         0 my $xn_yn_zd = $LIB -> _mul($xn_yn, $z->{_d});
2359              
2360 0         0 my $xd_yd = $LIB -> _mul($x->{_d}, $y->{_d});
2361 0         0 my $xd_yd_zn = $LIB -> _mul($LIB -> _copy($xd_yd), $z->{_n});
2362              
2363 0         0 my $xd_yd_zd = $LIB -> _mul($xd_yd, $z->{_d});
2364              
2365 0 0       0 my $sgn1 = $x->{sign} eq $y->{sign} ? "+" : "-";
2366 0         0 my $sgn2 = $z->{sign};
2367              
2368 0         0 ($x->{_n}, $x->{sign}) = $LIB -> _sadd($xn_yn_zd, $sgn1,
2369             $xd_yd_zn, $sgn2);
2370 0         0 $x->{_d} = $xd_yd_zd;
2371 0         0 $x -> bnorm();
2372              
2373 0         0 return $x;
2374             }
2375              
2376             sub bmodpow {
2377             # set up parameters
2378 70 50 33 70 1 1334 my ($class, $x, $y, $m, @r)
2379             = ref($_[0]) && ref($_[0]) eq ref($_[1]) && ref($_[1]) eq ref($_[2])
2380             ? (ref($_[0]), @_)
2381             : objectify(3, @_);
2382              
2383             # Don't modify constant (read-only) objects.
2384              
2385 70 50       239 return $x if $x -> modify('bmodpow');
2386              
2387             # Convert $x, $y, and $m into Math::BigInt objects.
2388              
2389 70         200 my $xint = Math::BigInt -> new($x -> copy() -> bint());
2390 70         294 my $yint = Math::BigInt -> new($y -> copy() -> bint());
2391 70         301 my $mint = Math::BigInt -> new($m -> copy() -> bint());
2392              
2393 70         456 $xint -> bmodpow($yint, $mint, @r);
2394 70         280 my $xtmp = Math::BigRat -> new($xint -> bfstr());
2395              
2396 70         170 $x -> {sign} = $xtmp -> {sign};
2397 70         189 $x -> {_n} = $xtmp -> {_n};
2398 70         128 $x -> {_d} = $xtmp -> {_d};
2399 70         1198 return $x;
2400             }
2401              
2402             sub bmodinv {
2403             # set up parameters
2404 62 50 33 62 1 1014 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
2405             ? (ref($_[0]), @_)
2406             : objectify(2, @_);
2407              
2408             # Don't modify constant (read-only) objects.
2409              
2410 62 50       182 return $x if $x -> modify('bmodinv');
2411              
2412             # Convert $x and $y into Math::BigInt objects.
2413              
2414 62         200 my $xint = Math::BigInt -> new($x -> copy() -> bint());
2415 62         279 my $yint = Math::BigInt -> new($y -> copy() -> bint());
2416              
2417 62         384 $xint -> bmodinv($yint, @r);
2418 62         215 my $xtmp = Math::BigRat -> new($xint -> bfstr());
2419              
2420 62         156 $x -> {sign} = $xtmp -> {sign};
2421 62         170 $x -> {_n} = $xtmp -> {_n};
2422 62         107 $x -> {_d} = $xtmp -> {_d};
2423 62         1014 return $x;
2424             }
2425              
2426             sub blog {
2427             # Return the logarithm of the operand. If a second operand is defined, that
2428             # value is used as the base, otherwise the base is assumed to be Euler's
2429             # constant.
2430              
2431 74     74 1 857 my ($class, $x, $base, @r);
2432              
2433             # Don't objectify the base, since an undefined base, as in $x->blog() or
2434             # $x->blog(undef) signals that the base is Euler's number.
2435              
2436 74 50 33     250 if (!ref($_[0]) && $_[0] =~ /^[A-Za-z]|::/) {
2437             # E.g., Math::BigRat->blog(256, 2)
2438 0 0       0 ($class, $x, $base, @r) =
2439             defined $_[2] ? objectify(2, @_) : objectify(1, @_);
2440             } else {
2441             # E.g., Math::BigRat::blog(256, 2) or $x->blog(2)
2442 74 100       370 ($class, $x, $base, @r) =
2443             defined $_[1] ? objectify(2, @_) : objectify(1, @_);
2444             }
2445              
2446             # Don't modify constant (read-only) objects.
2447              
2448 74 50       832 return $x if $x -> modify('blog');
2449              
2450             # Handle all exception cases and all trivial cases. I have used Wolfram Alpha
2451             # (http://www.wolframalpha.com) as the reference for these cases.
2452              
2453 74 100       209 return $x -> bnan() if $x -> is_nan();
2454              
2455 54 100       148 if (defined $base) {
2456 22 50       65 $base = $class -> new($base) unless ref $base;
2457 22 100 66     56 if ($base -> is_nan() || $base -> is_one()) {
    50 33        
    100          
2458 8         23 return $x -> bnan();
2459             } elsif ($base -> is_inf() || $base -> is_zero()) {
2460 0 0 0     0 return $x -> bnan() if $x -> is_inf() || $x -> is_zero();
2461 0         0 return $x -> bzero();
2462             } elsif ($base -> is_negative()) { # -inf < base < 0
2463 8 50       30 return $x -> bzero() if $x -> is_one(); # x = 1
2464 8 50       52 return $x -> bone() if $x == $base; # x = base
2465 8         34 return $x -> bnan(); # otherwise
2466             }
2467 6 50       57 return $x -> bone() if $x == $base; # 0 < base && 0 < x < inf
2468             }
2469              
2470             # We now know that the base is either undefined or positive and finite.
2471              
2472 38 100       116 if ($x -> is_inf()) { # x = +/-inf
    100          
    100          
    100          
2473 8 50 33     37 my $sign = defined $base && $base < 1 ? '-' : '+';
2474 8         30 return $x -> binf($sign);
2475             } elsif ($x -> is_neg()) { # -inf < x < 0
2476 8         63 return $x -> bnan();
2477             } elsif ($x -> is_one()) { # x = 1
2478 4         24 return $x -> bzero();
2479             } elsif ($x -> is_zero()) { # x = 0
2480 12 50 66     61 my $sign = defined $base && $base < 1 ? '+' : '-';
2481 12         65 return $x -> binf($sign);
2482             }
2483              
2484             # Now take care of the cases where $x and/or $base is 1/N.
2485             #
2486             # log(1/N) / log(B) = -log(N)/log(B)
2487             # log(1/N) / log(1/B) = log(N)/log(B)
2488             # log(N) / log(1/B) = -log(N)/log(B)
2489              
2490 6         18 my $neg = 0;
2491 6 50       37 if ($x -> numerator() -> is_one()) {
2492 0         0 $x -> binv();
2493 0         0 $neg = !$neg;
2494             }
2495 6 100 66     44 if (defined(blessed($base)) && $base -> isa($class)) {
2496 2 50       9 if ($base -> numerator() -> is_one()) {
2497 0         0 $base = $base -> copy() -> binv();
2498 0         0 $neg = !$neg;
2499             }
2500             }
2501              
2502             # disable upgrading and downgrading
2503              
2504 6         61 require Math::BigFloat;
2505 6         32 my $upg = Math::BigFloat -> upgrade();
2506 6         50 my $dng = Math::BigFloat -> downgrade();
2507 6         23 Math::BigFloat -> upgrade(undef);
2508 6         25 Math::BigFloat -> downgrade(undef);
2509              
2510             # At this point we are done handling all exception cases and trivial cases.
2511              
2512 6 100       31 $base = Math::BigFloat -> new($base) if defined $base;
2513 6         78 my $xnum = Math::BigFloat -> new($LIB -> _str($x->{_n}));
2514 6         35 my $xden = Math::BigFloat -> new($LIB -> _str($x->{_d}));
2515 6         49 my $xstr = $xnum -> bfdiv($xden) -> blog($base, @r) -> bfstr();
2516              
2517             # reset upgrading and downgrading
2518              
2519 6         53 Math::BigFloat -> upgrade($upg);
2520 6         32 Math::BigFloat -> downgrade($dng);
2521              
2522 6         47 my $xobj = Math::BigRat -> new($xstr);
2523 6         38 $x -> {sign} = $xobj -> {sign};
2524 6         28 $x -> {_n} = $xobj -> {_n};
2525 6         24 $x -> {_d} = $xobj -> {_d};
2526              
2527 6 50       237 return $neg ? $x -> bneg() : $x;
2528             }
2529              
2530             sub bexp {
2531             # set up parameters
2532 1 50   1 1 6 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2533              
2534             # Don't modify constant (read-only) objects.
2535              
2536 1 50       24 return $x if $x -> modify('bexp');
2537              
2538 1 50       9 return $x -> binf(@r) if $x -> is_inf("+");
2539 1 50       7 return $x -> bzero(@r) if $x -> is_inf("-");
2540              
2541             # we need to limit the accuracy to protect against overflow
2542 1         8 my $fallback = 0;
2543 1         4 my ($scale, @params);
2544 1         14 ($x, @params) = $x->_find_round_parameters(@r);
2545              
2546             # also takes care of the "error in _find_round_parameters?" case
2547 1 50       11 return $x if $x -> is_nan();
2548              
2549             # no rounding at all, so must use fallback
2550 1 50       4 if (scalar @params == 0) {
2551             # simulate old behaviour
2552 1         10 $params[0] = $class -> div_scale(); # and round to it as accuracy
2553 1         3 $params[1] = undef; # P = undef
2554 1         3 $scale = $params[0]+4; # at least four more for proper round
2555 1         2 $params[2] = $r[2]; # round mode by caller or undef
2556 1         3 $fallback = 1; # to clear a/p afterwards
2557             } else {
2558             # the 4 below is empirical, and there might be cases where it's not enough...
2559 0   0     0 $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
2560             }
2561              
2562 1 50       6 return $x -> bone(@params) if $x -> is_zero();
2563              
2564             # See the comments in Math::BigFloat on how this algorithm works.
2565             # Basically we calculate A and B (where B is faculty(N)) so that A/B = e
2566              
2567 1         6 my $x_org = $x -> copy();
2568 1 50       4 if ($scale <= 75) {
2569             # set $x directly from a cached string form
2570             $x->{_n} =
2571 1         4 $LIB->_new("90933395208605785401971970164779391644753259799242");
2572             $x->{_d} =
2573 1         5 $LIB->_new("33452526613163807108170062053440751665152000000000");
2574 1         3 $x->{sign} = '+';
2575             } else {
2576             # compute A and B so that e = A / B.
2577              
2578             # After some terms we end up with this, so we use it as a starting point:
2579 0         0 my $A = $LIB->_new("90933395208605785401971970164779391644753259799242");
2580 0         0 my $F = $LIB->_new(42); my $step = 42;
  0         0  
2581              
2582             # Compute how many steps we need to take to get $A and $B sufficiently big
2583 0         0 my $steps = Math::BigFloat::_len_to_steps($scale - 4);
2584             # print STDERR "# Doing $steps steps for ", $scale-4, " digits\n";
2585 0         0 while ($step++ <= $steps) {
2586             # calculate $a * $f + 1
2587 0         0 $A = $LIB->_mul($A, $F);
2588 0         0 $A = $LIB->_inc($A);
2589             # increment f
2590 0         0 $F = $LIB->_inc($F);
2591             }
2592             # compute $B as factorial of $steps (this is faster than doing it manually)
2593 0         0 my $B = $LIB->_fac($LIB->_new($steps));
2594              
2595             # print "A ", $LIB->_str($A), "\nB ", $LIB->_str($B), "\n";
2596              
2597 0         0 $x->{_n} = $A;
2598 0         0 $x->{_d} = $B;
2599 0         0 $x->{sign} = '+';
2600             }
2601              
2602             # $x contains now an estimate of e, with some surplus digits, so we can round
2603 1 50       6 if (!$x_org -> is_one()) {
2604             # raise $x to the wanted power and round it in one step:
2605 1         8 $x -> bpow($x_org, @params);
2606             } else {
2607             # else just round the already computed result
2608 0         0 delete $x->{accuracy}; delete $x->{precision};
  0         0  
2609             # shortcut to not run through _find_round_parameters again
2610 0 0       0 if (defined $params[0]) {
2611 0         0 $x -> bround($params[0], $params[2]); # then round accordingly
2612             } else {
2613 0         0 $x -> bfround($params[1], $params[2]); # then round accordingly
2614             }
2615             }
2616 1 50       8 if ($fallback) {
2617             # clear a/p after round, since user did not request it
2618 1         4 delete $x->{accuracy}; delete $x->{precision};
  1         4  
2619             }
2620              
2621 1         11 $x;
2622             }
2623              
2624             sub bilog2 {
2625 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2626              
2627             # Don't modify constant (read-only) objects.
2628              
2629 0 0       0 return $x if $x -> modify('bilog2');
2630              
2631 0 0       0 return $x -> bnan(@r) if $x -> is_nan();
2632 0 0       0 return $x -> binf("+", @r) if $x -> is_inf("+");
2633 0 0       0 return $x -> binf("-", @r) if $x -> is_zero();
2634              
2635 0 0       0 if ($x -> is_neg()) {
2636 0 0       0 return $x -> _upg() -> bilog2(@r) if $class -> upgrade();
2637 0         0 return $x -> bnan(@r);
2638             }
2639              
2640 0         0 $x->{_n} = $LIB -> _div($x->{_n}, $x->{_d});
2641 0         0 $x->{_n} = $LIB -> _ilog2($x->{_n});
2642 0         0 $x->{_d} = $LIB -> _one();
2643 0         0 $x -> bnorm() -> round(@r);
2644 0         0 $x -> _dng();
2645 0         0 return $x;
2646             }
2647              
2648             sub bilog10 {
2649 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2650              
2651             # Don't modify constant (read-only) objects.
2652              
2653 0 0       0 return $x if $x -> modify('bilog10');
2654              
2655 0 0       0 return $x -> bnan(@r) if $x -> is_nan();
2656 0 0       0 return $x -> binf("+", @r) if $x -> is_inf("+");
2657 0 0       0 return $x -> binf("-", @r) if $x -> is_zero();
2658              
2659 0 0       0 if ($x -> is_neg()) {
2660 0 0       0 return $x -> _upg() -> bilog10(@r) if $class -> upgrade();
2661 0         0 return $x -> bnan(@r);
2662             }
2663              
2664 0         0 $x->{_n} = $LIB -> _div($x->{_n}, $x->{_d});
2665 0         0 $x->{_n} = $LIB -> _ilog10($x->{_n});
2666 0         0 $x->{_d} = $LIB -> _one();
2667 0         0 $x -> bnorm() -> round(@r);
2668 0         0 $x -> _dng();
2669 0         0 return $x;
2670             }
2671              
2672             sub bclog2 {
2673 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2674              
2675             # Don't modify constant (read-only) objects.
2676              
2677 0 0       0 return $x if $x -> modify('bclog2');
2678              
2679 0 0       0 return $x -> bnan(@r) if $x -> is_nan();
2680 0 0       0 return $x -> binf("+", @r) if $x -> is_inf("+");
2681 0 0       0 return $x -> binf("-", @r) if $x -> is_zero();
2682              
2683 0 0       0 if ($x -> is_neg()) {
2684 0 0       0 return $x -> _upg() -> bclog2(@r) if $class -> upgrade();
2685 0         0 return $x -> bnan(@r);
2686             }
2687              
2688 0         0 $x->{_n} = $LIB -> _div($x->{_n}, $x->{_d});
2689 0         0 $x->{_n} = $LIB -> _clog2($x->{_n});
2690 0         0 $x->{_d} = $LIB -> _one();
2691 0         0 $x -> bnorm() -> round(@r);
2692 0         0 $x -> _dng();
2693 0         0 return $x;
2694             }
2695              
2696             sub bclog10 {
2697 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2698              
2699             # Don't modify constant (read-only) objects.
2700              
2701 0 0       0 return $x if $x -> modify('bclog10');
2702              
2703 0 0       0 return $x -> bnan(@r) if $x -> is_nan();
2704 0 0       0 return $x -> binf("+", @r) if $x -> is_inf("+");
2705 0 0       0 return $x -> binf("-", @r) if $x -> is_zero();
2706              
2707 0 0       0 if ($x -> is_neg()) {
2708 0 0       0 return $x -> _upg() -> bclog10(@r) if $class -> upgrade();
2709 0         0 return $x -> bnan(@r);
2710             }
2711              
2712 0         0 $x->{_n} = $LIB -> _div($x->{_n}, $x->{_d});
2713 0         0 $x->{_n} = $LIB -> _clog10($x->{_n});
2714 0         0 $x->{_d} = $LIB -> _one();
2715 0         0 $x -> bnorm() -> round(@r);
2716 0         0 $x -> _dng();
2717 0         0 return $x;
2718             }
2719              
2720             sub bnok {
2721             # set up parameters
2722 0 0 0 0 1 0 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
2723             ? (ref($_[0]), @_)
2724             : objectify(2, @_);
2725              
2726 0 0       0 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
2727              
2728             # Don't modify constant (read-only) objects.
2729              
2730 0 0       0 return $x if $x -> modify('bnok');
2731              
2732 0 0 0     0 return $x -> bnan() if $x -> is_nan() || $y -> is_nan();
2733 0 0 0     0 return $x -> bnan() if (($x -> is_finite() && !$x -> is_int()) ||
      0        
      0        
2734             ($y -> is_finite() && !$y -> is_int()));
2735              
2736 0         0 my $xint = Math::BigInt -> new($x -> bstr());
2737 0         0 my $yint = Math::BigInt -> new($y -> bstr());
2738 0         0 $xint -> bnok($yint);
2739 0         0 my $xrat = Math::BigRat -> new($xint);
2740              
2741 0         0 $x -> {sign} = $xrat -> {sign};
2742 0         0 $x -> {_n} = $xrat -> {_n};
2743 0         0 $x -> {_d} = $xrat -> {_d};
2744              
2745 0         0 return $x;
2746             }
2747              
2748             sub bperm {
2749             # set up parameters
2750 0 0 0 0 1 0 my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
2751             ? (ref($_[0]), @_)
2752             : objectify(2, @_);
2753              
2754 0 0       0 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
2755              
2756             # Don't modify constant (read-only) objects.
2757              
2758 0 0       0 return $x if $x -> modify('bperm');
2759              
2760 0 0 0     0 return $x -> bnan() if $x -> is_nan() || $y -> is_nan();
2761 0 0 0     0 return $x -> bnan() if (($x -> is_finite() && !$x -> is_int()) ||
      0        
      0        
2762             ($y -> is_finite() && !$y -> is_int()));
2763              
2764 0         0 my $xint = Math::BigInt -> new($x -> bstr());
2765 0         0 my $yint = Math::BigInt -> new($y -> bstr());
2766 0         0 $xint -> bperm($yint);
2767 0         0 my $xrat = Math::BigRat -> new($xint);
2768              
2769 0         0 $x -> {sign} = $xrat -> {sign};
2770 0         0 $x -> {_n} = $xrat -> {_n};
2771 0         0 $x -> {_d} = $xrat -> {_d};
2772              
2773 0         0 return $x;
2774             }
2775              
2776             sub bfac {
2777 22 50   22 1 382 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2778              
2779             # Don't modify constant (read-only) objects.
2780              
2781 22 50       98 return $x if $x -> modify('bfac');
2782              
2783 22 100 66     74 return $x -> bnan(@r) if $x -> is_nan() || $x -> is_inf("-");
2784 18 50       74 return $x -> binf("+", @r) if $x -> is_inf("+");
2785 18 100 66     176 return $x -> bnan(@r) if $x -> is_neg() || !$x -> is_int();
2786 13 100 100     56 return $x -> bone(@r) if $x -> is_zero() || $x -> is_one();
2787              
2788 6         29 $x->{_n} = $LIB->_fac($x->{_n});
2789             # since _d is 1, we don't need to reduce/norm the result
2790 6         26 $x -> round(@r);
2791 6         17 $x -> _dng();
2792 6         49 return $x;
2793             }
2794              
2795             sub bdfac {
2796             # compute double factorial, modify $x in place
2797 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2798              
2799             # Don't modify constant (read-only) objects.
2800              
2801 0 0       0 return $x if $x -> modify('bdfac');
2802              
2803 0 0 0     0 return $x -> bnan(@r) if $x -> is_nan() || $x -> is_inf("-");
2804 0 0       0 return $x -> binf("+", @r) if $x -> is_inf("+");
2805 0 0 0     0 return $x -> bnan(@r) if $x <= -2 || !$x -> is_int();
2806 0 0       0 return $x -> bone(@r) if $x <= 1;
2807              
2808 0 0       0 croak("bdfac() requires a newer version of the $LIB library.")
2809             unless $LIB -> can('_dfac');
2810              
2811 0         0 $x->{_n} = $LIB->_dfac($x->{_n});
2812             # since _d is 1, we don't need to reduce/norm the result
2813 0         0 $x -> round(@r);
2814 0         0 $x -> _dng();
2815 0         0 return $x;
2816             }
2817              
2818             sub btfac {
2819             # compute triple factorial, modify $x in place
2820 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2821              
2822             # Don't modify constant (read-only) objects.
2823              
2824 0 0       0 return $x if $x -> modify('btfac');
2825              
2826 0 0 0     0 return $x -> bnan(@r) if $x -> is_nan() || !$x -> is_int();
2827 0 0       0 return $x -> binf("+", @r) if $x -> is_inf("+");
2828              
2829 0         0 my $k = $class -> new("3");
2830 0 0       0 return $x -> bnan(@r) if $x <= -$k;
2831              
2832 0         0 my $one = $class -> bone();
2833 0 0       0 return $x -> bone(@r) if $x <= $one;
2834              
2835 0         0 my $f = $x -> copy();
2836 0         0 while ($f -> bsub($k) > $one) {
2837 0         0 $x -> bmul($f);
2838             }
2839 0         0 $x -> round(@r);
2840 0         0 $x -> _dng();
2841 0         0 return $x;
2842             }
2843              
2844             sub bmfac {
2845             # compute multi-factorial
2846              
2847 0 0 0 0 1 0 my ($class, $x, $k, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
2848             ? (ref($_[0]), @_) : objectify(2, @_);
2849              
2850             # Don't modify constant (read-only) objects.
2851              
2852 0 0       0 return $x if $x -> modify('bmfac');
2853              
2854 0 0 0     0 return $x -> bnan(@r) if $x -> is_nan() || $x -> is_inf("-") ||
      0        
2855             !$k -> is_pos();
2856 0 0       0 return $x -> binf("+", @r) if $x -> is_inf("+");
2857 0 0       0 return $x -> bround(@r) if $k -> is_inf("+");
2858 0 0 0     0 return $x -> bnan(@r) if !$x -> is_int() || !$k -> is_int();
2859 0 0 0     0 return $x -> bnan(@r) if $k < 1 || $x <= -$k;
2860              
2861 0         0 my $one = $class -> bone();
2862 0 0       0 return $x -> bone(@r) if $x <= $one;
2863              
2864 0         0 my $f = $x -> copy();
2865 0         0 while ($f -> bsub($k) > $one) {
2866 0         0 $x -> bmul($f);
2867             }
2868 0         0 $x -> round(@r);
2869 0         0 $x -> _dng();
2870 0         0 return $x;
2871             }
2872              
2873             sub bfib {
2874             # compute Fibonacci number(s)
2875 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2876              
2877 0 0       0 croak("bfib() requires a newer version of the $LIB library.")
2878             unless $LIB -> can('_fib');
2879              
2880             # Don't modify constant (read-only) objects.
2881              
2882 0 0       0 return $x if $x -> modify('bfib');
2883              
2884             # List context.
2885              
2886 0 0       0 if (wantarray) {
2887 0 0       0 croak("bfib() can't return an infinitely long list of numbers")
2888             if $x -> is_inf();
2889              
2890 0 0 0     0 return if $x -> is_nan() || !$x -> is_int();
2891              
2892             # The following places a limit on how large $x can be. Should this
2893             # limit be removed? XXX
2894              
2895 0         0 my $n = $x -> numify();
2896              
2897 0         0 my @y;
2898             {
2899 0         0 $y[0] = $x -> copy() -> babs();
  0         0  
2900 0         0 $y[0]{_n} = $LIB -> _zero();
2901 0         0 $y[0]{_d} = $LIB -> _one();
2902 0 0       0 last if $n == 0;
2903              
2904 0         0 $y[1] = $y[0] -> copy();
2905 0         0 $y[1]{_n} = $LIB -> _one();
2906 0         0 $y[1]{_d} = $LIB -> _one();
2907 0 0       0 last if $n == 1;
2908              
2909 0         0 for (my $i = 2 ; $i <= abs($n) ; $i++) {
2910 0         0 $y[$i] = $y[$i - 1] -> copy();
2911             $y[$i]{_n} = $LIB -> _add($LIB -> _copy($y[$i - 1]{_n}),
2912 0         0 $y[$i - 2]{_n});
2913             }
2914              
2915             # If negative, insert sign as appropriate.
2916              
2917 0 0       0 if ($x -> is_neg()) {
2918 0         0 for (my $i = 2 ; $i <= $#y ; $i += 2) {
2919 0         0 $y[$i]{sign} = '-';
2920             }
2921             }
2922              
2923             # The last element in the array is the invocand.
2924              
2925 0         0 $x->{sign} = $y[-1]{sign};
2926 0         0 $x->{_n} = $y[-1]{_n};
2927 0         0 $x->{_d} = $y[-1]{_d};
2928 0         0 $y[-1] = $x;
2929             }
2930              
2931 0         0 for (@y) {
2932 0         0 $_ -> bnorm();
2933 0         0 $_ -> round(@r);
2934             }
2935              
2936 0         0 return @y;
2937             }
2938              
2939             # Scalar context.
2940              
2941             else {
2942 0 0       0 return $x if $x -> is_inf('+');
2943 0 0 0     0 return $x -> bnan() if $x -> is_nan() || $x -> is_inf('-') ||
      0        
2944             !$x -> is_int();
2945              
2946 0 0 0     0 $x->{sign} = $x -> is_neg() && $x -> is_even() ? '-' : '+';
2947 0         0 $x->{_n} = $LIB -> _fib($x->{_n});
2948 0         0 $x->{_d} = $LIB -> _one();
2949 0         0 $x -> bnorm();
2950 0         0 return $x -> round(@r);
2951             }
2952             }
2953              
2954             sub blucas {
2955             # compute Lucas number(s)
2956 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
2957              
2958 0 0       0 croak("blucas() requires a newer version of the $LIB library.")
2959             unless $LIB -> can('_lucas');
2960              
2961             # Don't modify constant (read-only) objects.
2962              
2963 0 0       0 return $x if $x -> modify('blucas');
2964              
2965             # List context.
2966              
2967 0 0       0 if (wantarray) {
2968 0 0       0 croak("blucas() can't return an infinitely long list of numbers")
2969             if $x -> is_inf();
2970              
2971 0 0 0     0 return if $x -> is_nan() || !$x -> is_int();
2972              
2973             # The following places a limit on how large $x can be, at least on 32
2974             # bit systems. Should this limit be removed? XXX
2975              
2976 0         0 my $n = $x -> numify();
2977              
2978 0         0 my @y;
2979             {
2980 0         0 $y[0] = $x -> copy() -> babs();
  0         0  
2981 0         0 $y[0]{_n} = $LIB -> _two();
2982 0 0       0 last if $n == 0;
2983              
2984 0         0 $y[1] = $y[0] -> copy();
2985 0         0 $y[1]{_n} = $LIB -> _one();
2986 0 0       0 last if $n == 1;
2987              
2988 0         0 for (my $i = 2 ; $i <= abs($n) ; $i++) {
2989 0         0 $y[$i] = $y[$i - 1] -> copy();
2990             $y[$i]{_n} = $LIB -> _add($LIB -> _copy($y[$i - 1]{_n}),
2991 0         0 $y[$i - 2]{_n});
2992             }
2993              
2994             # If negative, insert sign as appropriate.
2995              
2996 0 0       0 if ($x -> is_neg()) {
2997 0         0 for (my $i = 2 ; $i <= $#y ; $i += 2) {
2998 0         0 $y[$i]{sign} = '-';
2999             }
3000             }
3001              
3002             # The last element in the array is the invocand.
3003              
3004 0         0 $x->{_n} = $y[-1]{_n};
3005 0         0 $x->{sign} = $y[-1]{sign};
3006 0         0 $y[-1] = $x;
3007             }
3008              
3009 0         0 @y = map { $_ -> round(@r) } @y;
  0         0  
3010 0         0 return @y;
3011             }
3012              
3013             # Scalar context.
3014              
3015             else {
3016 0 0       0 return $x if $x -> is_inf('+');
3017 0 0 0     0 return $x -> bnan() if $x -> is_nan() || $x -> is_inf('-') ||
      0        
3018             !$x -> is_int();
3019              
3020 0 0 0     0 $x->{sign} = $x -> is_neg() && $x -> is_even() ? '-' : '+';
3021 0         0 $x->{_n} = $LIB -> _lucas($x->{_n});
3022 0         0 return $x -> round(@r);
3023             }
3024             }
3025              
3026             sub blsft {
3027 0     0 1 0 my ($class, $x, $y, $b, @r);
3028              
3029             # Objectify the base only when it is defined, since an undefined base, as
3030             # in $x->blsft(3) or $x->blog(3, undef) means use the default base 2.
3031              
3032 0 0 0     0 if (!ref($_[0]) && $_[0] =~ /^[A-Za-z]|::/) {
3033             # E.g., Math::BigInt->blog(256, 5, 2)
3034 0 0       0 ($class, $x, $y, $b, @r) =
3035             defined $_[3] ? objectify(3, @_) : objectify(2, @_);
3036             } else {
3037             # E.g., Math::BigInt::blog(256, 5, 2) or $x->blog(5, 2)
3038 0 0       0 ($class, $x, $y, $b, @r) =
3039             defined $_[2] ? objectify(3, @_) : objectify(2, @_);
3040             }
3041              
3042             # Don't modify constant (read-only) objects.
3043              
3044 0 0       0 return $x if $x -> modify('blsft');
3045              
3046 0 0       0 $b = 2 unless defined($b);
3047 0 0 0     0 $b = $class -> new($b) unless ref($b) && $b -> isa($class);
3048              
3049 0 0 0     0 return $x -> bnan() if $x -> is_nan() || $y -> is_nan() || $b -> is_nan();
      0        
3050              
3051             # shift by a negative amount?
3052 0 0       0 return $x -> brsft($y -> copy() -> babs(), $b) if $y -> {sign} =~ /^-/;
3053              
3054 0         0 $x -> bmul($b -> bpow($y));
3055             }
3056              
3057             sub brsft {
3058 0     0 1 0 my ($class, $x, $y, $b, @r);
3059              
3060             # Objectify the base only when it is defined, since an undefined base, as
3061             # in $x->blsft(3) or $x->blog(3, undef) means use the default base 2.
3062              
3063 0 0 0     0 if (!ref($_[0]) && $_[0] =~ /^[A-Za-z]|::/) {
3064             # E.g., Math::BigInt->blog(256, 5, 2)
3065 0 0       0 ($class, $x, $y, $b, @r) =
3066             defined $_[3] ? objectify(3, @_) : objectify(2, @_);
3067             } else {
3068             # E.g., Math::BigInt::blog(256, 5, 2) or $x->blog(5, 2)
3069 0 0       0 ($class, $x, $y, $b, @r) =
3070             defined $_[2] ? objectify(3, @_) : objectify(2, @_);
3071             }
3072              
3073             # Don't modify constant (read-only) objects.
3074              
3075 0 0       0 return $x if $x -> modify('brsft');
3076              
3077 0 0       0 $b = 2 unless defined($b);
3078 0 0 0     0 $b = $class -> new($b) unless ref($b) && $b -> isa($class);
3079              
3080 0 0 0     0 return $x -> bnan() if $x -> is_nan() || $y -> is_nan() || $b -> is_nan();
      0        
3081              
3082             # shift by a negative amount?
3083 0 0       0 return $x -> blsft($y -> copy() -> babs(), $b) if $y -> {sign} =~ /^-/;
3084              
3085             # the following call to bfdiv() will return either quotient (scalar context)
3086             # or quotient and remainder (list context).
3087 0         0 $x -> bfdiv($b -> bpow($y));
3088             }
3089              
3090             ###############################################################################
3091             # Bitwise methods
3092             ###############################################################################
3093              
3094             # Bitwise left shift.
3095              
3096             sub bblsft {
3097             # We don't call objectify(), because the bitwise methods should not
3098             # upgrade, even when upgrading is enabled.
3099              
3100 0 0   0 1 0 my ($class, $x, $y, @r) = ref($_[0]) ? (ref($_[0]), @_) : @_;
3101              
3102             # Don't modify constant (read-only) objects.
3103              
3104 0 0 0     0 return $x if ref($x) && $x -> modify('bblsft');
3105              
3106             # Let Math::BigInt do the job.
3107              
3108 0         0 my $xint = Math::BigInt -> bblsft($x, $y, @r);
3109              
3110             # Temporarily disable downgrading.
3111              
3112 0         0 my $dng = $class -> downgrade();
3113 0         0 $class -> downgrade(undef);
3114              
3115             # Convert to our class without downgrading.
3116              
3117 0         0 my $xrat = $class -> new($xint);
3118              
3119             # Reset downgrading.
3120              
3121 0         0 $class -> downgrade($dng);
3122              
3123             # If we are called as a class method, the first operand might not be an
3124             # object of this class, so check.
3125              
3126 0 0 0     0 if (defined(blessed($x)) && $x -> isa(__PACKAGE__)) {
3127 0         0 $x -> {sign} = $xrat -> {sign};
3128 0         0 $x -> {_n} = $xrat -> {_n};
3129 0         0 $x -> {_d} = $xrat -> {_d};
3130             } else {
3131 0         0 $x = $xrat;
3132             }
3133              
3134             # Now we might downgrade.
3135              
3136 0         0 $x -> round(@r);
3137 0         0 $x -> _dng();
3138 0         0 return $x;
3139             }
3140              
3141             # Bitwise right shift.
3142              
3143             sub bbrsft {
3144             # We don't call objectify(), because the bitwise methods should not
3145             # upgrade/downgrade, even when upgrading/downgrading is enabled.
3146              
3147 0 0   0 1 0 my ($class, $x, $y, @r) = ref($_[0]) ? (ref($_[0]), @_) : @_;
3148              
3149             # Don't modify constant (read-only) objects.
3150              
3151 0 0 0     0 return $x if ref($x) && $x -> modify('bbrsft');
3152              
3153             # Let Math::BigInt do the job.
3154              
3155 0         0 my $xint = Math::BigInt -> bbrsft($x, $y, @r);
3156              
3157             # Temporarily disable downgrading.
3158              
3159 0         0 my $dng = $class -> downgrade();
3160 0         0 $class -> downgrade(undef);
3161              
3162             # Convert to our class without downgrading.
3163              
3164 0         0 my $xrat = $class -> new($xint);
3165              
3166             # Reset downgrading.
3167              
3168 0         0 $class -> downgrade($dng);
3169              
3170             # If we are called as a class method, the first operand might not be an
3171             # object of this class, so check.
3172              
3173 0 0 0     0 if (defined(blessed($x)) && $x -> isa(__PACKAGE__)) {
3174 0         0 $x -> {sign} = $xrat -> {sign};
3175 0         0 $x -> {_n} = $xrat -> {_n};
3176 0         0 $x -> {_d} = $xrat -> {_d};
3177             } else {
3178 0         0 $x = $xrat;
3179             }
3180              
3181             # Now we might downgrade.
3182              
3183 0         0 $x -> round(@r);
3184 0         0 $x -> _dng();
3185 0         0 return $x;
3186             }
3187              
3188             sub band {
3189 289     289 1 529 my $x = shift;
3190 289         453 my $xref = ref($x);
3191 289   33     657 my $class = $xref || $x;
3192              
3193             # Don't modify constant (read-only) objects.
3194              
3195 289 50       854 return $x if $x -> modify('band');
3196              
3197 289 50       773 croak 'band() is an instance method, not a class method' unless $xref;
3198 289 50       611 croak 'Not enough arguments for band()' if @_ < 1;
3199              
3200 289         449 my $y = shift;
3201 289 50       543 $y = $class -> new($y) unless ref($y);
3202              
3203 289         556 my @r = @_;
3204              
3205 289         773 my $xtmp = $x -> as_int() -> band($y -> as_int()) -> as_rat();
3206 289         1642 $x -> {sign} = $xtmp -> {sign};
3207 289         725 $x -> {_n} = $xtmp -> {_n};
3208 289         614 $x -> {_d} = $xtmp -> {_d};
3209              
3210 289         703 return $x -> round(@r);
3211             }
3212              
3213             sub bior {
3214 289     289 1 433 my $x = shift;
3215 289         608 my $xref = ref($x);
3216 289   33     643 my $class = $xref || $x;
3217              
3218             # Don't modify constant (read-only) objects.
3219              
3220 289 50       921 return $x if $x -> modify('bior');
3221              
3222 289 50       544 croak 'bior() is an instance method, not a class method' unless $xref;
3223 289 50       654 croak 'Not enough arguments for bior()' if @_ < 1;
3224              
3225 289         395 my $y = shift;
3226 289 50       656 $y = $class -> new($y) unless ref($y);
3227              
3228 289         497 my @r = @_;
3229              
3230 289         761 my $xtmp = $x -> as_int() -> bior($y -> as_int()) -> as_rat();
3231 289         1576 $x -> {sign} = $xtmp -> {sign};
3232 289         656 $x -> {_n} = $xtmp -> {_n};
3233 289         552 $x -> {_d} = $xtmp -> {_d};
3234              
3235 289         596 return $x -> round(@r);
3236             }
3237              
3238             sub bxor {
3239 289     289 1 408 my $x = shift;
3240 289         448 my $xref = ref($x);
3241 289   33     572 my $class = $xref || $x;
3242              
3243             # Don't modify constant (read-only) objects.
3244              
3245 289 50       887 return $x if $x -> modify('bxor');
3246              
3247 289 50       612 croak 'bxor() is an instance method, not a class method' unless $xref;
3248 289 50       620 croak 'Not enough arguments for bxor()' if @_ < 1;
3249              
3250 289         396 my $y = shift;
3251 289 50       548 $y = $class -> new($y) unless ref($y);
3252              
3253 289         591 my @r = @_;
3254              
3255 289         749 my $xtmp = $x -> as_int() -> bxor($y -> as_int()) -> as_rat();
3256 289         1456 $x -> {sign} = $xtmp -> {sign};
3257 289         707 $x -> {_n} = $xtmp -> {_n};
3258 289         554 $x -> {_d} = $xtmp -> {_d};
3259              
3260 289         552 return $x -> round(@r);
3261             }
3262              
3263             sub bnot {
3264 0     0 1 0 my $x = shift;
3265 0         0 my $xref = ref($x);
3266 0   0     0 my $class = $xref || $x;
3267              
3268             # Don't modify constant (read-only) objects.
3269              
3270 0 0       0 return $x if $x -> modify('bnot');
3271              
3272 0 0       0 croak 'bnot() is an instance method, not a class method' unless $xref;
3273              
3274 0         0 my @r = @_;
3275              
3276 0         0 my $xtmp = $x -> as_int() -> bnot() -> as_rat();
3277 0         0 $x -> {sign} = $xtmp -> {sign};
3278 0         0 $x -> {_n} = $xtmp -> {_n};
3279 0         0 $x -> {_d} = $xtmp -> {_d};
3280              
3281 0         0 return $x -> round(@r);
3282             }
3283              
3284             ##############################################################################
3285             # round
3286              
3287             sub round {
3288 7867     7867 1 12236 my $x = shift;
3289              
3290             # Don't modify constant (read-only) objects.
3291              
3292 7867 50       22272 return $x if $x -> modify('round');
3293              
3294 7867 100 100     17393 $x -> _dng() if ($x -> is_int() ||
      100        
3295             $x -> is_inf() ||
3296             $x -> is_nan());
3297 7867         29961 $x;
3298             }
3299              
3300             sub bround {
3301 7     7 1 19 my $x = shift;
3302              
3303             # Don't modify constant (read-only) objects.
3304              
3305 7 50       97 return $x if $x -> modify('bround');
3306              
3307 7 50 100     33 $x -> _dng() if ($x -> is_int() ||
      66        
3308             $x -> is_inf() ||
3309             $x -> is_nan());
3310 7         24 $x;
3311             }
3312              
3313             sub bfround {
3314 8     8 1 23 my $x = shift;
3315              
3316             # Don't modify constant (read-only) objects.
3317              
3318 8 50       233 return $x if $x -> modify('bfround');
3319              
3320 8 50 100     41 $x -> _dng() if ($x -> is_int() ||
      66        
3321             $x -> is_inf() ||
3322             $x -> is_nan());
3323 8         28 $x;
3324             }
3325              
3326             sub bfloor {
3327 188 50   188 1 2072 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
3328              
3329             # Don't modify constant (read-only) objects.
3330              
3331 188 50       694 return $x if $x -> modify('bfloor');
3332              
3333 188 100       583 return $x -> bnan(@r) if $x -> is_nan();
3334              
3335 183 100 100     465 if (!$x -> is_finite() || # NaN or inf or
3336             $LIB->_is_one($x->{_d})) # integer
3337             {
3338 86         482 $x -> round(@r);
3339 86         256 $x -> _dng();
3340 86         728 return $x;
3341             }
3342              
3343 97         445 $x->{_n} = $LIB->_div($x->{_n}, $x->{_d}); # 22/7 => 3/1 w/ truncate
3344 97         327 $x->{_d} = $LIB->_one(); # d => 1
3345 97 100       487 $x->{_n} = $LIB->_inc($x->{_n}) if $x->{sign} eq '-'; # -22/7 => -4/1
3346              
3347 97         371 $x -> round(@r);
3348 97         333 $x -> _dng();
3349 97         754 return $x;
3350             }
3351              
3352             sub bceil {
3353 84 50   84 1 1545 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
3354              
3355             # Don't modify constant (read-only) objects.
3356              
3357 84 50       304 return $x if $x -> modify('bceil');
3358              
3359 84 100       229 return $x -> bnan(@r) if $x -> is_nan();
3360              
3361 79 100 100     175 if (!$x -> is_finite() || # NaN or inf or
3362             $LIB->_is_one($x->{_d})) # integer
3363             {
3364 29         105 $x -> round(@r);
3365 29         81 $x -> _dng();
3366 29         332 return $x;
3367             }
3368              
3369 50         247 $x->{_n} = $LIB->_div($x->{_n}, $x->{_d}); # 22/7 => 3/1 w/ truncate
3370 50         176 $x->{_d} = $LIB->_one(); # d => 1
3371 50 100       234 $x->{_n} = $LIB->_inc($x->{_n}) if $x->{sign} eq '+'; # +22/7 => 4/1
3372 50 100 100     205 $x->{sign} = '+' if $x->{sign} eq '-' && $LIB->_is_zero($x->{_n}); # -0 => 0
3373              
3374 50         195 $x -> round(@r);
3375 50         124 $x -> _dng();
3376 50         545 return $x;
3377             }
3378              
3379             sub bint {
3380 2107 50   2107 1 5157 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
3381              
3382             # Don't modify constant (read-only) objects.
3383              
3384 2107 50       5512 return $x if $x -> modify('bint');
3385              
3386 2107 100       4881 return $x -> bnan(@r) if $x -> is_nan();
3387              
3388 2042 100 100     4429 if (!$x -> is_finite() || # NaN or inf or
3389             $LIB->_is_one($x->{_d})) # integer
3390             {
3391 1215         3312 $x -> round(@r);
3392 1215         2870 $x -> _dng();
3393 1215         3612 return $x;
3394             }
3395              
3396 827         2798 $x->{_n} = $LIB->_div($x->{_n}, $x->{_d}); # 22/7 => 3/1 w/ truncate
3397 827         2068 $x->{_d} = $LIB->_one(); # d => 1
3398 827 100 66     2237 $x->{sign} = '+' if $x->{sign} eq '-' && $LIB -> _is_zero($x->{_n});
3399              
3400 827         2333 $x -> round(@r);
3401 827         1880 $x -> _dng();
3402 827         2374 return $x;
3403             }
3404              
3405             sub bgcd {
3406             # GCD -- Euclid's algorithm, variant C (Knuth Vol 3, pg 341 ff)
3407              
3408             # Class::method(...) -> Class->method(...)
3409 0 0 0 0 1 0 unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
      0        
3410             ($_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i &&
3411             $_[0] !~ /^(inf|nan)/i)))
3412             {
3413             #carp "Using ", (caller(0))[3], "() as a function is deprecated;",
3414             # " use is as a method instead";
3415 0         0 unshift @_, __PACKAGE__;
3416             }
3417              
3418 0         0 my ($class, @args) = objectify(0, @_);
3419              
3420             # Pre-process list of operands.
3421              
3422 0         0 for my $arg (@args) {
3423 0 0       0 return $class -> bnan() unless $arg -> is_finite();
3424             }
3425              
3426             # Temporarily disable downgrading.
3427              
3428 0         0 my $dng = $class -> downgrade();
3429 0         0 $class -> downgrade(undef);
3430              
3431 0         0 my $x = shift @args;
3432 0         0 $x = $x -> copy(); # bgcd() and blcm() never modify any operands
3433              
3434 0         0 while (@args) {
3435 0         0 my $y = shift @args;
3436              
3437             # greatest common divisor
3438 0         0 while (! $y -> is_zero()) {
3439 0         0 ($x, $y) = ($y -> copy(), $x -> copy() -> bmod($y));
3440             }
3441              
3442 0 0       0 last if $x -> is_one();
3443             }
3444 0         0 $x -> babs();
3445              
3446             # Restore downgrading.
3447              
3448 0         0 $class -> downgrade($dng);
3449              
3450 0 0       0 $x -> _dng() if $x -> is_int();
3451 0         0 return $x;
3452             }
3453              
3454             sub blcm {
3455             # Least Common Multiple
3456              
3457             # Class::method(...) -> Class->method(...)
3458 0 0 0 0 1 0 unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
      0        
3459             ($_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i &&
3460             $_[0] !~ /^(inf|nan)/i)))
3461             {
3462             #carp "Using ", (caller(0))[3], "() as a function is deprecated;",
3463             # " use is as a method instead";
3464 0         0 unshift @_, __PACKAGE__;
3465             }
3466              
3467 0         0 my ($class, @args) = objectify(0, @_);
3468              
3469             # Pre-process list of operands.
3470              
3471 0         0 for my $arg (@args) {
3472 0 0       0 return $class -> bnan() unless $arg -> is_finite();
3473             }
3474              
3475 0         0 for my $arg (@args) {
3476 0 0       0 return $class -> bzero() if $arg -> is_zero();
3477             }
3478              
3479 0         0 my $x = shift @args;
3480 0         0 $x = $x -> copy(); # bgcd() and blcm() never modify any operands
3481              
3482 0         0 while (@args) {
3483 0         0 my $y = shift @args;
3484 0         0 my $gcd = $x -> copy() -> bgcd($y);
3485 0         0 $x -> bdiv($gcd) -> bmul($y);
3486             }
3487              
3488 0         0 $x -> babs(); # might downgrade
3489 0         0 return $x;
3490             }
3491              
3492             sub digit {
3493 44 50   44 1 648 my ($class, $x, $n) = ref($_[0]) ? (undef, $_[0], $_[1]) : objectify(1, @_);
3494              
3495 44 50       104 return $nan unless $x -> is_int();
3496 44   100     181 $LIB->_digit($x->{_n}, $n || 0); # digit(-123/1, 2) => digit(123, 2)
3497             }
3498              
3499             sub length {
3500 20 50   20 1 482 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
3501              
3502 20 50       64 return $nan unless $x -> is_int();
3503 20         87 $LIB->_len($x->{_n}); # length(-123/1) => length(123)
3504             }
3505              
3506             sub parts {
3507 40 50   40 1 885 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
3508              
3509 40         81 my $c = 'Math::BigInt';
3510              
3511 40 100       160 return ($c -> bnan(), $c -> bnan()) if $x -> is_nan();
3512 36 100       111 return ($c -> binf(), $c -> binf()) if $x -> is_inf("+");
3513 32 100       102 return ($c -> binf('-'), $c -> binf()) if $x -> is_inf("-");
3514              
3515 28         163 my $n = $c -> new($LIB->_str($x->{_n}));
3516 28         88 $n->{sign} = $x->{sign};
3517 28         118 my $d = $c -> new($LIB->_str($x->{_d}));
3518 28         696 ($n, $d);
3519             }
3520              
3521             sub dparts {
3522 0     0 1 0 my $x = shift;
3523 0         0 my $class = ref $x;
3524              
3525 0 0       0 croak("dparts() is an instance method") unless $class;
3526              
3527 0 0       0 if ($x -> is_nan()) {
3528 0 0       0 return $class -> bnan(), $class -> bnan() if wantarray;
3529 0         0 return $class -> bnan();
3530             }
3531              
3532 0 0       0 if ($x -> is_inf()) {
3533 0 0       0 return $class -> binf($x -> sign()), $class -> bzero() if wantarray;
3534 0         0 return $class -> binf($x -> sign());
3535             }
3536              
3537             # 355/113 => 3 + 16/113
3538              
3539 0         0 my ($q, $r) = $LIB -> _div($LIB -> _copy($x -> {_n}), $x -> {_d});
3540              
3541 0         0 my $int = Math::BigRat -> new($x -> {sign} . $LIB -> _str($q));
3542 0 0       0 return $int unless wantarray;
3543              
3544             my $frc = Math::BigRat -> new($x -> {sign} . $LIB -> _str($r),
3545 0         0 $LIB -> _str($x -> {_d}));
3546              
3547 0         0 return $int, $frc;
3548             }
3549              
3550             sub fparts {
3551 2     2 1 5 my $x = shift;
3552 2         5 my $class = ref $x;
3553              
3554             # NaN => NaN/NaN
3555              
3556 2 50       5 if ($x -> is_nan()) {
3557 0 0       0 return $class -> bnan(), $class -> bnan() if wantarray;
3558 0         0 return $class -> bnan();
3559             }
3560              
3561             # ±Inf => ±Inf/1
3562              
3563 2 50       6 if ($x -> is_inf()) {
3564 0 0       0 return $class -> binf($x -> sign()), $class -> bone() if wantarray;
3565 0         0 return $class -> binf($x -> sign());
3566             }
3567              
3568             # -3/2 -> -3/1
3569              
3570 2         8 my $numer = $x -> copy();
3571 2         7 $numer -> {_d} = $LIB -> _one();
3572 2 50       6 return $numer unless wantarray;
3573              
3574             # -3/2 -> 2/1
3575              
3576 2         30 my $denom = $x -> copy();
3577 2         5 $denom -> {sign} = "+";
3578 2         6 $denom -> {_n} = $denom -> {_d};
3579 2         6 $denom -> {_d} = $LIB -> _one();
3580              
3581 2         6 return $numer, $denom;
3582             }
3583              
3584             sub numerator {
3585 52 50   52 1 3296 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
3586              
3587             # NaN, inf, -inf
3588 52 100       164 return Math::BigInt -> new($x->{sign}) if !$x -> is_finite();
3589              
3590 31         141 my $n = Math::BigInt -> new($LIB->_str($x->{_n}));
3591 31         84 $n->{sign} = $x->{sign};
3592 31         141 $n;
3593             }
3594              
3595             sub denominator {
3596 48 50   48 1 848 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
3597              
3598             # NaN
3599 48 100       161 return Math::BigInt -> new($x->{sign}) if $x -> is_nan();
3600             # inf, -inf
3601 37 100       90 return Math::BigInt -> bone() if !$x -> is_finite();
3602              
3603 27         104 Math::BigInt -> new($LIB->_str($x->{_d}));
3604             }
3605              
3606             ###############################################################################
3607             # String conversion methods
3608             ###############################################################################
3609              
3610             sub bstr {
3611 7497 50   7497 1 24675 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
3612              
3613 7497 50       17508 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
3614              
3615             # Inf and NaN
3616              
3617 7497 100       23126 if (!$x -> is_finite()) {
3618 1004 100       4772 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
3619 235         1402 return 'inf'; # +inf
3620             }
3621              
3622             # Upgrade?
3623              
3624 6493 50 33     20760 return $x -> _upg() -> bstr(@r)
3625             if $class -> upgrade() && !$x -> isa($class);
3626              
3627             # Finite number
3628              
3629 6493         11024 my $s = '';
3630 6493 100       15099 $s = $x->{sign} if $x->{sign} ne '+'; # '+3/2' => '3/2'
3631              
3632 6493 100       14327 my $str = $x->{sign} eq '-' ? '-' : '';
3633 6493         24506 $str .= $LIB->_str($x->{_n});
3634 6493 100       20405 $str .= '/' . $LIB->_str($x->{_d}) unless $LIB -> _is_one($x->{_d});
3635 6493         30733 return $str;
3636             }
3637              
3638             sub bsstr {
3639 26 50   26 1 594 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
3640              
3641 26 50       101 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
3642              
3643             # Inf and NaN
3644              
3645 26 100       77 if (!$x -> is_finite()) {
3646 12 100       53 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
3647 4         51 return 'inf'; # +inf
3648             }
3649              
3650             # Upgrade?
3651              
3652 14 50 33     56 return $x -> _upg() -> bsstr(@r)
3653             if $class -> upgrade() && !$x -> isa($class);
3654              
3655             # Finite number
3656              
3657 14 100       49 my $str = $x->{sign} eq '-' ? '-' : '';
3658 14         84 $str .= $LIB->_str($x->{_n});
3659 14 100       58 $str .= '/' . $LIB->_str($x->{_d}) unless $LIB -> _is_one($x->{_d});
3660 14         144 return $str;
3661             }
3662              
3663             sub bnstr {
3664 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
3665              
3666             # Inf and NaN
3667              
3668 0 0 0     0 if ($x->{sign} ne '+' && $x->{sign} ne '-') {
3669 0 0       0 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
3670 0         0 return 'inf'; # +inf
3671             }
3672              
3673             # Upgrade?
3674              
3675 0 0 0     0 $x -> _upg() -> bnstr(@r)
3676             if $class -> upgrade() && !$x -> isa(__PACKAGE__);
3677              
3678 0         0 return $x -> as_float(@r) -> bnstr();
3679             }
3680              
3681             sub bestr {
3682 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
3683              
3684             # Inf and NaN
3685              
3686 0 0 0     0 if ($x->{sign} ne '+' && $x->{sign} ne '-') {
3687 0 0       0 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
3688 0         0 return 'inf'; # +inf
3689             }
3690              
3691             # Upgrade?
3692              
3693 0 0 0     0 $x -> _upg() -> bestr(@r)
3694             if $class -> upgrade() && !$x -> isa(__PACKAGE__);
3695              
3696 0         0 return $x -> as_float(@r) -> bestr();
3697             }
3698              
3699             sub bdstr {
3700 1775 50   1775 1 4194 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
3701              
3702             # Inf and NaN
3703              
3704 1775 50 66     4538 if ($x->{sign} ne '+' && $x->{sign} ne '-') {
3705 0 0       0 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
3706 0         0 return 'inf'; # +inf
3707             }
3708              
3709             return ($x->{sign} eq '-' ? '-' : '') . $LIB->_str($x->{_n})
3710 1775 100       3147 if $x -> is_int();
    50          
3711              
3712             # Upgrade?
3713              
3714 0 0 0     0 $x -> _upg() -> bdstr(@r)
3715             if $class -> upgrade() && !$x -> isa(__PACKAGE__);
3716              
3717             # Integer number
3718              
3719 0         0 return $x -> as_float(@r) -> bdstr();
3720             }
3721              
3722             sub bfstr {
3723 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
3724              
3725 0 0       0 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
3726              
3727             # Inf and NaN
3728              
3729 0 0       0 if (!$x -> is_finite()) {
3730 0 0       0 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
3731 0         0 return 'inf'; # +inf
3732             }
3733              
3734             # Upgrade?
3735              
3736 0 0 0     0 return $x -> _upg() -> bfstr(@r)
3737             if $class -> upgrade() && !$x -> isa($class);
3738              
3739             # Finite number
3740              
3741 0 0       0 my $str = $x->{sign} eq '-' ? '-' : '';
3742 0         0 $str .= $LIB->_str($x->{_n});
3743 0 0       0 $str .= '/' . $LIB->_str($x->{_d}) unless $LIB -> _is_one($x->{_d});
3744 0         0 return $str;
3745             }
3746              
3747             sub to_hex {
3748 0 0   0 1 0 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
3749              
3750             # Inf and NaN
3751              
3752 0 0       0 if (!$x -> is_finite()) {
3753 0 0       0 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
3754 0         0 return 'inf'; # +inf
3755             }
3756              
3757 0 0       0 return $nan unless $x -> is_int();
3758              
3759 0         0 my $str = $LIB->_to_hex($x->{_n});
3760 0 0       0 return $x->{sign} eq "-" ? "-$str" : $str;
3761             }
3762              
3763             sub to_oct {
3764 0 0   0 1 0 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
3765              
3766             # Inf and NaN
3767              
3768 0 0       0 if (!$x -> is_finite()) {
3769 0 0       0 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
3770 0         0 return 'inf'; # +inf
3771             }
3772              
3773 0 0       0 return $nan unless $x -> is_int();
3774              
3775 0         0 my $str = $LIB->_to_oct($x->{_n});
3776 0 0       0 return $x->{sign} eq "-" ? "-$str" : $str;
3777             }
3778              
3779             sub to_bin {
3780 0 0   0 1 0 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
3781              
3782             # Inf and NaN
3783              
3784 0 0       0 if (!$x -> is_finite()) {
3785 0 0       0 return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
3786 0         0 return 'inf'; # +inf
3787             }
3788              
3789 0 0       0 return $nan unless $x -> is_int();
3790              
3791 0         0 my $str = $LIB->_to_bin($x->{_n});
3792 0 0       0 return $x->{sign} eq "-" ? "-$str" : $str;
3793             }
3794              
3795             sub to_bytes {
3796             # return a byte string
3797              
3798 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
3799              
3800 0 0       0 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
3801              
3802 0 0 0     0 croak("to_bytes() requires a finite, non-negative integer")
3803             if $x -> is_neg() || ! $x -> is_int();
3804              
3805 0 0 0     0 return $x -> _upg() -> to_bytes(@r)
3806             if $class -> upgrade() && !$x -> isa(__PACKAGE__);
3807              
3808 0 0       0 croak("to_bytes() requires a newer version of the $LIB library.")
3809             unless $LIB -> can('_to_bytes');
3810              
3811 0         0 return $LIB->_to_bytes($x->{_n});
3812             }
3813              
3814             sub to_ieee754 {
3815 0 0   0 1 0 my ($class, $x, $format, @r) = ref($_[0]) ? (ref($_[0]), @_)
3816             : objectify(1, @_);
3817              
3818 0 0       0 carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
3819              
3820 0         0 return $x -> as_float() -> to_ieee754($format);
3821             }
3822              
3823             sub to_fp80 {
3824 0 0   0 1 0 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_)
3825             : objectify(1, @_);
3826              
3827 0         0 return $x -> as_float(@r) -> to_fp80();
3828             }
3829              
3830             sub as_hex {
3831 2 50   2 1 33 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
3832              
3833 2 50       7 return $x unless $x -> is_int();
3834              
3835 2 50       7 my $s = $x->{sign}; $s = '' if $s eq '+';
  2         11  
3836 2         14 $s . $LIB->_as_hex($x->{_n});
3837             }
3838              
3839             sub as_oct {
3840 2 50   2 1 39 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
3841              
3842 2 50       11 return $x unless $x -> is_int();
3843              
3844 2 50       8 my $s = $x->{sign}; $s = '' if $s eq '+';
  2         10  
3845 2         12 $s . $LIB->_as_oct($x->{_n});
3846             }
3847              
3848             sub as_bin {
3849 2 50   2 1 14 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
3850              
3851 2 50       9 return $x unless $x -> is_int();
3852              
3853 2         31 my $s = $x->{sign};
3854 2 50       11 $s = '' if $s eq '+';
3855 2         14 $s . $LIB->_as_bin($x->{_n});
3856             }
3857              
3858             sub numify {
3859             # convert 17/8 => float (aka 2.125)
3860 39 50   39 1 607 my ($self, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
3861              
3862             # Non-finite number.
3863              
3864 39 100       146 if ($x -> is_nan()) {
3865 1         6 require Math::Complex;
3866 1         3 my $inf = $Math::Complex::Inf;
3867 1         3 return $inf - $inf;
3868             }
3869              
3870 38 100       128 if ($x -> is_inf()) {
3871 2         13 require Math::Complex;
3872 2         6 my $inf = $Math::Complex::Inf;
3873 2 100       23 return $x -> is_negative() ? -$inf : $inf;
3874             }
3875              
3876             # Finite number.
3877              
3878             my $abs = $LIB->_is_one($x->{_d})
3879             ? $LIB->_num($x->{_n})
3880             : Math::BigFloat -> new($LIB->_str($x->{_n}))
3881 36 100       151 -> bfdiv($LIB->_str($x->{_d}))
3882             -> bstr();
3883 36 100       601 return $x->{sign} eq '-' ? 0 - $abs : 0 + $abs;
3884             }
3885              
3886             ##############################################################################
3887             # import
3888              
3889             sub import {
3890 18     18   746 my $class = shift;
3891 18         39 $IMPORT++; # remember we did import()
3892 18         55 my @a; # unrecognized arguments
3893              
3894 18         47 my @import = ();
3895              
3896 18         83 while (@_) {
3897 4         11 my $param = shift;
3898              
3899             # Enable overloading of constants.
3900              
3901 4 50       18 if ($param eq ':constant') {
3902             overload::constant
3903              
3904             integer => sub {
3905 0     0   0 $class -> new(shift);
3906             },
3907              
3908             float => sub {
3909 0     0   0 $class -> new(shift);
3910             },
3911              
3912             binary => sub {
3913             # E.g., a literal 0377 shall result in an object whose value
3914             # is decimal 255, but new("0377") returns decimal 377.
3915 0 0   0   0 return $class -> from_oct($_[0]) if $_[0] =~ /^0_*[0-7]/;
3916 0         0 $class -> new(shift);
3917 0         0 };
3918 0         0 next;
3919             }
3920              
3921             # Upgrading.
3922              
3923 4 50       17 if ($param eq 'upgrade') {
3924 0         0 $class -> upgrade(shift);
3925 0         0 next;
3926             }
3927              
3928             # Downgrading.
3929              
3930 4 100       12 if ($param eq 'downgrade') {
3931 1         10 $class -> downgrade(shift);
3932 1         4 next;
3933             }
3934              
3935             # Accuracy.
3936              
3937 3 50       12 if ($param eq 'accuracy') {
3938 0         0 $class -> accuracy(shift);
3939 0         0 next;
3940             }
3941              
3942             # Precision.
3943              
3944 3 50       11 if ($param eq 'precision') {
3945 0         0 $class -> precision(shift);
3946 0         0 next;
3947             }
3948              
3949             # Rounding mode.
3950              
3951 3 50       11 if ($param eq 'round_mode') {
3952 0         0 $class -> round_mode(shift);
3953 0         0 next;
3954             }
3955              
3956             # Fall-back accuracy.
3957              
3958 3 50       11 if ($param eq 'div_scale') {
3959 0         0 $class -> div_scale(shift);
3960 0         0 next;
3961             }
3962              
3963             # Backend library.
3964              
3965 3 50       27 if ($param =~ /^(lib|try|only)\z/) {
3966 3         10 push @import, $param;
3967 3 50       22 push @import, shift() if @_;
3968 3         13 next;
3969             }
3970              
3971 0 0       0 if ($param eq 'with') {
3972             # alternative class for our private parts()
3973             # XXX: no longer supported
3974             # $LIB = shift() || 'Calc';
3975             # carp "'with' is no longer supported, use 'lib', 'try', or 'only'";
3976 0         0 shift;
3977 0         0 next;
3978             }
3979              
3980             # Unrecognized parameter.
3981              
3982 0         0 push @a, $param;
3983             }
3984              
3985 18         147 Math::BigInt -> import(@import);
3986              
3987             # find out which library was actually loaded
3988 18         119 $LIB = Math::BigInt -> config("lib");
3989              
3990 18         245 $class -> SUPER::import(@a); # for subclasses
3991 18 50       31640 $class -> export_to_level(1, $class, @a) if @a; # need this, too
3992             }
3993              
3994             1;
3995              
3996             __END__