File Coverage

blib/lib/Math/BigRat.pm
Criterion Covered Total %
statement 828 1040 79.6
branch 538 808 66.5
condition 227 393 57.7
subroutine 97 132 73.4
pod 69 70 98.5
total 1759 2443 72.0


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             # sign : +,-,NaN,+inf,-inf
7             # _d : denominator
8             # _n : numerator (value = _n/_d)
9             # _a : accuracy
10             # _p : precision
11             # You should not look at the innards of a BigRat - use the methods for this.
12              
13             package Math::BigRat;
14              
15 19     19   1061081 use 5.006;
  19         194  
16 19     19   80 use strict;
  19         25  
  19         396  
17 19     19   84 use warnings;
  19         45  
  19         586  
18              
19 19     19   79 use Carp qw< carp croak >;
  19         32  
  19         959  
20 19     19   105 use Scalar::Util qw< blessed >;
  19         46  
  19         696  
21              
22 19     19   15224 use Math::BigFloat ();
  19         822038  
  19         21268  
23              
24             our $VERSION = '0.2622';
25              
26             our @ISA = qw(Math::BigFloat);
27              
28             our ($accuracy, $precision, $round_mode, $div_scale,
29             $upgrade, $downgrade, $_trap_nan, $_trap_inf);
30              
31             use overload
32              
33             # overload key: with_assign
34              
35 49     49   237 '+' => sub { $_[0] -> copy() -> badd($_[1]); },
36              
37 53     53   259 '-' => sub { my $c = $_[0] -> copy;
38 53 50       134 $_[2] ? $c -> bneg() -> badd( $_[1])
39             : $c -> bsub($_[1]); },
40              
41 55     55   1398 '*' => sub { $_[0] -> copy() -> bmul($_[1]); },
42              
43 49 50   49   365 '/' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bdiv($_[0])
44             : $_[0] -> copy() -> bdiv($_[1]); },
45              
46 21 50   21   127 '%' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bmod($_[0])
47             : $_[0] -> copy() -> bmod($_[1]); },
48              
49 2 50   2   10 '**' => 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]) -> blsft($_[0])
53             : $_[0] -> copy() -> blsft($_[1]); },
54              
55 0 0   0   0 '>>' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> brsft($_[0])
56             : $_[0] -> copy() -> brsft($_[1]); },
57              
58             # overload key: assign
59              
60 0     0   0 '+=' => sub { $_[0]->badd($_[1]); },
61              
62 1     1   256 '-=' => sub { $_[0]->bsub($_[1]); },
63              
64 1     1   7 '*=' => sub { $_[0]->bmul($_[1]); },
65              
66 0     0   0 '/=' => sub { scalar $_[0]->bdiv($_[1]); },
67              
68 0     0   0 '%=' => sub { $_[0]->bmod($_[1]); },
69              
70 0     0   0 '**=' => sub { $_[0]->bpow($_[1]); },
71              
72 0     0   0 '<<=' => sub { $_[0]->blsft($_[1]); },
73              
74 0     0   0 '>>=' => sub { $_[0]->brsft($_[1]); },
75              
76             # 'x=' => sub { },
77              
78             # '.=' => sub { },
79              
80             # overload key: num_comparison
81              
82 19 50   19   103 '<' => 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 24 50   24   132 '>' => 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 10     10   188 '==' => 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 1791 50   1791   458109 '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   22855 '&' => 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   25489 '|' => 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   24730 '^' => 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 6     6   38 '++' => sub { $_[0] -> binc() },
166              
167 5     5   29 '--' => 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 7     7   36 'log' => sub { $_[0] -> copy() -> blog(); },
183              
184 0     0   0 'sqrt' => sub { $_[0] -> copy() -> bsqrt(); },
185              
186 2     2   12 'int' => sub { $_[0] -> copy() -> bint(); },
187              
188             # overload key: conversion
189              
190 0 0   0   0 'bool' => sub { $_[0] -> is_zero() ? '' : 1; },
191              
192 5248     5248   270179 '""' => sub { $_[0] -> bstr(); },
193              
194 8     8   39 '0+' => sub { $_[0] -> numify(); },
195              
196 0     0   0 '=' => sub { $_[0]->copy(); },
197              
198 19     19   207 ;
  19         35  
  19         1163  
199              
200             BEGIN {
201 19     19   8345 *objectify = \&Math::BigInt::objectify; # inherit this from BigInt
202 19         41 *AUTOLOAD = \&Math::BigFloat::AUTOLOAD; # can't inherit AUTOLOAD
203             # We inherit these from BigFloat because currently it is not possible that
204             # Math::BigFloat has a different $LIB variable than we, because
205             # Math::BigFloat also uses Math::BigInt::config->('lib') (there is always
206             # only one library loaded)
207 19         32 *_e_add = \&Math::BigFloat::_e_add;
208 19         31 *_e_sub = \&Math::BigFloat::_e_sub;
209 19         50 *as_number = \&as_int;
210 19         45 *is_pos = \&is_positive;
211 19         192564 *is_neg = \&is_negative;
212             }
213              
214             ##############################################################################
215             # Global constants and flags. Access these only via the accessor methods!
216              
217             $accuracy = $precision = undef;
218             $round_mode = 'even';
219             $div_scale = 40;
220             $upgrade = undef;
221             $downgrade = undef;
222              
223             # These are internally, and not to be used from the outside at all!
224              
225             $_trap_nan = 0; # are NaNs ok? set w/ config()
226             $_trap_inf = 0; # are infs ok? set w/ config()
227              
228             # the math backend library
229              
230             my $LIB = 'Math::BigInt::Calc';
231              
232             my $nan = 'NaN';
233             #my $class = 'Math::BigRat';
234              
235             sub isa {
236 5423 100   5423 0 635075 return 0 if $_[1] =~ /^Math::Big(Int|Float)/; # we aren't
237 3530         11643 UNIVERSAL::isa(@_);
238             }
239              
240             ##############################################################################
241              
242             sub new {
243 19671     19671 1 12969991 my $proto = shift;
244 19671         29455 my $protoref = ref $proto;
245 19671   33     59422 my $class = $protoref || $proto;
246              
247             # Check the way we are called.
248              
249 19671 50       34849 if ($protoref) {
250 0         0 croak("new() is a class method, not an instance method");
251             }
252              
253 19671 100       31675 if (@_ < 1) {
254             #carp("Using new() with no argument is deprecated;",
255             # " use bzero() or new(0) instead");
256 1         3 return $class -> bzero();
257             }
258              
259 19670 50       29958 if (@_ > 2) {
260 0         0 carp("Superfluous arguments to new() ignored.");
261             }
262              
263             # Get numerator and denominator. If any of the arguments is undefined,
264             # return zero.
265              
266 19670         30727 my ($n, $d) = @_;
267              
268 19670 100 100     75788 if (@_ == 1 && !defined $n ||
      33        
      66        
      66        
269             @_ == 2 && (!defined $n || !defined $d))
270             {
271             #carp("Use of uninitialized value in new()");
272 1         3 return $class -> bzero();
273             }
274              
275             # Initialize a new object.
276              
277 19669         31146 my $self = bless {}, $class;
278              
279             # One or two input arguments may be given. First handle the numerator $n.
280              
281 19669 100       31461 if (ref($n)) {
282 5828 50 66     37492 $n = Math::BigFloat -> new($n, undef, undef)
      66        
283             unless ($n -> isa('Math::BigRat') ||
284             $n -> isa('Math::BigInt') ||
285             $n -> isa('Math::BigFloat'));
286             } else {
287 13841 100       18899 if (defined $d) {
288             # If the denominator is defined, the numerator is not a string
289             # fraction, e.g., "355/113".
290 5         12 $n = Math::BigFloat -> new($n, undef, undef);
291             } else {
292             # If the denominator is undefined, the numerator might be a string
293             # fraction, e.g., "355/113".
294 13836 100       27293 if ($n =~ m| ^ \s* (\S+) \s* / \s* (\S+) \s* $ |x) {
295 397         1151 $n = Math::BigFloat -> new($1, undef, undef);
296 397         19344 $d = Math::BigFloat -> new($2, undef, undef);
297             } else {
298 13439         51711 $n = Math::BigFloat -> new($n, undef, undef);
299             }
300             }
301             }
302              
303             # At this point $n is an object and $d is either an object or undefined. An
304             # undefined $d means that $d was not specified by the caller (not that $d
305             # was specified as an undefined value).
306              
307 19669 100       870235 unless (defined $d) {
308             #return $n -> copy($n) if $n -> isa('Math::BigRat');
309 19262 50       39604 if ($n -> isa('Math::BigRat')) {
310 0 0 0     0 return $downgrade -> new($n) if defined($downgrade) && $n -> is_int();
311 0         0 return $class -> copy($n);
312             }
313              
314 19262 100       128064 if ($n -> is_nan()) {
315 333         1940 return $class -> bnan();
316             }
317              
318 18929 100       111451 if ($n -> is_inf()) {
319 563         4545 return $class -> binf($n -> sign());
320             }
321              
322 18366 100       118306 if ($n -> isa('Math::BigInt')) {
323 5717         16279 $self -> {_n} = $LIB -> _new($n -> copy() -> babs() -> bstr());
324 5717         234322 $self -> {_d} = $LIB -> _one();
325 5717         28412 $self -> {sign} = $n -> sign();
326 5717 100       29004 return $downgrade -> new($n) if defined $downgrade;
327 5716         10821 return $self;
328             }
329              
330 12649 50       70383 if ($n -> isa('Math::BigFloat')) {
331 12649         83900 my $m = $n -> mantissa() -> babs();
332 12649         757571 my $e = $n -> exponent();
333 12649         1026107 $self -> {_n} = $LIB -> _new($m -> bstr());
334 12649         235544 $self -> {_d} = $LIB -> _one();
335              
336 12649 100       69807 if ($e > 0) {
    100          
337             $self -> {_n} = $LIB -> _lsft($self -> {_n},
338 747         113472 $LIB -> _new($e -> bstr()), 10);
339             } elsif ($e < 0) {
340             $self -> {_d} = $LIB -> _lsft($self -> {_d},
341 880         235316 $LIB -> _new(-$e -> bstr()), 10);
342              
343 880         85224 my $gcd = $LIB -> _gcd($LIB -> _copy($self -> {_n}), $self -> {_d});
344 880 100       79457 if (!$LIB -> _is_one($gcd)) {
345 852         4636 $self -> {_n} = $LIB -> _div($self->{_n}, $gcd);
346 852         8286 $self -> {_d} = $LIB -> _div($self->{_d}, $gcd);
347             }
348             }
349              
350 12649         3045064 $self -> {sign} = $n -> sign();
351 12649 100 100     74983 return $downgrade -> new($n) if defined($downgrade) && $n -> is_int();
352 12644         127967 return $self;
353             }
354              
355 0         0 die "I don't know how to handle this"; # should never get here
356             }
357              
358             # At the point we know that both $n and $d are defined. We know that $n is
359             # an object, but $d might still be a scalar. Now handle $d.
360              
361 407 100 66     1270 $d = Math::BigFloat -> new($d, undef, undef)
      100        
362             unless ref($d) && ($d -> isa('Math::BigRat') ||
363             $d -> isa('Math::BigInt') ||
364             $d -> isa('Math::BigFloat'));
365              
366             # At this point both $n and $d are objects.
367              
368 407 100 66     7705 if ($n -> is_nan() || $d -> is_nan()) {
369 3         21 return $class -> bnan();
370             }
371              
372             # At this point neither $n nor $d is a NaN.
373              
374 404 100       4094 if ($n -> is_zero()) {
375 6 50       63 if ($d -> is_zero()) { # 0/0 = NaN
376 0         0 return $class -> bnan();
377             }
378 6         56 return $class -> bzero();
379             }
380              
381 398 50       3439 if ($d -> is_zero()) {
382 0         0 return $class -> binf($d -> sign());
383             }
384              
385             # At this point, neither $n nor $d is a NaN or a zero.
386              
387             # Copy them now before manipulating them.
388              
389 398         3444 $n = $n -> copy();
390 398         9717 $d = $d -> copy();
391              
392 398 100       7891 if ($d < 0) { # make sure denominator is positive
393 10         1317 $n -> bneg();
394 10         139 $d -> bneg();
395             }
396              
397 398 100       62617 if ($n -> is_inf()) {
398 8 100       105 return $class -> bnan() if $d -> is_inf(); # Inf/Inf = NaN
399 7         42 return $class -> binf($n -> sign());
400             }
401              
402             # At this point $n is finite.
403              
404 390 100       2595 return $class -> bzero() if $d -> is_inf();
405 386 50       2097 return $class -> binf($d -> sign()) if $d -> is_zero();
406              
407             # At this point both $n and $d are finite and non-zero.
408              
409 386 100       3514 if ($n < 0) {
410 129         16843 $n -> bneg();
411 129         1336 $self -> {sign} = '-';
412             } else {
413 257         37342 $self -> {sign} = '+';
414             }
415              
416 386 50       746 if ($n -> isa('Math::BigRat')) {
417              
418 0 0       0 if ($d -> isa('Math::BigRat')) {
419              
420             # At this point both $n and $d is a Math::BigRat.
421              
422             # p r p * s (p / gcd(p, r)) * (s / gcd(s, q))
423             # - / - = ----- = ---------------------------------
424             # q s q * r (q / gcd(s, q)) * (r / gcd(p, r))
425              
426 0         0 my $p = $n -> {_n};
427 0         0 my $q = $n -> {_d};
428 0         0 my $r = $d -> {_n};
429 0         0 my $s = $d -> {_d};
430 0         0 my $gcd_pr = $LIB -> _gcd($LIB -> _copy($p), $r);
431 0         0 my $gcd_sq = $LIB -> _gcd($LIB -> _copy($s), $q);
432 0         0 $self -> {_n} = $LIB -> _mul($LIB -> _div($LIB -> _copy($p), $gcd_pr),
433             $LIB -> _div($LIB -> _copy($s), $gcd_sq));
434 0         0 $self -> {_d} = $LIB -> _mul($LIB -> _div($LIB -> _copy($q), $gcd_sq),
435             $LIB -> _div($LIB -> _copy($r), $gcd_pr));
436              
437 0 0 0     0 return $downgrade -> new($n->bstr())
438             if defined($downgrade) && $self -> is_int();
439 0         0 return $self; # no need for $self -> bnorm() here
440             }
441              
442             # At this point, $n is a Math::BigRat and $d is a Math::Big(Int|Float).
443              
444 0         0 my $p = $n -> {_n};
445 0         0 my $q = $n -> {_d};
446 0         0 my $m = $d -> mantissa();
447 0         0 my $e = $d -> exponent();
448              
449             # / p
450             # | ------------ if e > 0
451             # | q * m * 10^e
452             # |
453             # p | p
454             # - / (m * 10^e) = | ----- if e == 0
455             # q | q * m
456             # |
457             # | p * 10^-e
458             # | -------- if e < 0
459             # \ q * m
460              
461 0         0 $self -> {_n} = $LIB -> _copy($p);
462 0         0 $self -> {_d} = $LIB -> _mul($LIB -> _copy($q), $m);
463 0 0       0 if ($e > 0) {
    0          
464 0         0 $self -> {_d} = $LIB -> _lsft($self -> {_d}, $e, 10);
465             } elsif ($e < 0) {
466 0         0 $self -> {_n} = $LIB -> _lsft($self -> {_n}, -$e, 10);
467             }
468              
469 0         0 return $self -> bnorm();
470              
471             } else {
472              
473 386 50       2686 if ($d -> isa('Math::BigRat')) {
474              
475             # At this point $n is a Math::Big(Int|Float) and $d is a
476             # Math::BigRat.
477              
478 0         0 my $m = $n -> mantissa();
479 0         0 my $e = $n -> exponent();
480 0         0 my $p = $d -> {_n};
481 0         0 my $q = $d -> {_d};
482              
483             # / q * m * 10^e
484             # | ------------ if e > 0
485             # | p
486             # |
487             # p | m * q
488             # (m * 10^e) / - = | ----- if e == 0
489             # q | p
490             # |
491             # | q * m
492             # | --------- if e < 0
493             # \ p * 10^-e
494              
495 0         0 $self -> {_n} = $LIB -> _mul($LIB -> _copy($q), $m);
496 0         0 $self -> {_d} = $LIB -> _copy($p);
497 0 0       0 if ($e > 0) {
    0          
498 0         0 $self -> {_n} = $LIB -> _lsft($self -> {_n}, $e, 10);
499             } elsif ($e < 0) {
500 0         0 $self -> {_d} = $LIB -> _lsft($self -> {_d}, -$e, 10);
501             }
502 0         0 return $self -> bnorm();
503              
504             } else {
505              
506             # At this point $n and $d are both a Math::Big(Int|Float)
507              
508 386         2378 my $m1 = $n -> mantissa();
509 386         17679 my $e1 = $n -> exponent();
510 386         28454 my $m2 = $d -> mantissa();
511 386         14542 my $e2 = $d -> exponent();
512              
513             # /
514             # | m1 * 10^(e1 - e2)
515             # | ----------------- if e1 > e2
516             # | m2
517             # |
518             # m1 * 10^e1 | m1
519             # ---------- = | -- if e1 = e2
520             # m2 * 10^e2 | m2
521             # |
522             # | m1
523             # | ----------------- if e1 < e2
524             # | m2 * 10^(e2 - e1)
525             # \
526              
527 386         26596 $self -> {_n} = $LIB -> _new($m1 -> bstr());
528 386         6876 $self -> {_d} = $LIB -> _new($m2 -> bstr());
529 386         6079 my $ediff = $e1 - $e2;
530 386 100       22684 if ($ediff > 0) {
    100          
531             $self -> {_n} = $LIB -> _lsft($self -> {_n},
532 24         4066 $LIB -> _new($ediff -> bstr()),
533             10);
534             } elsif ($ediff < 0) {
535             $self -> {_d} = $LIB -> _lsft($self -> {_d},
536 22         5546 $LIB -> _new(-$ediff -> bstr()),
537             10);
538             }
539              
540 386         91054 return $self -> bnorm();
541             }
542             }
543              
544 0 0 0     0 return $downgrade -> new($self -> bstr())
545             if defined($downgrade) && $self -> is_int();
546 0         0 return $self;
547             }
548              
549             sub copy {
550 1319     1319 1 57858 my $self = shift;
551 1319         1872 my $selfref = ref $self;
552 1319   33     2642 my $class = $selfref || $self;
553              
554             # If called as a class method, the object to copy is the next argument.
555              
556 1319 50       2245 $self = shift() unless $selfref;
557              
558 1319         2240 my $copy = bless {}, $class;
559              
560 1319         3010 $copy->{sign} = $self->{sign};
561 1319         3110 $copy->{_d} = $LIB->_copy($self->{_d});
562 1319         7301 $copy->{_n} = $LIB->_copy($self->{_n});
563 1319 50       7028 $copy->{_a} = $self->{_a} if defined $self->{_a};
564 1319 50       2129 $copy->{_p} = $self->{_p} if defined $self->{_p};
565              
566             #($copy, $copy->{_a}, $copy->{_p})
567             # = $copy->_find_round_parameters(@_);
568              
569 1319         3700 return $copy;
570             }
571              
572             sub bnan {
573 537     537 1 2163 my $self = shift;
574 537         690 my $selfref = ref $self;
575 537   66     1189 my $class = $selfref || $self;
576              
577 537 100       898 $self = bless {}, $class unless $selfref;
578              
579 537 100       941 if ($_trap_nan) {
580 5         621 croak ("Tried to set a variable to NaN in $class->bnan()");
581             }
582              
583 532 100       809 return $downgrade -> bnan() if defined $downgrade;
584              
585 525         909 $self -> {sign} = $nan;
586 525         903 $self -> {_n} = $LIB -> _zero();
587 525         2195 $self -> {_d} = $LIB -> _one();
588              
589             ($self, $self->{_a}, $self->{_p})
590 525         2283 = $self->_find_round_parameters(@_);
591              
592 525         14508 return $self;
593             }
594              
595             sub binf {
596 751     751 1 4401 my $self = shift;
597 751         964 my $selfref = ref $self;
598 751   66     1744 my $class = $selfref || $self;
599              
600 751 100       1369 $self = bless {}, $class unless $selfref;
601              
602 751         990 my $sign = shift();
603 751 100 100     2389 $sign = defined($sign) && substr($sign, 0, 1) eq '-' ? '-inf' : '+inf';
604              
605 751 100       1249 if ($_trap_inf) {
606 12         1102 croak ("Tried to set a variable to +-inf in $class->binf()");
607             }
608              
609 739 100       1087 return $downgrade -> binf($sign) if defined $downgrade;
610              
611 732         1111 $self -> {sign} = $sign;
612 732         1425 $self -> {_n} = $LIB -> _zero();
613 732         3150 $self -> {_d} = $LIB -> _one();
614              
615             ($self, $self->{_a}, $self->{_p})
616 732         3240 = $self->_find_round_parameters(@_);
617              
618 732         21607 return $self;
619             }
620              
621             sub bone {
622 13     13 1 947 my $self = shift;
623 13         23 my $selfref = ref $self;
624 13   66     30 my $class = $selfref || $self;
625              
626 13         18 my $sign = shift();
627 13 100 100     56 $sign = '+' unless defined($sign) && $sign eq '-';
628              
629 13 100       27 return $downgrade -> bone($sign) if defined $downgrade;
630              
631 12 50       21 $self = bless {}, $class unless $selfref;
632 12         16 $self -> {sign} = $sign;
633 12         24 $self -> {_n} = $LIB -> _one();
634 12         53 $self -> {_d} = $LIB -> _one();
635              
636             ($self, $self->{_a}, $self->{_p})
637 12         52 = $self->_find_round_parameters(@_);
638              
639 12         304 return $self;
640             }
641              
642             sub bzero {
643 62     62 1 1276 my $self = shift;
644 62         107 my $selfref = ref $self;
645 62   66     170 my $class = $selfref || $self;
646              
647 62 100       118 return $downgrade -> bzero() if defined $downgrade;
648              
649 61 100       126 $self = bless {}, $class unless $selfref;
650 61         113 $self -> {sign} = '+';
651 61         128 $self -> {_n} = $LIB -> _zero();
652 61         290 $self -> {_d} = $LIB -> _one();
653              
654             ($self, $self->{_a}, $self->{_p})
655 61         308 = $self->_find_round_parameters(@_);
656              
657 61         1666 return $self;
658             }
659              
660             ##############################################################################
661              
662             sub config {
663             # return (later set?) configuration data as hash ref
664 12   50 12 1 3647 my $class = shift() || 'Math::BigRat';
665              
666 12 100 100     42 if (@_ == 1 && ref($_[0]) ne 'HASH') {
667 6         16 my $cfg = $class->SUPER::config();
668 6         252 return $cfg->{$_[0]};
669             }
670              
671 6         28 my $cfg = $class->SUPER::config(@_);
672              
673             # now we need only to override the ones that are different from our parent
674 6         735 $cfg->{class} = $class;
675 6         8 $cfg->{with} = $LIB;
676              
677 6         17 $cfg;
678             }
679              
680             ##############################################################################
681              
682             sub bstr {
683 29743 50   29743 1 10686695 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
684              
685 29743 100       96906 if ($x->{sign} !~ /^[+-]$/) { # inf, NaN etc
686 1200         1629 my $s = $x->{sign};
687 1200         2111 $s =~ s/^\+//; # +inf => inf
688 1200         6138 return $s;
689             }
690              
691 28543         35929 my $s = '';
692 28543 100       54929 $s = $x->{sign} if $x->{sign} ne '+'; # '+3/2' => '3/2'
693              
694 28543 100       71790 return $s . $LIB->_str($x->{_n}) if $LIB->_is_one($x->{_d});
695 1823         9456 $s . $LIB->_str($x->{_n}) . '/' . $LIB->_str($x->{_d});
696             }
697              
698             sub bsstr {
699 8 50   8 1 39 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
700              
701 8 100       26 if ($x->{sign} !~ /^[+-]$/) { # inf, NaN etc
702 3         5 my $s = $x->{sign};
703 3         5 $s =~ s/^\+//; # +inf => inf
704 3         19 return $s;
705             }
706              
707 5         8 my $s = '';
708 5 100       11 $s = $x->{sign} if $x->{sign} ne '+'; # +3 vs 3
709 5         13 $s . $LIB->_str($x->{_n}) . '/' . $LIB->_str($x->{_d});
710             }
711              
712             sub bnorm {
713             # reduce the number to the shortest form
714 769 100   769 1 8076 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
715              
716             # Both parts must be objects of whatever we are using today.
717 769 50       1881 if (my $c = $LIB->_check($x->{_n})) {
718 0         0 croak("n did not pass the self-check ($c) in bnorm()");
719             }
720 769 50       21365 if (my $c = $LIB->_check($x->{_d})) {
721 0         0 croak("d did not pass the self-check ($c) in bnorm()");
722             }
723              
724             # no normalize for NaN, inf etc.
725 769 100       17002 if ($x->{sign} !~ /^[+-]$/) {
726 18 100       36 return $downgrade -> new($x) if defined $downgrade;
727 16         111 return $x;
728             }
729              
730             # normalize zeros to 0/1
731 751 100       1532 if ($LIB->_is_zero($x->{_n})) {
732 36 100       163 return $downgrade -> bzero() if defined($downgrade);
733 33         43 $x->{sign} = '+'; # never leave a -0
734 33 100       51 $x->{_d} = $LIB->_one() unless $LIB->_is_one($x->{_d});
735 33         248 return $x;
736             }
737              
738             # n/1
739 715 100       3478 if ($LIB->_is_one($x->{_d})) {
740 216 100       942 return $downgrade -> new($x) if defined($downgrade);
741 205         1526 return $x; # no need to reduce
742             }
743              
744             # Compute the GCD.
745 499         2540 my $gcd = $LIB->_gcd($LIB->_copy($x->{_n}), $x->{_d});
746 499 100       24187 if (!$LIB->_is_one($gcd)) {
747 97         533 $x->{_n} = $LIB->_div($x->{_n}, $gcd);
748 97         1055 $x->{_d} = $LIB->_div($x->{_d}, $gcd);
749             }
750              
751 499         6954 $x;
752             }
753              
754             ##############################################################################
755             # sign manipulation
756              
757             sub bneg {
758             # (BRAT or num_str) return BRAT
759             # negate number or make a negated number from string
760 26 50   26 1 103 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
761              
762 26 50       72 return $x if $x->modify('bneg');
763              
764             # for +0 do not negate (to have always normalized +0). Does nothing for 'NaN'
765             $x->{sign} =~ tr/+-/-+/
766 26 100 100     87 unless ($x->{sign} eq '+' && $LIB->_is_zero($x->{_n}));
767              
768             return $downgrade -> new($x)
769 26 100 100     106 if defined($downgrade) && $LIB -> _is_one($x->{_d});
770 22         191 $x;
771             }
772              
773             ##############################################################################
774             # special values
775              
776             sub _bnan {
777             # used by parent class bnan() to initialize number to NaN
778 0     0   0 my $self = shift;
779              
780 0 0       0 if ($_trap_nan) {
781 0         0 my $class = ref($self);
782             # "$self" below will stringify the object, this blows up if $self is a
783             # partial object (happens under trap_nan), so fix it beforehand
784 0 0       0 $self->{_d} = $LIB->_zero() unless defined $self->{_d};
785 0 0       0 $self->{_n} = $LIB->_zero() unless defined $self->{_n};
786 0         0 croak ("Tried to set $self to NaN in $class\::_bnan()");
787             }
788 0         0 $self->{_n} = $LIB->_zero();
789 0         0 $self->{_d} = $LIB->_zero();
790             }
791              
792             sub _binf {
793             # used by parent class bone() to initialize number to +inf/-inf
794 0     0   0 my $self = shift;
795              
796 0 0       0 if ($_trap_inf) {
797 0         0 my $class = ref($self);
798             # "$self" below will stringify the object, this blows up if $self is a
799             # partial object (happens under trap_nan), so fix it beforehand
800 0 0       0 $self->{_d} = $LIB->_zero() unless defined $self->{_d};
801 0 0       0 $self->{_n} = $LIB->_zero() unless defined $self->{_n};
802 0         0 croak ("Tried to set $self to inf in $class\::_binf()");
803             }
804 0         0 $self->{_n} = $LIB->_zero();
805 0         0 $self->{_d} = $LIB->_zero();
806             }
807              
808             sub _bone {
809             # used by parent class bone() to initialize number to +1/-1
810 0     0   0 my $self = shift;
811 0         0 $self->{_n} = $LIB->_one();
812 0         0 $self->{_d} = $LIB->_one();
813             }
814              
815             sub _bzero {
816             # used by parent class bzero() to initialize number to 0
817 0     0   0 my $self = shift;
818 0         0 $self->{_n} = $LIB->_zero();
819 0         0 $self->{_d} = $LIB->_one();
820             }
821              
822             ##############################################################################
823             # mul/add/div etc
824              
825             sub badd {
826             # add two rational numbers
827              
828             # set up parameters
829 325     325 1 1280 my ($class, $x, $y, @r) = (ref($_[0]), @_);
830             # objectify is costly, so avoid it
831 325 100 66     1008 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
832 91         186 ($class, $x, $y, @r) = objectify(2, @_);
833             }
834              
835 325 100 100     1121 unless ($x -> is_finite() && $y -> is_finite()) {
836 202 100 100     1260 if ($x -> is_nan() || $y -> is_nan()) {
    100          
    100          
    100          
    50          
837 62         426 return $x -> bnan(@r);
838             } elsif ($x -> is_inf("+")) {
839 41 100       1289 return $x -> bnan(@r) if $y -> is_inf("-");
840 35         585 return $x -> binf("+", @r);
841             } elsif ($x -> is_inf("-")) {
842 41 100       1641 return $x -> bnan(@r) if $y -> is_inf("+");
843 35         559 return $x -> binf("-", @r);
844             } elsif ($y -> is_inf("+")) {
845 30         1564 return $x -> binf("+", @r);
846             } elsif ($y -> is_inf("-")) {
847 28         1951 return $x -> binf("-", @r);
848             }
849             }
850              
851             # 1 1 gcd(3, 4) = 1 1*3 + 1*4 7
852             # - + - = --------- = --
853             # 4 3 4*3 12
854              
855             # we do not compute the gcd() here, but simple do:
856             # 5 7 5*3 + 7*4 43
857             # - + - = --------- = --
858             # 4 3 4*3 12
859              
860             # and bnorm() will then take care of the rest
861              
862             # 5 * 3
863 123         1119 $x->{_n} = $LIB->_mul($x->{_n}, $y->{_d});
864              
865             # 7 * 4
866 123         1037 my $m = $LIB->_mul($LIB->_copy($y->{_n}), $x->{_d});
867              
868             # 5 * 3 + 7 * 4
869 123         1325 ($x->{_n}, $x->{sign}) = _e_add($x->{_n}, $m, $x->{sign}, $y->{sign});
870              
871             # 4 * 3
872 123         3261 $x->{_d} = $LIB->_mul($x->{_d}, $y->{_d});
873              
874             # normalize result, and possible round
875 123         797 $x->bnorm()->round(@r);
876             }
877              
878             sub bsub {
879             # subtract two rational numbers
880              
881             # set up parameters
882 91     91 1 412 my ($class, $x, $y, @r) = (ref($_[0]), @_);
883             # objectify is costly, so avoid it
884 91 100 66     300 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
885 5         13 ($class, $x, $y, @r) = objectify(2, @_);
886             }
887              
888             # flip sign of $x, call badd(), then flip sign of result
889             $x->{sign} =~ tr/+-/-+/
890 91 100 100     266 unless $x->{sign} eq '+' && $x -> is_zero(); # not -0
891 91         215 $x = $x->badd($y, @r); # does norm and round
892             $x->{sign} =~ tr/+-/-+/
893 91 100 100     640 unless $x->{sign} eq '+' && $x -> is_zero(); # not -0
894              
895 91         223 $x->bnorm();
896             }
897              
898             sub bmul {
899             # multiply two rational numbers
900              
901             # set up parameters
902 93     93 1 373 my ($class, $x, $y, @r) = (ref($_[0]), @_);
903             # objectify is costly, so avoid it
904 93 100 66     299 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
905 6         17 ($class, $x, $y, @r) = objectify(2, @_);
906             }
907              
908 93 100 100     330 return $x->bnan() if $x->{sign} eq 'NaN' || $y->{sign} eq 'NaN';
909              
910             # inf handling
911 85 100 100     231 if ($x->{sign} =~ /^[+-]inf$/ || $y->{sign} =~ /^[+-]inf$/) {
912 13 50 33     22 return $x->bnan() if $x->is_zero() || $y->is_zero();
913             # result will always be +-inf:
914             # +inf * +/+inf => +inf, -inf * -/-inf => +inf
915             # +inf * -/-inf => -inf, -inf * +/+inf => -inf
916 13 100 100     49 return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
917 8 100 100     27 return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
918 6         11 return $x->binf('-');
919             }
920              
921             # x == 0 # also: or y == 1 or y == -1
922 72 100       124 if ($x -> is_zero()) {
923 5 100       39 $x = $downgrade -> bzero($x) if defined $downgrade;
924 5 50       59 return wantarray ? ($x, $class->bzero()) : $x;
925             }
926              
927 67 100       96 if ($y -> is_zero()) {
928 3 50       22 $x = defined($downgrade) ? $downgrade -> bzero($x) : $x -> bzero();
929 3 50       29 return wantarray ? ($x, $class->bzero()) : $x;
930             }
931              
932             # According to Knuth, this can be optimized by doing gcd twice (for d
933             # and n) and reducing in one step. This saves us a bnorm() at the end.
934             #
935             # p s p * s (p / gcd(p, r)) * (s / gcd(s, q))
936             # - * - = ----- = ---------------------------------
937             # q r q * r (q / gcd(s, q)) * (r / gcd(p, r))
938              
939 64         119 my $gcd_pr = $LIB -> _gcd($LIB -> _copy($x->{_n}), $y->{_d});
940 64         2125 my $gcd_sq = $LIB -> _gcd($LIB -> _copy($y->{_n}), $x->{_d});
941              
942             $x->{_n} = $LIB -> _mul(scalar $LIB -> _div($x->{_n}, $gcd_pr),
943 64         1525 scalar $LIB -> _div($LIB -> _copy($y->{_n}),
944             $gcd_sq));
945             $x->{_d} = $LIB -> _mul(scalar $LIB -> _div($x->{_d}, $gcd_sq),
946 64         1676 scalar $LIB -> _div($LIB -> _copy($y->{_d}),
947             $gcd_pr));
948              
949             # compute new sign
950 64 100       1246 $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
951              
952 64         115 $x->bnorm()->round(@r);
953             }
954              
955             sub bdiv {
956             # (dividend: BRAT or num_str, divisor: BRAT or num_str) return
957             # (BRAT, BRAT) (quo, rem) or BRAT (only rem)
958              
959             # set up parameters
960 87     87 1 461 my ($class, $x, $y, @r) = (ref($_[0]), @_);
961             # objectify is costly, so avoid it
962 87 100 66     289 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
963 7         18 ($class, $x, $y, @r) = objectify(2, @_);
964             }
965              
966 87 50       237 return $x if $x->modify('bdiv');
967              
968 87         101 my $wantarray = wantarray; # call only once
969              
970             # At least one argument is NaN. This is handled the same way as in
971             # Math::BigInt -> bdiv(). See the comments in the code implementing that
972             # method.
973              
974 87 100 100     148 if ($x -> is_nan() || $y -> is_nan()) {
975 5 50       35 if ($wantarray) {
976 0 0       0 return $downgrade -> bnan(), $downgrade -> bnan()
977             if defined($downgrade);
978 0         0 return $x -> bnan(), $class -> bnan();
979             } else {
980 5 50       8 return $downgrade -> bnan()
981             if defined($downgrade);
982 5         8 return $x -> bnan();
983             }
984             }
985              
986             # Divide by zero and modulo zero. This is handled the same way as in
987             # Math::BigInt -> bdiv(). See the comments in the code implementing that
988             # method.
989              
990 82 100       762 if ($y -> is_zero()) {
991 11         68 my ($quo, $rem);
992 11 100       18 if ($wantarray) {
993 3         6 $rem = $x -> copy();
994             }
995 11 100       19 if ($x -> is_zero()) {
996 3         19 $quo = $x -> bnan();
997             } else {
998 8         22 $quo = $x -> binf($x -> {sign});
999             }
1000              
1001 8 50 33     17 $quo = $downgrade -> new($quo)
1002             if defined($downgrade) && $quo -> is_int();
1003 8 50 66     21 $rem = $downgrade -> new($rem)
      33        
1004             if $wantarray && defined($downgrade) && $rem -> is_int();
1005 8 100       61 return $wantarray ? ($quo, $rem) : $quo;
1006             }
1007              
1008             # Numerator (dividend) is +/-inf. This is handled the same way as in
1009             # Math::BigInt -> bdiv(). See the comments in the code implementing that
1010             # method.
1011              
1012 71 50       110 if ($x -> is_inf()) {
1013 0         0 my ($quo, $rem);
1014 0 0       0 $rem = $class -> bnan() if $wantarray;
1015 0 0       0 if ($y -> is_inf()) {
1016 0         0 $quo = $x -> bnan();
1017             } else {
1018 0 0       0 my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
1019 0         0 $quo = $x -> binf($sign);
1020             }
1021              
1022 0 0 0     0 $quo = $downgrade -> new($quo)
1023             if defined($downgrade) && $quo -> is_int();
1024 0 0 0     0 $rem = $downgrade -> new($rem)
      0        
1025             if $wantarray && defined($downgrade) && $rem -> is_int();
1026 0 0       0 return $wantarray ? ($quo, $rem) : $quo;
1027             }
1028              
1029             # Denominator (divisor) is +/-inf. This is handled the same way as in
1030             # Math::BigFloat -> bdiv(). See the comments in the code implementing that
1031             # method.
1032              
1033 71 100       392 if ($y -> is_inf()) {
1034 2         14 my ($quo, $rem);
1035 2 50       4 if ($wantarray) {
1036 0 0 0     0 if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
1037 0         0 $rem = $x -> copy();
1038 0         0 $quo = $x -> bzero();
1039             } else {
1040 0         0 $rem = $class -> binf($y -> {sign});
1041 0         0 $quo = $x -> bone('-');
1042             }
1043 0 0 0     0 $quo = $downgrade -> new($quo)
1044             if defined($downgrade) && $quo -> is_int();
1045 0 0 0     0 $rem = $downgrade -> new($rem)
1046             if defined($downgrade) && $rem -> is_int();
1047 0         0 return ($quo, $rem);
1048             } else {
1049 2 50       5 if ($y -> is_inf()) {
1050 2 50 33     12 if ($x -> is_nan() || $x -> is_inf()) {
1051 0 0       0 return $downgrade -> bnan() if defined $downgrade;
1052 0         0 return $x -> bnan();
1053             } else {
1054 2 50       21 return $downgrade -> bzero() if defined $downgrade;
1055 2         6 return $x -> bzero();
1056             }
1057             }
1058             }
1059             }
1060              
1061             # At this point, both the numerator and denominator are finite numbers, and
1062             # the denominator (divisor) is non-zero.
1063              
1064             # x == 0?
1065 69 100       320 if ($x->is_zero()) {
1066 3 0       19 return $wantarray ? ($downgrade -> bzero(), $downgrade -> bzero())
    50          
1067             : $downgrade -> bzero() if defined $downgrade;
1068 3 100       23 return $wantarray ? ($x, $class->bzero()) : $x;
1069             }
1070              
1071             # XXX TODO: list context, upgrade
1072             # According to Knuth, this can be optimized by doing gcd twice (for d and n)
1073             # and reducing in one step. This would save us the bnorm() at the end.
1074             #
1075             # p r p * s (p / gcd(p, r)) * (s / gcd(s, q))
1076             # - / - = ----- = ---------------------------------
1077             # q s q * r (q / gcd(s, q)) * (r / gcd(p, r))
1078              
1079 66         155 $x->{_n} = $LIB->_mul($x->{_n}, $y->{_d});
1080 66         715 $x->{_d} = $LIB->_mul($x->{_d}, $y->{_n});
1081              
1082             # compute new sign
1083 66 100       457 $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
1084              
1085 66         160 $x -> bnorm();
1086 66 100       126 if (wantarray) {
1087 6         12 my $rem = $x -> copy();
1088 6         13 $x = $x -> bfloor();
1089 6         13 $x = $x -> round(@r);
1090 6         8 $rem = $rem -> bsub($x -> copy()) -> bmul($y);
1091 6 50 33     20 $x = $downgrade -> new($x) if defined($downgrade) && $x -> is_int();
1092 6 50 33     10 $rem = $downgrade -> new($rem) if defined($downgrade) && $rem -> is_int();
1093 6         19 return $x, $rem;
1094             } else {
1095 60         120 return $x -> round(@r);
1096             }
1097             }
1098              
1099             sub bmod {
1100             # compute "remainder" (in Perl way) of $x / $y
1101              
1102             # set up parameters
1103 21     21 1 43 my ($class, $x, $y, @r) = (ref($_[0]), @_);
1104             # objectify is costly, so avoid it
1105 21 50 33     76 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1106 0         0 ($class, $x, $y, @r) = objectify(2, @_);
1107             }
1108              
1109 21 50       51 return $x if $x->modify('bmod');
1110              
1111             # At least one argument is NaN. This is handled the same way as in
1112             # Math::BigInt -> bmod().
1113              
1114 21 100 100     38 if ($x -> is_nan() || $y -> is_nan()) {
1115 2         18 return $x -> bnan();
1116             }
1117              
1118             # Modulo zero. This is handled the same way as in Math::BigInt -> bmod().
1119              
1120 19 50       167 if ($y -> is_zero()) {
1121 0 0       0 return $downgrade -> bzero() if defined $downgrade;
1122 0         0 return $x;
1123             }
1124              
1125             # Numerator (dividend) is +/-inf. This is handled the same way as in
1126             # Math::BigInt -> bmod().
1127              
1128 19 50       35 if ($x -> is_inf()) {
1129 0         0 return $x -> bnan();
1130             }
1131              
1132             # Denominator (divisor) is +/-inf. This is handled the same way as in
1133             # Math::BigInt -> bmod().
1134              
1135 19 50       107 if ($y -> is_inf()) {
1136 0 0 0     0 if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
1137 0 0 0     0 return $downgrade -> new($x) if defined($downgrade) && $x -> is_int();
1138 0         0 return $x;
1139             } else {
1140 0 0       0 return $downgrade -> binf($y -> sign()) if defined($downgrade);
1141 0         0 return $x -> binf($y -> sign());
1142             }
1143             }
1144              
1145             # At this point, both the numerator and denominator are finite numbers, and
1146             # the denominator (divisor) is non-zero.
1147              
1148 19 50       101 if ($x->is_zero()) { # 0 / 7 = 0, mod 0
1149 0 0       0 return $downgrade -> bzero() if defined $downgrade;
1150 0         0 return $x;
1151             }
1152              
1153             # Compute $x - $y * floor($x/$y). This can probably be optimized by working
1154             # on a lower level.
1155              
1156 19         30 $x -> bsub($x -> copy() -> bdiv($y) -> bfloor() -> bmul($y));
1157 19         49 return $x -> round(@r);
1158             }
1159              
1160             ##############################################################################
1161             # bdec/binc
1162              
1163             sub bdec {
1164             # decrement value (subtract 1)
1165 12 50   12 1 53 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1166              
1167 12 100       48 if ($x->{sign} !~ /^[+-]$/) { # NaN, inf, -inf
1168 3 100       13 return $downgrade -> new($x) if defined $downgrade;
1169 1         8 return $x;
1170             }
1171              
1172 9 100       27 if ($x->{sign} eq '-') {
1173 1         5 $x->{_n} = $LIB->_add($x->{_n}, $x->{_d}); # -5/2 => -7/2
1174             } else {
1175 8 100       41 if ($LIB->_acmp($x->{_n}, $x->{_d}) < 0) # n < d?
1176             {
1177             # 1/3 -- => -2/3
1178 3         22 $x->{_n} = $LIB->_sub($LIB->_copy($x->{_d}), $x->{_n});
1179 3         78 $x->{sign} = '-';
1180             } else {
1181 5         53 $x->{_n} = $LIB->_sub($x->{_n}, $x->{_d}); # 5/2 => 3/2
1182             }
1183             }
1184 9         162 $x->bnorm()->round(@r);
1185             }
1186              
1187             sub binc {
1188             # increment value (add 1)
1189 13 50   13 1 69 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1190              
1191 13 100       57 if ($x->{sign} !~ /^[+-]$/) { # NaN, inf, -inf
1192 3 100       14 return $downgrade -> new($x) if defined $downgrade;
1193 1         8 return $x;
1194             }
1195              
1196 10 100       28 if ($x->{sign} eq '-') {
1197 3 100       9 if ($LIB->_acmp($x->{_n}, $x->{_d}) < 0) {
1198             # -1/3 ++ => 2/3 (overflow at 0)
1199 2         14 $x->{_n} = $LIB->_sub($LIB->_copy($x->{_d}), $x->{_n});
1200 2         47 $x->{sign} = '+';
1201             } else {
1202 1         12 $x->{_n} = $LIB->_sub($x->{_n}, $x->{_d}); # -5/2 => -3/2
1203             }
1204             } else {
1205 7         29 $x->{_n} = $LIB->_add($x->{_n}, $x->{_d}); # 5/2 => 7/2
1206             }
1207 10         149 $x->bnorm()->round(@r);
1208             }
1209              
1210             sub binv {
1211 20     20 1 98 my $x = shift;
1212 20         41 my @r = @_;
1213              
1214 20 50       60 return $x if $x->modify('binv');
1215              
1216 20 100       61 return $x if $x -> is_nan();
1217 18 100       102 return $x -> bzero() if $x -> is_inf();
1218 14 100       108 return $x -> binf("+") if $x -> is_zero();
1219              
1220 12         36 ($x -> {_n}, $x -> {_d}) = ($x -> {_d}, $x -> {_n});
1221 12         115 $x -> round(@r);
1222             }
1223              
1224             ##############################################################################
1225             # is_foo methods (the rest is inherited)
1226              
1227             sub is_int {
1228             # return true if arg (BRAT or num_str) is an integer
1229 9820 50   9820 1 105552 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1230              
1231             return 1 if ($x->{sign} =~ /^[+-]$/) && # NaN and +-inf aren't
1232 9820 100 100     38812 $LIB->_is_one($x->{_d}); # x/y && y != 1 => no integer
1233 31         214 0;
1234             }
1235              
1236             sub is_zero {
1237             # return true if arg (BRAT or num_str) is zero
1238 649 50   649 1 1547 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1239              
1240 649 100 100     1693 return 1 if $x->{sign} eq '+' && $LIB->_is_zero($x->{_n});
1241 576         2644 0;
1242             }
1243              
1244             sub is_one {
1245             # return true if arg (BRAT or num_str) is +1 or -1 if signis given
1246 311 50   311 1 1027 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1247              
1248 311 50       512 croak "too many arguments for is_one()" if @_ > 2;
1249 311   100     636 my $sign = $_[1] || '';
1250 311 100       512 $sign = '+' if $sign ne '-';
1251             return 1 if ($x->{sign} eq $sign &&
1252 311 100 100     727 $LIB->_is_one($x->{_n}) && $LIB->_is_one($x->{_d}));
      100        
1253 274         1387 0;
1254             }
1255              
1256             sub is_odd {
1257             # return true if arg (BFLOAT or num_str) is odd or false if even
1258 25 50   25 1 96 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1259              
1260             return 1 if ($x->{sign} =~ /^[+-]$/) && # NaN & +-inf aren't
1261 25 100 100     87 ($LIB->_is_one($x->{_d}) && $LIB->_is_odd($x->{_n})); # x/2 is not, but 3/1
      100        
1262 15         138 0;
1263             }
1264              
1265             sub is_even {
1266             # return true if arg (BINT or num_str) is even or false if odd
1267 18 50   18 1 103 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1268              
1269 18 100       59 return 0 if $x->{sign} !~ /^[+-]$/; # NaN & +-inf aren't
1270             return 1 if ($LIB->_is_one($x->{_d}) # x/3 is never
1271 15 100 100     32 && $LIB->_is_even($x->{_n})); # but 4/1 is
1272 9         112 0;
1273             }
1274              
1275             ##############################################################################
1276             # parts() and friends
1277              
1278             sub numerator {
1279 39 50   39 1 2443 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
1280              
1281             # NaN, inf, -inf
1282 39 100       168 return Math::BigInt->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
1283              
1284 24         63 my $n = Math::BigInt->new($LIB->_str($x->{_n}));
1285 24         1242 $n->{sign} = $x->{sign};
1286 24         86 $n;
1287             }
1288              
1289             sub denominator {
1290 35 50   35 1 4441 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
1291              
1292             # NaN
1293 35 100       110 return Math::BigInt->new($x->{sign}) if $x->{sign} eq 'NaN';
1294             # inf, -inf
1295 26 100       104 return Math::BigInt->bone() if $x->{sign} !~ /^[+-]$/;
1296              
1297 20         59 Math::BigInt->new($LIB->_str($x->{_d}));
1298             }
1299              
1300             sub parts {
1301 11 50   11 1 61 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
1302              
1303 11         15 my $c = 'Math::BigInt';
1304              
1305 11 100       23 return ($c->bnan(), $c->bnan()) if $x->{sign} eq 'NaN';
1306 10 100       21 return ($c->binf(), $c->binf()) if $x->{sign} eq '+inf';
1307 9 100       15 return ($c->binf('-'), $c->binf()) if $x->{sign} eq '-inf';
1308              
1309 8         21 my $n = $c->new($LIB->_str($x->{_n}));
1310 8         446 $n->{sign} = $x->{sign};
1311 8         16 my $d = $c->new($LIB->_str($x->{_d}));
1312 8         399 ($n, $d);
1313             }
1314              
1315             sub dparts {
1316 16     16 1 48 my $x = shift;
1317 16         20 my $class = ref $x;
1318              
1319 16 50       36 croak("dparts() is an instance method") unless $class;
1320              
1321 16 100       37 if ($x -> is_nan()) {
1322 2 100       14 return $class -> bnan(), $class -> bnan() if wantarray;
1323 1         3 return $class -> bnan();
1324             }
1325              
1326 14 100       120 if ($x -> is_inf()) {
1327 4 100       37 return $class -> binf($x -> sign()), $class -> bzero() if wantarray;
1328 2         7 return $class -> binf($x -> sign());
1329             }
1330              
1331             # 355/113 => 3 + 16/113
1332              
1333 10         70 my ($q, $r) = $LIB -> _div($LIB -> _copy($x -> {_n}), $x -> {_d});
1334              
1335 10         167 my $int = Math::BigRat -> new($x -> {sign} . $LIB -> _str($q));
1336 10 100       28 return $int unless wantarray;
1337              
1338             my $frc = Math::BigRat -> new($x -> {sign} . $LIB -> _str($r),
1339 5         13 $LIB -> _str($x -> {_d}));
1340              
1341 5         18 return $int, $frc;
1342             }
1343              
1344             sub fparts {
1345 14     14 1 77 my $x = shift;
1346 14         22 my $class = ref $x;
1347              
1348 14 50       32 croak("fparts() is an instance method") unless $class;
1349              
1350 14 100       35 return ($class -> bnan(),
1351             $class -> bnan()) if $x -> is_nan();
1352              
1353 13         85 my $numer = $x -> copy();
1354 13         43 my $denom = $class -> bzero();
1355              
1356 13         29 $denom -> {_n} = $numer -> {_d};
1357 13         32 $numer -> {_d} = $LIB -> _one();
1358              
1359 13         70 return ($numer, $denom);
1360             }
1361              
1362             sub length {
1363 5 50   5 1 27 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1364              
1365 5 50       9 return $nan unless $x->is_int();
1366 5         37 $LIB->_len($x->{_n}); # length(-123/1) => length(123)
1367             }
1368              
1369             sub digit {
1370 11 50   11 1 107 my ($class, $x, $n) = ref($_[0]) ? (undef, $_[0], $_[1]) : objectify(1, @_);
1371              
1372 11 50       38 return $nan unless $x->is_int();
1373 11   100     121 $LIB->_digit($x->{_n}, $n || 0); # digit(-123/1, 2) => digit(123, 2)
1374             }
1375              
1376             ##############################################################################
1377             # special calc routines
1378              
1379             sub bceil {
1380 24 50   24 1 107 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
1381              
1382 24 100 100     91 if ($x->{sign} !~ /^[+-]$/ || # NaN or inf or
1383             $LIB->_is_one($x->{_d})) # integer
1384             {
1385 10 100       41 return $downgrade -> new($x) if defined $downgrade;
1386 8         60 return $x;
1387             }
1388              
1389 14         92 $x->{_n} = $LIB->_div($x->{_n}, $x->{_d}); # 22/7 => 3/1 w/ truncate
1390 14         113 $x->{_d} = $LIB->_one(); # d => 1
1391 14 100       79 $x->{_n} = $LIB->_inc($x->{_n}) if $x->{sign} eq '+'; # +22/7 => 4/1
1392 14 100 100     70 $x->{sign} = '+' if $x->{sign} eq '-' && $LIB->_is_zero($x->{_n}); # -0 => 0
1393 14 100       48 return $downgrade -> new($x) if defined $downgrade;
1394 13         91 $x;
1395             }
1396              
1397             sub bfloor {
1398 52 50   52 1 178 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
1399              
1400 52 100 100     215 if ($x->{sign} !~ /^[+-]$/ || # NaN or inf or
1401             $LIB->_is_one($x->{_d})) # integer
1402             {
1403 24 100       125 return $downgrade -> new($x) if defined $downgrade;
1404 22         108 return $x;
1405             }
1406              
1407 28         195 $x->{_n} = $LIB->_div($x->{_n}, $x->{_d}); # 22/7 => 3/1 w/ truncate
1408 28         235 $x->{_d} = $LIB->_one(); # d => 1
1409 28 100       159 $x->{_n} = $LIB->_inc($x->{_n}) if $x->{sign} eq '-'; # -22/7 => -4/1
1410 28 100       133 return $downgrade -> new($x) if defined $downgrade;
1411 27         116 $x;
1412             }
1413              
1414             sub bint {
1415 963 50   963 1 2396 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
1416              
1417 963 100 100     4749 if ($x->{sign} !~ /^[+-]$/ || # NaN or inf or
1418             $LIB->_is_one($x->{_d})) # integer
1419             {
1420 552 100       3237 return $downgrade -> new($x) if defined $downgrade;
1421 550         1501 return $x;
1422             }
1423              
1424 411         2987 $x->{_n} = $LIB->_div($x->{_n}, $x->{_d}); # 22/7 => 3/1 w/ truncate
1425 411         3596 $x->{_d} = $LIB->_one(); # d => 1
1426 411 100 66     3468 $x->{sign} = '+' if $x->{sign} eq '-' && $LIB -> _is_zero($x->{_n});
1427 411 100       741 return $downgrade -> new($x) if defined $downgrade;
1428 410         994 return $x;
1429             }
1430              
1431             sub bfac {
1432 13 50   13 1 54 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1433              
1434             # if $x is not an integer
1435 13 100 66     41 if (($x->{sign} ne '+') || (!$LIB->_is_one($x->{_d}))) {
1436 3         9 return $x->bnan();
1437             }
1438              
1439 10         63 $x->{_n} = $LIB->_fac($x->{_n});
1440             # since _d is 1, we don't need to reduce/norm the result
1441 10         166 $x->round(@r);
1442             }
1443              
1444             sub bpow {
1445             # power ($x ** $y)
1446              
1447             # set up parameters
1448 190     190 1 1188 my ($class, $x, $y, @r) = (ref($_[0]), @_);
1449              
1450             # objectify is costly, so avoid it
1451 190 100 66     890 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1452 6         13 ($class, $x, $y, @r) = objectify(2, @_);
1453             }
1454              
1455 190 50       589 return $x if $x->modify('bpow');
1456              
1457             # $x and/or $y is a NaN
1458 190 100 100     404 return $x->bnan() if $x->is_nan() || $y->is_nan();
1459              
1460             # $x and/or $y is a +/-Inf
1461 161 100       1616 if ($x->is_inf("-")) {
    100          
    100          
    100          
1462 13 100       196 return $x->bzero() if $y->is_negative();
1463 7 100       155 return $x->bnan() if $y->is_zero();
1464 6 100       10 return $x if $y->is_odd();
1465 4         7 return $x->bneg();
1466             } elsif ($x->is_inf("+")) {
1467 13 100       530 return $x->bzero() if $y->is_negative();
1468 7 100       186 return $x->bnan() if $y->is_zero();
1469 6         50 return $x;
1470             } elsif ($y->is_inf("-")) {
1471 11 100       668 return $x->bnan() if $x -> is_one("-");
1472 10 100 100     28 return $x->binf("+") if $x > -1 && $x < 1;
1473 7 100       16 return $x->bone() if $x -> is_one("+");
1474 6         19 return $x->bzero();
1475             } elsif ($y->is_inf("+")) {
1476 11 100       769 return $x->bnan() if $x -> is_one("-");
1477 10 100 100     30 return $x->bzero() if $x > -1 && $x < 1;
1478 7 100       20 return $x->bone() if $x -> is_one("+");
1479 6         16 return $x->binf("+");
1480             }
1481              
1482 113 100       7800 if ($x -> is_zero()) {
1483 11 100       83 return $x -> bone() if $y -> is_zero();
1484 10 100       71 return $x -> binf() if $y -> is_negative();
1485 5         188 return $x;
1486             }
1487              
1488             # We don't support complex numbers, so upgrade or return NaN.
1489              
1490 102 100 100     673 if ($x -> is_negative() && !$y -> is_int()) {
1491 20 50       42 return $upgrade -> bpow($upgrade -> new($x), $y, @r)
1492             if defined $upgrade;
1493 20         56 return $x -> bnan();
1494             }
1495              
1496 82 100 100     1807 if ($x -> is_one("+") || $y -> is_one()) {
1497 20         484 return $x;
1498             }
1499              
1500 62 100       109 if ($x -> is_one("-")) {
1501 6 100       63 return $x if $y -> is_odd();
1502 3         12 return $x -> bneg();
1503             }
1504              
1505             # (a/b)^-(c/d) = (b/a)^(c/d)
1506 56 100       188 ($x->{_n}, $x->{_d}) = ($x->{_d}, $x->{_n}) if $y->is_negative();
1507              
1508 56 100       1233 unless ($LIB->_is_one($y->{_n})) {
1509 47         300 $x->{_n} = $LIB->_pow($x->{_n}, $y->{_n});
1510 47         2617 $x->{_d} = $LIB->_pow($x->{_d}, $y->{_n});
1511 47 100 100     1809 $x->{sign} = '+' if $x->{sign} eq '-' && $LIB->_is_even($y->{_n});
1512             }
1513              
1514 56 100       253 unless ($LIB->_is_one($y->{_d})) {
1515 2 100       14 return $x->bsqrt(@r) if $LIB->_is_two($y->{_d}); # 1/2 => sqrt
1516 1         9 return $x->broot($LIB->_str($y->{_d}), @r); # 1/N => root(N)
1517             }
1518              
1519 54         315 return $x->round(@r);
1520             }
1521              
1522             sub blog {
1523             # Return the logarithm of the operand. If a second operand is defined, that
1524             # value is used as the base, otherwise the base is assumed to be Euler's
1525             # constant.
1526              
1527 20     20 1 63 my ($class, $x, $base, @r);
1528              
1529             # Don't objectify the base, since an undefined base, as in $x->blog() or
1530             # $x->blog(undef) signals that the base is Euler's number.
1531              
1532 20 50 33     58 if (!ref($_[0]) && $_[0] =~ /^[A-Za-z]|::/) {
1533             # E.g., Math::BigRat->blog(256, 2)
1534 0 0       0 ($class, $x, $base, @r) =
1535             defined $_[2] ? objectify(2, @_) : objectify(1, @_);
1536             } else {
1537             # E.g., Math::BigRat::blog(256, 2) or $x->blog(2)
1538 20 100       53 ($class, $x, $base, @r) =
1539             defined $_[1] ? objectify(2, @_) : objectify(1, @_);
1540             }
1541              
1542 20 50       135 return $x if $x->modify('blog');
1543              
1544             # Handle all exception cases and all trivial cases. I have used Wolfram Alpha
1545             # (http://www.wolframalpha.com) as the reference for these cases.
1546              
1547 20 100       45 return $x -> bnan() if $x -> is_nan();
1548              
1549 15 100       82 if (defined $base) {
1550 7 50       14 $base = $class -> new($base) unless ref $base;
1551 7 100 66     12 if ($base -> is_nan() || $base -> is_one()) {
    50 33        
    100          
1552 2         11 return $x -> bnan();
1553             } elsif ($base -> is_inf() || $base -> is_zero()) {
1554 0 0 0     0 return $x -> bnan() if $x -> is_inf() || $x -> is_zero();
1555 0         0 return $x -> bzero();
1556             } elsif ($base -> is_negative()) { # -inf < base < 0
1557 2 50       46 return $x -> bzero() if $x -> is_one(); # x = 1
1558 2 50       4 return $x -> bone() if $x == $base; # x = base
1559 2         5 return $x -> bnan(); # otherwise
1560             }
1561 3 50       103 return $x -> bone() if $x == $base; # 0 < base && 0 < x < inf
1562             }
1563              
1564             # We now know that the base is either undefined or positive and finite.
1565              
1566 11 100       22 if ($x -> is_inf()) { # x = +/-inf
    100          
    100          
    100          
1567 2 50 33     20 my $sign = defined $base && $base < 1 ? '-' : '+';
1568 2         5 return $x -> binf($sign);
1569             } elsif ($x -> is_neg()) { # -inf < x < 0
1570 2         75 return $x -> bnan();
1571             } elsif ($x -> is_one()) { # x = 1
1572 1         15 return $x -> bzero();
1573             } elsif ($x -> is_zero()) { # x = 0
1574 3 50 66     24 my $sign = defined $base && $base < 1 ? '+' : '-';
1575 3         11 return $x -> binf($sign);
1576             }
1577              
1578             # Now take care of the cases where $x and/or $base is 1/N.
1579             #
1580             # log(1/N) / log(B) = -log(N)/log(B)
1581             # log(1/N) / log(1/B) = log(N)/log(B)
1582             # log(N) / log(1/B) = -log(N)/log(B)
1583              
1584 3         8 my $neg = 0;
1585 3 50       11 if ($x -> numerator() -> is_one()) {
1586 0         0 $x -> binv();
1587 0         0 $neg = !$neg;
1588             }
1589 3 100 66     54 if (defined(blessed($base)) && $base -> isa($class)) {
1590 2 50       4 if ($base -> numerator() -> is_one()) {
1591 0         0 $base = $base -> copy() -> binv();
1592 0         0 $neg = !$neg;
1593             }
1594             }
1595              
1596             # At this point we are done handling all exception cases and trivial cases.
1597              
1598 3 100       31 $base = Math::BigFloat -> new($base) if defined $base;
1599              
1600 3         81 my $xn = Math::BigFloat -> new($LIB -> _str($x->{_n}));
1601 3         184 my $xd = Math::BigFloat -> new($LIB -> _str($x->{_d}));
1602              
1603 3         367 my $xtmp = Math::BigRat -> new($xn -> bdiv($xd) -> blog($base, @r) -> bsstr());
1604              
1605 3         12 $x -> {sign} = $xtmp -> {sign};
1606 3         8 $x -> {_n} = $xtmp -> {_n};
1607 3         9 $x -> {_d} = $xtmp -> {_d};
1608              
1609 3 50       97 return $neg ? $x -> bneg() : $x;
1610             }
1611              
1612             sub bexp {
1613             # set up parameters
1614 1     1 1 4 my ($class, $x, $y, @r) = (ref($_[0]), @_);
1615              
1616             # objectify is costly, so avoid it
1617 1 50 33     6 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1618 1         7 ($class, $x, $y, @r) = objectify(1, @_);
1619             }
1620              
1621 1 50       8 return $x->binf(@r) if $x->{sign} eq '+inf';
1622 1 50       3 return $x->bzero(@r) if $x->{sign} eq '-inf';
1623              
1624             # we need to limit the accuracy to protect against overflow
1625 1         2 my $fallback = 0;
1626 1         1 my ($scale, @params);
1627 1         7 ($x, @params) = $x->_find_round_parameters(@r);
1628              
1629             # also takes care of the "error in _find_round_parameters?" case
1630 1 50       30 return $x if $x->{sign} eq 'NaN';
1631              
1632             # no rounding at all, so must use fallback
1633 1 50       2 if (scalar @params == 0) {
1634             # simulate old behaviour
1635 1         5 $params[0] = $class->div_scale(); # and round to it as accuracy
1636 1         12 $params[1] = undef; # P = undef
1637 1         2 $scale = $params[0]+4; # at least four more for proper round
1638 1         1 $params[2] = $r[2]; # round mode by caller or undef
1639 1         1 $fallback = 1; # to clear a/p afterwards
1640             } else {
1641             # the 4 below is empirical, and there might be cases where it's not enough...
1642 0   0     0 $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
1643             }
1644              
1645 1 50       13 return $x->bone(@params) if $x->is_zero();
1646              
1647             # See the comments in Math::BigFloat on how this algorithm works.
1648             # Basically we calculate A and B (where B is faculty(N)) so that A/B = e
1649              
1650 1         4 my $x_org = $x->copy();
1651 1 50       3 if ($scale <= 75) {
1652             # set $x directly from a cached string form
1653             $x->{_n} =
1654 1         3 $LIB->_new("90933395208605785401971970164779391644753259799242");
1655             $x->{_d} =
1656 1         36 $LIB->_new("33452526613163807108170062053440751665152000000000");
1657 1         18 $x->{sign} = '+';
1658             } else {
1659             # compute A and B so that e = A / B.
1660              
1661             # After some terms we end up with this, so we use it as a starting point:
1662 0         0 my $A = $LIB->_new("90933395208605785401971970164779391644753259799242");
1663 0         0 my $F = $LIB->_new(42); my $step = 42;
  0         0  
1664              
1665             # Compute how many steps we need to take to get $A and $B sufficiently big
1666 0         0 my $steps = Math::BigFloat::_len_to_steps($scale - 4);
1667             # print STDERR "# Doing $steps steps for ", $scale-4, " digits\n";
1668 0         0 while ($step++ <= $steps) {
1669             # calculate $a * $f + 1
1670 0         0 $A = $LIB->_mul($A, $F);
1671 0         0 $A = $LIB->_inc($A);
1672             # increment f
1673 0         0 $F = $LIB->_inc($F);
1674             }
1675             # compute $B as factorial of $steps (this is faster than doing it manually)
1676 0         0 my $B = $LIB->_fac($LIB->_new($steps));
1677              
1678             # print "A ", $LIB->_str($A), "\nB ", $LIB->_str($B), "\n";
1679              
1680 0         0 $x->{_n} = $A;
1681 0         0 $x->{_d} = $B;
1682 0         0 $x->{sign} = '+';
1683             }
1684              
1685             # $x contains now an estimate of e, with some surplus digits, so we can round
1686 1 50       3 if (!$x_org->is_one()) {
1687             # raise $x to the wanted power and round it in one step:
1688 1         4 $x->bpow($x_org, @params);
1689             } else {
1690             # else just round the already computed result
1691 0         0 delete $x->{_a}; delete $x->{_p};
  0         0  
1692             # shortcut to not run through _find_round_parameters again
1693 0 0       0 if (defined $params[0]) {
1694 0         0 $x->bround($params[0], $params[2]); # then round accordingly
1695             } else {
1696 0         0 $x->bfround($params[1], $params[2]); # then round accordingly
1697             }
1698             }
1699 1 50       3 if ($fallback) {
1700             # clear a/p after round, since user did not request it
1701 1         2 delete $x->{_a}; delete $x->{_p};
  1         2  
1702             }
1703              
1704 1         4 $x;
1705             }
1706              
1707             sub bnok {
1708             # set up parameters
1709 4956     4956 1 34483 my ($class, $x, $y, @r) = (ref($_[0]), @_);
1710              
1711             # objectify is costly, so avoid it
1712 4956 100 66     25156 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1713 2478         6595 ($class, $x, $y, @r) = objectify(2, @_);
1714             }
1715              
1716 4956 100 100     27606 return $x->bnan() if $x->is_nan() || $y->is_nan();
1717 4932 50 66     53273 return $x->bnan() if (($x->is_finite() && !$x->is_int()) ||
      66        
      33        
1718             ($y->is_finite() && !$y->is_int()));
1719              
1720 4932         40637 my $xint = Math::BigInt -> new($x -> bstr());
1721 4932         288939 my $yint = Math::BigInt -> new($y -> bstr());
1722 4932         264893 $xint -> bnok($yint);
1723 4932         2666502 my $xrat = Math::BigRat -> new($xint);
1724              
1725 4932         10394 $x -> {sign} = $xrat -> {sign};
1726 4932         9981 $x -> {_n} = $xrat -> {_n};
1727 4932         7519 $x -> {_d} = $xrat -> {_d};
1728              
1729 4932         65388 return $x;
1730             }
1731              
1732             sub broot {
1733             # set up parameters
1734 7     7 1 53 my ($class, $x, $y, @r) = (ref($_[0]), @_);
1735             # objectify is costly, so avoid it
1736 7 100 66     31 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1737 5         13 ($class, $x, $y, @r) = objectify(2, @_);
1738             }
1739              
1740             # Convert $x into a Math::BigFloat.
1741              
1742 7         63 my $xd = Math::BigFloat -> new($LIB -> _str($x->{_d}));
1743 7         419 my $xflt = Math::BigFloat -> new($LIB -> _str($x->{_n})) -> bdiv($xd);
1744 7         2773 $xflt -> {sign} = $x -> {sign};
1745              
1746             # Convert $y into a Math::BigFloat.
1747              
1748 7         19 my $yd = Math::BigFloat -> new($LIB -> _str($y->{_d}));
1749 7         409 my $yflt = Math::BigFloat -> new($LIB -> _str($y->{_n})) -> bdiv($yd);
1750 7         1365 $yflt -> {sign} = $y -> {sign};
1751              
1752             # Compute the root and convert back to a Math::BigRat.
1753              
1754 7         24 $xflt -> broot($yflt, @r);
1755 7         244579 my $xtmp = Math::BigRat -> new($xflt -> bsstr());
1756              
1757 7         18 $x -> {sign} = $xtmp -> {sign};
1758 7         13 $x -> {_n} = $xtmp -> {_n};
1759 7         15 $x -> {_d} = $xtmp -> {_d};
1760              
1761 7         60 return $x;
1762             }
1763              
1764             sub bmodpow {
1765             # set up parameters
1766 19     19 1 100 my ($class, $x, $y, $m, @r) = (ref($_[0]), @_);
1767             # objectify is costly, so avoid it
1768 19 50 33     76 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1769 0         0 ($class, $x, $y, $m, @r) = objectify(3, @_);
1770             }
1771              
1772             # Convert $x, $y, and $m into Math::BigInt objects.
1773              
1774 19         40 my $xint = Math::BigInt -> new($x -> copy() -> bint());
1775 19         992 my $yint = Math::BigInt -> new($y -> copy() -> bint());
1776 19         928 my $mint = Math::BigInt -> new($m -> copy() -> bint());
1777              
1778 19         840 $xint -> bmodpow($yint, $mint, @r);
1779 19         57474 my $xtmp = Math::BigRat -> new($xint -> bsstr());
1780              
1781 19         74 $x -> {sign} = $xtmp -> {sign};
1782 19         29 $x -> {_n} = $xtmp -> {_n};
1783 19         28 $x -> {_d} = $xtmp -> {_d};
1784 19         331 return $x;
1785             }
1786              
1787             sub bmodinv {
1788             # set up parameters
1789 17     17 1 138 my ($class, $x, $y, @r) = (ref($_[0]), @_);
1790             # objectify is costly, so avoid it
1791 17 50 33     675 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1792 0         0 ($class, $x, $y, @r) = objectify(2, @_);
1793             }
1794              
1795             # Convert $x and $y into Math::BigInt objects.
1796              
1797 17         58 my $xint = Math::BigInt -> new($x -> copy() -> bint());
1798 17         946 my $yint = Math::BigInt -> new($y -> copy() -> bint());
1799              
1800 17         845 $xint -> bmodinv($yint, @r);
1801 17         5094 my $xtmp = Math::BigRat -> new($xint -> bsstr());
1802              
1803 17         56 $x -> {sign} = $xtmp -> {sign};
1804 17         37 $x -> {_n} = $xtmp -> {_n};
1805 17         37 $x -> {_d} = $xtmp -> {_d};
1806 17         416 return $x;
1807             }
1808              
1809             sub bsqrt {
1810 20 50   20 1 102 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1811              
1812 20 100       62 return $x->bnan() if $x->{sign} !~ /^[+]/; # NaN, -inf or < 0
1813 16 100       50 return $x if $x->{sign} eq '+inf'; # sqrt(inf) == inf
1814 15 100 100     29 return $x->round(@r) if $x->is_zero() || $x->is_one();
1815              
1816 13         18 my $n = $x -> {_n};
1817 13         18 my $d = $x -> {_d};
1818              
1819             # Look for an exact solution. For the numerator and the denominator, take
1820             # the square root and square it and see if we got the original value. If we
1821             # did, for both the numerator and the denominator, we have an exact
1822             # solution.
1823              
1824             {
1825 13         14 my $nsqrt = $LIB -> _sqrt($LIB -> _copy($n));
  13         48  
1826 13         995 my $n2 = $LIB -> _mul($LIB -> _copy($nsqrt), $nsqrt);
1827 13 100       218 if ($LIB -> _acmp($n, $n2) == 0) {
1828 11         79 my $dsqrt = $LIB -> _sqrt($LIB -> _copy($d));
1829 11         125 my $d2 = $LIB -> _mul($LIB -> _copy($dsqrt), $dsqrt);
1830 11 100       119 if ($LIB -> _acmp($d, $d2) == 0) {
1831 10         52 $x -> {_n} = $nsqrt;
1832 10         10 $x -> {_d} = $dsqrt;
1833 10         32 return $x->round(@r);
1834             }
1835             }
1836             }
1837              
1838 3         35 local $Math::BigFloat::upgrade = undef;
1839 3         5 local $Math::BigFloat::downgrade = undef;
1840 3         5 local $Math::BigFloat::precision = undef;
1841 3         4 local $Math::BigFloat::accuracy = undef;
1842 3         18 local $Math::BigInt::upgrade = undef;
1843 3         5 local $Math::BigInt::precision = undef;
1844 3         5 local $Math::BigInt::accuracy = undef;
1845              
1846 3         10 my $xn = Math::BigFloat -> new($LIB -> _str($n));
1847 3         228 my $xd = Math::BigFloat -> new($LIB -> _str($d));
1848              
1849 3         293 my $xtmp = Math::BigRat -> new($xn -> bdiv($xd) -> bsqrt() -> bsstr());
1850              
1851 3         10 $x -> {sign} = $xtmp -> {sign};
1852 3         7 $x -> {_n} = $xtmp -> {_n};
1853 3         7 $x -> {_d} = $xtmp -> {_d};
1854              
1855 3         12 $x->round(@r);
1856             }
1857              
1858             sub blsft {
1859 0     0 1 0 my ($class, $x, $y, $b) = objectify(2, @_);
1860              
1861 0 0       0 $b = 2 if !defined $b;
1862 0 0 0     0 $b = $class -> new($b) unless ref($b) && $b -> isa($class);
1863              
1864 0 0 0     0 return $x -> bnan() if $x -> is_nan() || $y -> is_nan() || $b -> is_nan();
      0        
1865              
1866             # shift by a negative amount?
1867 0 0       0 return $x -> brsft($y -> copy() -> babs(), $b) if $y -> {sign} =~ /^-/;
1868              
1869 0         0 $x -> bmul($b -> bpow($y));
1870             }
1871              
1872             sub brsft {
1873 0     0 1 0 my ($class, $x, $y, $b) = objectify(2, @_);
1874              
1875 0 0       0 $b = 2 if !defined $b;
1876 0 0 0     0 $b = $class -> new($b) unless ref($b) && $b -> isa($class);
1877              
1878 0 0 0     0 return $x -> bnan() if $x -> is_nan() || $y -> is_nan() || $b -> is_nan();
      0        
1879              
1880             # shift by a negative amount?
1881 0 0       0 return $x -> blsft($y -> copy() -> babs(), $b) if $y -> {sign} =~ /^-/;
1882              
1883             # the following call to bdiv() will return either quotient (scalar context)
1884             # or quotient and remainder (list context).
1885 0         0 $x -> bdiv($b -> bpow($y));
1886             }
1887              
1888             sub band {
1889 289     289 1 325 my $x = shift;
1890 289         363 my $xref = ref($x);
1891 289   33     525 my $class = $xref || $x;
1892              
1893 289 50       456 croak 'band() is an instance method, not a class method' unless $xref;
1894 289 50       493 croak 'Not enough arguments for band()' if @_ < 1;
1895              
1896 289         283 my $y = shift;
1897 289 50       420 $y = $class -> new($y) unless ref($y);
1898              
1899 289         484 my @r = @_;
1900              
1901 289         790 my $xtmp = Math::BigInt -> new($x -> bint()); # to Math::BigInt
1902 289         13785 $xtmp -> band($y);
1903 289         28807 $xtmp = $class -> new($xtmp); # back to Math::BigRat
1904              
1905 289         522 $x -> {sign} = $xtmp -> {sign};
1906 289         440 $x -> {_n} = $xtmp -> {_n};
1907 289         375 $x -> {_d} = $xtmp -> {_d};
1908              
1909 289         591 return $x -> round(@r);
1910             }
1911              
1912             sub bior {
1913 289     289 1 362 my $x = shift;
1914 289         360 my $xref = ref($x);
1915 289   33     753 my $class = $xref || $x;
1916              
1917 289 50       419 croak 'bior() is an instance method, not a class method' unless $xref;
1918 289 50       541 croak 'Not enough arguments for bior()' if @_ < 1;
1919              
1920 289         283 my $y = shift;
1921 289 50       477 $y = $class -> new($y) unless ref($y);
1922              
1923 289         400 my @r = @_;
1924              
1925 289         609 my $xtmp = Math::BigInt -> new($x -> bint()); # to Math::BigInt
1926 289         14841 $xtmp -> bior($y);
1927 289         32683 $xtmp = $class -> new($xtmp); # back to Math::BigRat
1928              
1929 289         699 $x -> {sign} = $xtmp -> {sign};
1930 289         431 $x -> {_n} = $xtmp -> {_n};
1931 289         386 $x -> {_d} = $xtmp -> {_d};
1932              
1933 289         521 return $x -> round(@r);
1934             }
1935              
1936             sub bxor {
1937 289     289 1 440 my $x = shift;
1938 289         557 my $xref = ref($x);
1939 289   33     572 my $class = $xref || $x;
1940              
1941 289 50       823 croak 'bxor() is an instance method, not a class method' unless $xref;
1942 289 50       704 croak 'Not enough arguments for bxor()' if @_ < 1;
1943              
1944 289         348 my $y = shift;
1945 289 50       734 $y = $class -> new($y) unless ref($y);
1946              
1947 289         493 my @r = @_;
1948              
1949 289         1039 my $xtmp = Math::BigInt -> new($x -> bint()); # to Math::BigInt
1950 289         14518 $xtmp -> bxor($y);
1951 289         33455 $xtmp = $class -> new($xtmp); # back to Math::BigRat
1952              
1953 289         698 $x -> {sign} = $xtmp -> {sign};
1954 289         492 $x -> {_n} = $xtmp -> {_n};
1955 289         529 $x -> {_d} = $xtmp -> {_d};
1956              
1957 289         735 return $x -> round(@r);
1958             }
1959              
1960             sub bnot {
1961 0     0 1 0 my $x = shift;
1962 0         0 my $xref = ref($x);
1963 0   0     0 my $class = $xref || $x;
1964              
1965 0 0       0 croak 'bnot() is an instance method, not a class method' unless $xref;
1966              
1967 0         0 my @r = @_;
1968              
1969 0         0 my $xtmp = Math::BigInt -> new($x -> bint()); # to Math::BigInt
1970 0         0 $xtmp -> bnot();
1971 0         0 $xtmp = $class -> new($xtmp); # back to Math::BigRat
1972              
1973 0         0 $x -> {sign} = $xtmp -> {sign};
1974 0         0 $x -> {_n} = $xtmp -> {_n};
1975 0         0 $x -> {_d} = $xtmp -> {_d};
1976              
1977 0         0 return $x -> round(@r);
1978             }
1979              
1980             ##############################################################################
1981             # round
1982              
1983             sub round {
1984 1237     1237 1 1580 my $x = shift;
1985 1237 0 33     2138 return $downgrade -> new($x) if defined($downgrade) &&
      66        
1986             ($x -> is_int() || $x -> is_inf() || $x -> is_nan());
1987 1235         10039 $x;
1988             }
1989              
1990             sub bround {
1991 4     4 1 6 my $x = shift;
1992 4 50 66     17 return $downgrade -> new($x) if defined($downgrade) &&
      33        
1993             ($x -> is_int() || $x -> is_inf() || $x -> is_nan());
1994 0         0 $x;
1995             }
1996              
1997             sub bfround {
1998 4     4 1 5 my $x = shift;
1999 4 50 66     25 return $downgrade -> new($x) if defined($downgrade) &&
      33        
2000             ($x -> is_int() || $x -> is_inf() || $x -> is_nan());
2001 0         0 $x;
2002             }
2003              
2004             ##############################################################################
2005             # comparing
2006              
2007             sub bcmp {
2008             # compare two signed numbers
2009              
2010             # set up parameters
2011 54     54 1 136 my ($class, $x, $y) = (ref($_[0]), @_);
2012              
2013             # objectify is costly, so avoid it
2014 54 100 66     196 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
2015 36         74 ($class, $x, $y) = objectify(2, @_);
2016             }
2017              
2018 54 50 33     531 if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/) {
2019             # $x is NaN and/or $y is NaN
2020 0 0 0     0 return if $x->{sign} eq $nan || $y->{sign} eq $nan;
2021             # $x and $y are both either +inf or -inf
2022 0 0 0     0 return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
2023             # $x = +inf and $y < +inf
2024 0 0       0 return +1 if $x->{sign} eq '+inf';
2025             # $x = -inf and $y > -inf
2026 0 0       0 return -1 if $x->{sign} eq '-inf';
2027             # $x < +inf and $y = +inf
2028 0 0       0 return -1 if $y->{sign} eq '+inf';
2029             # $x > -inf and $y = -inf
2030 0         0 return +1;
2031             }
2032              
2033             # $x >= 0 and $y < 0
2034 54 100 100     184 return 1 if $x->{sign} eq '+' && $y->{sign} eq '-';
2035             # $x < 0 and $y >= 0
2036 40 100 100     135 return -1 if $x->{sign} eq '-' && $y->{sign} eq '+';
2037              
2038             # At this point, we know that $x and $y have the same sign.
2039              
2040             # shortcut
2041 35         87 my $xz = $LIB->_is_zero($x->{_n});
2042 35         159 my $yz = $LIB->_is_zero($y->{_n});
2043 35 50 66     173 return 0 if $xz && $yz; # 0 <=> 0
2044 35 100 66     99 return -1 if $xz && $y->{sign} eq '+'; # 0 <=> +y
2045 32 50 33     69 return 1 if $yz && $x->{sign} eq '+'; # +x <=> 0
2046              
2047 32         100 my $t = $LIB->_mul($LIB->_copy($x->{_n}), $y->{_d});
2048 32         476 my $u = $LIB->_mul($LIB->_copy($y->{_n}), $x->{_d});
2049              
2050 32         313 my $cmp = $LIB->_acmp($t, $u); # signs are equal
2051 32 100       157 $cmp = -$cmp if $x->{sign} eq '-'; # both are '-' => reverse
2052 32         83 $cmp;
2053             }
2054              
2055             sub bacmp {
2056             # compare two numbers (as unsigned)
2057              
2058             # set up parameters
2059 50     50 1 278 my ($class, $x, $y) = (ref($_[0]), @_);
2060             # objectify is costly, so avoid it
2061 50 50 33     220 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
2062 0         0 ($class, $x, $y) = objectify(2, @_);
2063             }
2064              
2065 50 100 100     202 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/)) {
2066             # handle +-inf and NaN
2067 35 100 100     168 return if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
2068 28 100 100     398 return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
2069 24 100 66     193 return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/;
2070 12         121 return -1;
2071             }
2072              
2073 15         43 my $t = $LIB->_mul($LIB->_copy($x->{_n}), $y->{_d});
2074 15         222 my $u = $LIB->_mul($LIB->_copy($y->{_n}), $x->{_d});
2075 15         146 $LIB->_acmp($t, $u); # ignore signs
2076             }
2077              
2078             sub beq {
2079 10     10 1 19 my $self = shift;
2080 10         15 my $selfref = ref $self;
2081             #my $class = $selfref || $self;
2082              
2083 10 50       19 croak 'beq() is an instance method, not a class method' unless $selfref;
2084 10 50       28 croak 'Wrong number of arguments for beq()' unless @_ == 1;
2085              
2086 10         21 my $cmp = $self -> bcmp(shift);
2087 10   66     62 return defined($cmp) && ! $cmp;
2088             }
2089              
2090             sub bne {
2091 0     0 1 0 my $self = shift;
2092 0         0 my $selfref = ref $self;
2093             #my $class = $selfref || $self;
2094              
2095 0 0       0 croak 'bne() is an instance method, not a class method' unless $selfref;
2096 0 0       0 croak 'Wrong number of arguments for bne()' unless @_ == 1;
2097              
2098 0         0 my $cmp = $self -> bcmp(shift);
2099 0 0 0     0 return defined($cmp) && ! $cmp ? '' : 1;
2100             }
2101              
2102             sub blt {
2103 19     19 1 29 my $self = shift;
2104 19         31 my $selfref = ref $self;
2105             #my $class = $selfref || $self;
2106              
2107 19 50       37 croak 'blt() is an instance method, not a class method' unless $selfref;
2108 19 50       35 croak 'Wrong number of arguments for blt()' unless @_ == 1;
2109              
2110 19         31 my $cmp = $self -> bcmp(shift);
2111 19   66     118 return defined($cmp) && $cmp < 0;
2112             }
2113              
2114             sub ble {
2115 0     0 1 0 my $self = shift;
2116 0         0 my $selfref = ref $self;
2117             #my $class = $selfref || $self;
2118              
2119 0 0       0 croak 'ble() is an instance method, not a class method' unless $selfref;
2120 0 0       0 croak 'Wrong number of arguments for ble()' unless @_ == 1;
2121              
2122 0         0 my $cmp = $self -> bcmp(shift);
2123 0   0     0 return defined($cmp) && $cmp <= 0;
2124             }
2125              
2126             sub bgt {
2127 24     24 1 33 my $self = shift;
2128 24         38 my $selfref = ref $self;
2129             #my $class = $selfref || $self;
2130              
2131 24 50       42 croak 'bgt() is an instance method, not a class method' unless $selfref;
2132 24 50       57 croak 'Wrong number of arguments for bgt()' unless @_ == 1;
2133              
2134 24         58 my $cmp = $self -> bcmp(shift);
2135 24   66     147 return defined($cmp) && $cmp > 0;
2136             }
2137              
2138             sub bge {
2139 0     0 1 0 my $self = shift;
2140 0         0 my $selfref = ref $self;
2141             #my $class = $selfref || $self;
2142              
2143 0 0       0 croak 'bge() is an instance method, not a class method'
2144             unless $selfref;
2145 0 0       0 croak 'Wrong number of arguments for bge()' unless @_ == 1;
2146              
2147 0         0 my $cmp = $self -> bcmp(shift);
2148 0   0     0 return defined($cmp) && $cmp >= 0;
2149             }
2150              
2151             ##############################################################################
2152             # output conversion
2153              
2154             sub numify {
2155             # convert 17/8 => float (aka 2.125)
2156 20 50   20 1 73 my ($self, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
2157              
2158             # Non-finite number.
2159              
2160 20 100       43 if ($x -> is_nan()) {
2161 1         8 require Math::Complex;
2162 1         2 my $inf = $Math::Complex::Inf;
2163 1         4 return $inf - $inf;
2164             }
2165              
2166 19 100       106 if ($x -> is_inf()) {
2167 2         21 require Math::Complex;
2168 2         4 my $inf = $Math::Complex::Inf;
2169 2 100       13 return $x -> is_negative() ? -$inf : $inf;
2170             }
2171              
2172             # Finite number.
2173              
2174             my $abs = $LIB->_is_one($x->{_d})
2175             ? $LIB->_num($x->{_n})
2176             : Math::BigFloat -> new($LIB->_str($x->{_n}))
2177 17 100       121 -> bdiv($LIB->_str($x->{_d}))
2178             -> bstr();
2179 17 100       6070 return $x->{sign} eq '-' ? 0 - $abs : 0 + $abs;
2180             }
2181              
2182             sub as_int {
2183 883 50   883 1 21301 my ($self, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
2184              
2185             # NaN, inf etc
2186 883 100       2881 return Math::BigInt->new($x->{sign}) if $x->{sign} !~ /^[+-]$/;
2187              
2188 877         2576 my $u = Math::BigInt->bzero();
2189 877         32721 $u->{value} = $LIB->_div($LIB->_copy($x->{_n}), $x->{_d}); # 22/7 => 3
2190 877 100       11787 $u->bneg if $x->{sign} eq '-'; # no negative zero
2191 877         2156 $u;
2192             }
2193              
2194             sub as_float {
2195             # return N/D as Math::BigFloat
2196              
2197             # set up parameters
2198 3     3 1 15 my ($class, $x, @r) = (ref($_[0]), @_);
2199             # objectify is costly, so avoid it
2200 3 50       7 ($class, $x, @r) = objectify(1, @_) unless ref $_[0];
2201              
2202             # NaN, inf etc
2203 3 50       8 return Math::BigFloat->new($x->{sign}) if $x->{sign} !~ /^[+-]$/;
2204              
2205 3         7 my $xflt = Math::BigFloat -> new($LIB -> _str($x->{_n}));
2206 3         192 $xflt -> {sign} = $x -> {sign};
2207              
2208 3 100       7 unless ($LIB -> _is_one($x->{_d})) {
2209 2         12 my $xd = Math::BigFloat -> new($LIB -> _str($x->{_d}));
2210 2         103 $xflt -> bdiv($xd, @r);
2211             }
2212              
2213 3         1256 return $xflt;
2214             }
2215              
2216             sub as_bin {
2217 2 50   2 1 904 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
2218              
2219 2 50       5 return $x unless $x->is_int();
2220              
2221 2         15 my $s = $x->{sign};
2222 2 50       7 $s = '' if $s eq '+';
2223 2         7 $s . $LIB->_as_bin($x->{_n});
2224             }
2225              
2226             sub as_hex {
2227 2 50   2 1 14 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
2228              
2229 2 50       6 return $x unless $x->is_int();
2230              
2231 2 50       13 my $s = $x->{sign}; $s = '' if $s eq '+';
  2         6  
2232 2         6 $s . $LIB->_as_hex($x->{_n});
2233             }
2234              
2235             sub as_oct {
2236 2 50   2 1 823 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
2237              
2238 2 50       5 return $x unless $x->is_int();
2239              
2240 2 50       15 my $s = $x->{sign}; $s = '' if $s eq '+';
  2         5  
2241 2         7 $s . $LIB->_as_oct($x->{_n});
2242             }
2243              
2244             ##############################################################################
2245              
2246             sub from_hex {
2247 3     3 1 1037 my $class = shift;
2248              
2249             # The relationship should probably go the otherway, i.e, that new() calls
2250             # from_hex(). Fixme!
2251 3         6 my ($x, @r) = @_;
2252 3         15 $x =~ s|^\s*(?:0?[Xx]_*)?|0x|;
2253 3         9 $class->new($x, @r);
2254             }
2255              
2256             sub from_bin {
2257 3     3 1 1367 my $class = shift;
2258              
2259             # The relationship should probably go the otherway, i.e, that new() calls
2260             # from_bin(). Fixme!
2261 3         9 my ($x, @r) = @_;
2262 3         15 $x =~ s|^\s*(?:0?[Bb]_*)?|0b|;
2263 3         10 $class->new($x, @r);
2264             }
2265              
2266             sub from_oct {
2267 5     5 1 1402 my $class = shift;
2268              
2269             # Why is this different from from_hex() and from_bin()? Fixme!
2270 5         9 my @parts;
2271 5         10 for my $c (@_) {
2272 5         21 push @parts, Math::BigInt->from_oct($c);
2273             }
2274 5         1766 $class->new (@parts);
2275             }
2276              
2277             ##############################################################################
2278             # import
2279              
2280             sub import {
2281 19     19   1040 my $class = shift;
2282 19         28 my @a; # unrecognized arguments
2283 19         32 my $lib_param = '';
2284 19         26 my $lib_value = '';
2285              
2286 19         74 while (@_) {
2287 4         9 my $param = shift;
2288              
2289             # Enable overloading of constants.
2290              
2291 4 100       26 if ($param eq ':constant') {
2292             overload::constant
2293              
2294             integer => sub {
2295 7     7   28 $class -> new(shift);
2296             },
2297              
2298             float => sub {
2299 7     7   21 $class -> new(shift);
2300             },
2301              
2302             binary => sub {
2303             # E.g., a literal 0377 shall result in an object whose value
2304             # is decimal 255, but new("0377") returns decimal 377.
2305 8 100   8   1573 return $class -> from_oct($_[0]) if $_[0] =~ /^0_*[0-7]/;
2306 6         19 $class -> new(shift);
2307 1         6 };
2308 1         42 next;
2309             }
2310              
2311             # Upgrading.
2312              
2313 3 50       9 if ($param eq 'upgrade') {
2314 0         0 $class -> upgrade(shift);
2315 0         0 next;
2316             }
2317              
2318             # Downgrading.
2319              
2320 3 100       8 if ($param eq 'downgrade') {
2321 1         7 $class -> downgrade(shift);
2322 1         13 next;
2323             }
2324              
2325             # Accuracy.
2326              
2327 2 50       4 if ($param eq 'accuracy') {
2328 0         0 $class -> accuracy(shift);
2329 0         0 next;
2330             }
2331              
2332             # Precision.
2333              
2334 2 50       5 if ($param eq 'precision') {
2335 0         0 $class -> precision(shift);
2336 0         0 next;
2337             }
2338              
2339             # Rounding mode.
2340              
2341 2 50       4 if ($param eq 'round_mode') {
2342 0         0 $class -> round_mode(shift);
2343 0         0 next;
2344             }
2345              
2346             # Backend library.
2347              
2348 2 50       12 if ($param =~ /^(lib|try|only)\z/) {
2349             # alternative library
2350 2         4 $lib_param = $param; # "lib", "try", or "only"
2351 2         4 $lib_value = shift;
2352 2         5 next;
2353             }
2354              
2355 0 0       0 if ($param eq 'with') {
2356             # alternative class for our private parts()
2357             # XXX: no longer supported
2358             # $LIB = shift() || 'Calc';
2359             # carp "'with' is no longer supported, use 'lib', 'try', or 'only'";
2360 0         0 shift;
2361 0         0 next;
2362             }
2363              
2364             # Unrecognized parameter.
2365              
2366 0         0 push @a, $param;
2367             }
2368              
2369 19         150 require Math::BigInt;
2370              
2371 19         36 my @import = ('objectify');
2372 19 100       81 push @import, $lib_param, $lib_value if $lib_param ne '';
2373 19         105 Math::BigInt -> import(@import);
2374              
2375             # find out which one was actually loaded
2376 19         287245 $LIB = Math::BigInt -> config("lib");
2377              
2378             # any non :constant stuff is handled by Exporter (loaded by parent class)
2379             # even if @_ is empty, to give it a chance
2380 19         1150 $class->SUPER::import(@a); # for subclasses
2381 19         17677 $class->export_to_level(1, $class, @a); # need this, too
2382             }
2383              
2384             1;
2385              
2386             __END__