Integrate version.pm-0.77 into bleadperl
[p5sagit/p5-mst-13.2.git] / lib / Math / BigRat.pm
1
2 #
3 # "Tax the rat farms." - Lord Vetinari
4 #
5
6 # The following hash values are used:
7 #   sign : +,-,NaN,+inf,-inf
8 #   _d   : denominator
9 #   _n   : numeraotr (value = _n/_d)
10 #   _a   : accuracy
11 #   _p   : precision
12 # You should not look at the innards of a BigRat - use the methods for this.
13
14 package Math::BigRat;
15
16 # anythig older is untested, and unlikely to work
17 use 5.006;
18 use strict;
19
20 use Math::BigFloat;
21 use vars qw($VERSION @ISA $upgrade $downgrade
22             $accuracy $precision $round_mode $div_scale $_trap_nan $_trap_inf);
23
24 @ISA = qw(Math::BigFloat);
25
26 $VERSION = '0.22';
27
28 use overload;                   # inherit overload from Math::BigFloat
29
30 BEGIN
31   { 
32   *objectify = \&Math::BigInt::objectify;       # inherit this from BigInt
33   *AUTOLOAD = \&Math::BigFloat::AUTOLOAD;       # can't inherit AUTOLOAD
34   # we inherit these from BigFloat because currently it is not possible
35   # that MBF has a different $MBI variable than we, because MBF also uses
36   # Math::BigInt::config->('lib'); (there is always only one library loaded)
37   *_e_add = \&Math::BigFloat::_e_add;
38   *_e_sub = \&Math::BigFloat::_e_sub;
39   *as_int = \&as_number;
40   *is_pos = \&is_positive;
41   *is_neg = \&is_negative;
42   }
43
44 ##############################################################################
45 # Global constants and flags. Access these only via the accessor methods!
46
47 $accuracy = $precision = undef;
48 $round_mode = 'even';
49 $div_scale = 40;
50 $upgrade = undef;
51 $downgrade = undef;
52
53 # These are internally, and not to be used from the outside at all!
54
55 $_trap_nan = 0;                         # are NaNs ok? set w/ config()
56 $_trap_inf = 0;                         # are infs ok? set w/ config()
57
58 # the package we are using for our private parts, defaults to:
59 # Math::BigInt->config()->{lib}
60 my $MBI = 'Math::BigInt::Calc';
61
62 my $nan = 'NaN';
63 my $class = 'Math::BigRat';
64
65 sub isa
66   {
67   return 0 if $_[1] =~ /^Math::Big(Int|Float)/;         # we aren't
68   UNIVERSAL::isa(@_);
69   }
70
71 ##############################################################################
72
73 sub _new_from_float
74   {
75   # turn a single float input into a rational number (like '0.1')
76   my ($self,$f) = @_;
77
78   return $self->bnan() if $f->is_nan();
79   return $self->binf($f->{sign}) if $f->{sign} =~ /^[+-]inf$/;
80
81   $self->{_n} = $MBI->_copy( $f->{_m} );        # mantissa
82   $self->{_d} = $MBI->_one();
83   $self->{sign} = $f->{sign} || '+';
84   if ($f->{_es} eq '-')
85     {
86     # something like Math::BigRat->new('0.1');
87     # 1 / 1 => 1/10
88     $MBI->_lsft ( $self->{_d}, $f->{_e} ,10);   
89     }
90   else
91     {
92     # something like Math::BigRat->new('10');
93     # 1 / 1 => 10/1
94     $MBI->_lsft ( $self->{_n}, $f->{_e} ,10) unless 
95       $MBI->_is_zero($f->{_e}); 
96     }
97   $self;
98   }
99
100 sub new
101   {
102   # create a Math::BigRat
103   my $class = shift;
104
105   my ($n,$d) = @_;
106
107   my $self = { }; bless $self,$class;
108  
109   # input like (BigInt) or (BigFloat):
110   if ((!defined $d) && (ref $n) && (!$n->isa('Math::BigRat')))
111     {
112     if ($n->isa('Math::BigFloat'))
113       {
114       $self->_new_from_float($n);
115       }
116     if ($n->isa('Math::BigInt'))
117       {
118       # TODO: trap NaN, inf
119       $self->{_n} = $MBI->_copy($n->{value});           # "mantissa" = N
120       $self->{_d} = $MBI->_one();                       # d => 1
121       $self->{sign} = $n->{sign};
122       }
123     if ($n->isa('Math::BigInt::Lite'))
124       {
125       # TODO: trap NaN, inf
126       $self->{sign} = '+'; $self->{sign} = '-' if $$n < 0;
127       $self->{_n} = $MBI->_new(abs($$n));               # "mantissa" = N
128       $self->{_d} = $MBI->_one();                       # d => 1
129       }
130     return $self->bnorm();                              # normalize (120/1 => 12/10)
131     }
132
133   # input like (BigInt,BigInt) or (BigLite,BigLite):
134   if (ref($d) && ref($n))
135     {
136     # do N first (for $self->{sign}):
137     if ($n->isa('Math::BigInt'))
138       {
139       # TODO: trap NaN, inf
140       $self->{_n} = $MBI->_copy($n->{value});           # "mantissa" = N
141       $self->{sign} = $n->{sign};
142       }
143     elsif ($n->isa('Math::BigInt::Lite'))
144       {
145       # TODO: trap NaN, inf
146       $self->{sign} = '+'; $self->{sign} = '-' if $$n < 0;
147       $self->{_n} = $MBI->_new(abs($$n));               # "mantissa" = $n
148       }
149     else
150       {
151       require Carp;
152       Carp::croak(ref($n) . " is not a recognized object format for Math::BigRat->new");
153       }
154     # now D:
155     if ($d->isa('Math::BigInt'))
156       {
157       # TODO: trap NaN, inf
158       $self->{_d} = $MBI->_copy($d->{value});           # "mantissa" = D
159       # +/+ or -/- => +, +/- or -/+ => -
160       $self->{sign} = $d->{sign} ne $self->{sign} ? '-' : '+';
161       }
162     elsif ($d->isa('Math::BigInt::Lite'))
163       {
164       # TODO: trap NaN, inf
165       $self->{_d} = $MBI->_new(abs($$d));               # "mantissa" = D
166       my $ds = '+'; $ds = '-' if $$d < 0;
167       # +/+ or -/- => +, +/- or -/+ => -
168       $self->{sign} = $ds ne $self->{sign} ? '-' : '+';
169       }
170     else
171       {
172       require Carp;
173       Carp::croak(ref($d) . " is not a recognized object format for Math::BigRat->new");
174       }
175     return $self->bnorm();                              # normalize (120/1 => 12/10)
176     }
177   return $n->copy() if ref $n;                          # already a BigRat
178
179   if (!defined $n)
180     {
181     $self->{_n} = $MBI->_zero();                        # undef => 0
182     $self->{_d} = $MBI->_one();
183     $self->{sign} = '+';
184     return $self;
185     }
186
187   # string input with / delimiter
188   if ($n =~ /\s*\/\s*/)
189     {
190     return $class->bnan() if $n =~ /\/.*\//;    # 1/2/3 isn't valid
191     return $class->bnan() if $n =~ /\/\s*$/;    # 1/ isn't valid
192     ($n,$d) = split (/\//,$n);
193     # try as BigFloats first
194     if (($n =~ /[\.eE]/) || ($d =~ /[\.eE]/))
195       {
196       local $Math::BigFloat::accuracy = undef;
197       local $Math::BigFloat::precision = undef;
198
199       # one of them looks like a float 
200       my $nf = Math::BigFloat->new($n,undef,undef);
201       $self->{sign} = '+';
202       return $self->bnan() if $nf->is_nan();
203
204       $self->{_n} = $MBI->_copy( $nf->{_m} );   # get mantissa
205
206       # now correct $self->{_n} due to $n
207       my $f = Math::BigFloat->new($d,undef,undef);
208       return $self->bnan() if $f->is_nan();
209       $self->{_d} = $MBI->_copy( $f->{_m} );
210
211       # calculate the difference between nE and dE
212       my $diff_e = $nf->exponent()->bsub( $f->exponent);
213       if ($diff_e->is_negative())
214         {
215         # < 0: mul d with it
216         $MBI->_lsft( $self->{_d}, $MBI->_new( $diff_e->babs()), 10);
217         }
218       elsif (!$diff_e->is_zero())
219         {
220         # > 0: mul n with it
221         $MBI->_lsft( $self->{_n}, $MBI->_new( $diff_e), 10);
222         }
223       }
224     else
225       {
226       # both d and n look like (big)ints
227
228       $self->{sign} = '+';                                      # no sign => '+'
229       $self->{_n} = undef;
230       $self->{_d} = undef;
231       if ($n =~ /^([+-]?)0*([0-9]+)\z/)                         # first part ok?
232         {
233         $self->{sign} = $1 || '+';                              # no sign => '+'
234         $self->{_n} = $MBI->_new($2 || 0);
235         }
236
237       if ($d =~ /^([+-]?)0*([0-9]+)\z/)                         # second part ok?
238         {
239         $self->{sign} =~ tr/+-/-+/ if ($1 || '') eq '-';        # negate if second part neg.
240         $self->{_d} = $MBI->_new($2 || 0);
241         }
242
243       if (!defined $self->{_n} || !defined $self->{_d})
244         {
245         $d = Math::BigInt->new($d,undef,undef) unless ref $d;
246         $n = Math::BigInt->new($n,undef,undef) unless ref $n;
247
248         if ($n->{sign} =~ /^[+-]$/ && $d->{sign} =~ /^[+-]$/)
249           { 
250           # both parts are ok as integers (wierd things like ' 1e0'
251           $self->{_n} = $MBI->_copy($n->{value});
252           $self->{_d} = $MBI->_copy($d->{value});
253           $self->{sign} = $n->{sign};
254           $self->{sign} =~ tr/+-/-+/ if $d->{sign} eq '-';      # -1/-2 => 1/2
255           return $self->bnorm();
256           }
257
258         $self->{sign} = '+';                                    # a default sign
259         return $self->bnan() if $n->is_nan() || $d->is_nan();
260
261         # handle inf cases:
262         if ($n->is_inf() || $d->is_inf())
263           {
264           if ($n->is_inf())
265             {
266             return $self->bnan() if $d->is_inf();               # both are inf => NaN
267             my $s = '+';                # '+inf/+123' or '-inf/-123'
268             $s = '-' if substr($n->{sign},0,1) ne $d->{sign};
269             # +-inf/123 => +-inf
270             return $self->binf($s);
271             }
272           # 123/inf => 0
273           return $self->bzero();
274           }
275         }
276       }
277
278     return $self->bnorm();
279     }
280
281   # simple string input
282   if (($n =~ /[\.eE]/))
283     {
284     # looks like a float, quacks like a float, so probably is a float
285     $self->{sign} = 'NaN';
286     local $Math::BigFloat::accuracy = undef;
287     local $Math::BigFloat::precision = undef;
288     $self->_new_from_float(Math::BigFloat->new($n,undef,undef));
289     }
290   else
291     {
292     # for simple forms, use $MBI directly
293     if ($n =~ /^([+-]?)0*([0-9]+)\z/)
294       {
295       $self->{sign} = $1 || '+';
296       $self->{_n} = $MBI->_new($2 || 0);
297       $self->{_d} = $MBI->_one();
298       }
299     else
300       {
301       my $n = Math::BigInt->new($n,undef,undef);
302       $self->{_n} = $MBI->_copy($n->{value});
303       $self->{_d} = $MBI->_one();
304       $self->{sign} = $n->{sign};
305       return $self->bnan() if $self->{sign} eq 'NaN';
306       return $self->binf($self->{sign}) if $self->{sign} =~ /^[+-]inf$/;
307       }
308     }
309   $self->bnorm();
310   }
311
312 sub copy
313   {
314   # if two arguments, the first one is the class to "swallow" subclasses
315   my ($c,$x) = @_;
316
317   if (scalar @_ == 1)
318     {
319     $x = $_[0];
320     $c = ref($x);
321     }
322   return unless ref($x); # only for objects
323
324   my $self = bless {}, $c;
325
326   $self->{sign} = $x->{sign};
327   $self->{_d} = $MBI->_copy($x->{_d});
328   $self->{_n} = $MBI->_copy($x->{_n});
329   $self->{_a} = $x->{_a} if defined $x->{_a};
330   $self->{_p} = $x->{_p} if defined $x->{_p};
331   $self;
332   }
333
334 ##############################################################################
335
336 sub config
337   {
338   # return (later set?) configuration data as hash ref
339   my $class = shift || 'Math::BigRat';
340
341   if (@_ == 1 && ref($_[0]) ne 'HASH')
342     {
343     my $cfg = $class->SUPER::config();
344     return $cfg->{$_[0]};
345     }
346
347   my $cfg = $class->SUPER::config(@_);
348
349   # now we need only to override the ones that are different from our parent
350   $cfg->{class} = $class;
351   $cfg->{with} = $MBI;
352   $cfg;
353   }
354
355 ##############################################################################
356
357 sub bstr
358   {
359   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
360
361   if ($x->{sign} !~ /^[+-]$/)           # inf, NaN etc
362     {
363     my $s = $x->{sign}; $s =~ s/^\+//;  # +inf => inf
364     return $s;
365     }
366
367   my $s = ''; $s = $x->{sign} if $x->{sign} ne '+';     # '+3/2' => '3/2'
368
369   return $s . $MBI->_str($x->{_n}) if $MBI->_is_one($x->{_d});
370   $s . $MBI->_str($x->{_n}) . '/' . $MBI->_str($x->{_d});
371   }
372
373 sub bsstr
374   {
375   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
376
377   if ($x->{sign} !~ /^[+-]$/)           # inf, NaN etc
378     {
379     my $s = $x->{sign}; $s =~ s/^\+//;  # +inf => inf
380     return $s;
381     }
382   
383   my $s = ''; $s = $x->{sign} if $x->{sign} ne '+';     # +3 vs 3
384   $s . $MBI->_str($x->{_n}) . '/' . $MBI->_str($x->{_d});
385   }
386
387 sub bnorm
388   {
389   # reduce the number to the shortest form
390   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
391
392   # Both parts must be objects of whatever we are using today.
393   if ( my $c = $MBI->_check($x->{_n}) )
394     {
395     require Carp; Carp::croak ("n did not pass the self-check ($c) in bnorm()");
396     }
397   if ( my $c = $MBI->_check($x->{_d}) )
398     {
399     require Carp; Carp::croak ("d did not pass the self-check ($c) in bnorm()");
400     }
401
402   # no normalize for NaN, inf etc.
403   return $x if $x->{sign} !~ /^[+-]$/;
404
405   # normalize zeros to 0/1
406   if ($MBI->_is_zero($x->{_n}))
407     {
408     $x->{sign} = '+';                                   # never leave a -0
409     $x->{_d} = $MBI->_one() unless $MBI->_is_one($x->{_d});
410     return $x;
411     }
412
413   return $x if $MBI->_is_one($x->{_d});                 # no need to reduce
414
415   # reduce other numbers
416   my $gcd = $MBI->_copy($x->{_n});
417   $gcd = $MBI->_gcd($gcd,$x->{_d});
418   
419   if (!$MBI->_is_one($gcd))
420     {
421     $x->{_n} = $MBI->_div($x->{_n},$gcd);
422     $x->{_d} = $MBI->_div($x->{_d},$gcd);
423     }
424   $x;
425   }
426
427 ##############################################################################
428 # sign manipulation
429
430 sub bneg
431   {
432   # (BRAT or num_str) return BRAT
433   # negate number or make a negated number from string
434   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
435
436   return $x if $x->modify('bneg');
437
438   # for +0 dont negate (to have always normalized +0). Does nothing for 'NaN'
439   $x->{sign} =~ tr/+-/-+/ unless ($x->{sign} eq '+' && $MBI->_is_zero($x->{_n}));
440   $x;
441   }
442
443 ##############################################################################
444 # special values
445
446 sub _bnan
447   {
448   # used by parent class bnan() to initialize number to NaN
449   my $self = shift;
450
451   if ($_trap_nan)
452     {
453     require Carp;
454     my $class = ref($self);
455     # "$self" below will stringify the object, this blows up if $self is a
456     # partial object (happens under trap_nan), so fix it beforehand
457     $self->{_d} = $MBI->_zero() unless defined $self->{_d};
458     $self->{_n} = $MBI->_zero() unless defined $self->{_n};
459     Carp::croak ("Tried to set $self to NaN in $class\::_bnan()");
460     }
461   $self->{_n} = $MBI->_zero();
462   $self->{_d} = $MBI->_zero();
463   }
464
465 sub _binf
466   {
467   # used by parent class bone() to initialize number to +inf/-inf
468   my $self = shift;
469
470   if ($_trap_inf)
471     {
472     require Carp;
473     my $class = ref($self);
474     # "$self" below will stringify the object, this blows up if $self is a
475     # partial object (happens under trap_nan), so fix it beforehand
476     $self->{_d} = $MBI->_zero() unless defined $self->{_d};
477     $self->{_n} = $MBI->_zero() unless defined $self->{_n};
478     Carp::croak ("Tried to set $self to inf in $class\::_binf()");
479     }
480   $self->{_n} = $MBI->_zero();
481   $self->{_d} = $MBI->_zero();
482   }
483
484 sub _bone
485   {
486   # used by parent class bone() to initialize number to +1/-1
487   my $self = shift;
488   $self->{_n} = $MBI->_one();
489   $self->{_d} = $MBI->_one();
490   }
491
492 sub _bzero
493   {
494   # used by parent class bzero() to initialize number to 0
495   my $self = shift;
496   $self->{_n} = $MBI->_zero();
497   $self->{_d} = $MBI->_one();
498   }
499
500 ##############################################################################
501 # mul/add/div etc
502
503 sub badd
504   {
505   # add two rational numbers
506
507   # set up parameters
508   my ($self,$x,$y,@r) = (ref($_[0]),@_);
509   # objectify is costly, so avoid it
510   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
511     {
512     ($self,$x,$y,@r) = objectify(2,@_);
513     }
514
515   # +inf + +inf => +inf,  -inf + -inf => -inf
516   return $x->binf(substr($x->{sign},0,1))
517     if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
518
519   # +inf + -inf or -inf + +inf => NaN
520   return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
521
522   #  1   1    gcd(3,4) = 1    1*3 + 1*4    7
523   #  - + -                  = --------- = --                 
524   #  4   3                      4*3       12
525
526   # we do not compute the gcd() here, but simple do:
527   #  5   7    5*3 + 7*4   43
528   #  - + -  = --------- = --                 
529   #  4   3       4*3      12
530  
531   # and bnorm() will then take care of the rest
532
533   # 5 * 3
534   $x->{_n} = $MBI->_mul( $x->{_n}, $y->{_d});
535
536   # 7 * 4
537   my $m = $MBI->_mul( $MBI->_copy( $y->{_n} ), $x->{_d} );
538
539   # 5 * 3 + 7 * 4
540   ($x->{_n}, $x->{sign}) = _e_add( $x->{_n}, $m, $x->{sign}, $y->{sign});
541
542   # 4 * 3
543   $x->{_d} = $MBI->_mul( $x->{_d}, $y->{_d});
544
545   # normalize result, and possible round
546   $x->bnorm()->round(@r);
547   }
548
549 sub bsub
550   {
551   # subtract two rational numbers
552
553   # set up parameters
554   my ($self,$x,$y,@r) = (ref($_[0]),@_);
555   # objectify is costly, so avoid it
556   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
557     {
558     ($self,$x,$y,@r) = objectify(2,@_);
559     }
560
561   # flip sign of $x, call badd(), then flip sign of result
562   $x->{sign} =~ tr/+-/-+/
563     unless $x->{sign} eq '+' && $MBI->_is_zero($x->{_n});       # not -0
564   $x->badd($y,@r);                              # does norm and round
565   $x->{sign} =~ tr/+-/-+/ 
566     unless $x->{sign} eq '+' && $MBI->_is_zero($x->{_n});       # not -0
567   $x;
568   }
569
570 sub bmul
571   {
572   # multiply two rational numbers
573   
574   # set up parameters
575   my ($self,$x,$y,@r) = (ref($_[0]),@_);
576   # objectify is costly, so avoid it
577   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
578     {
579     ($self,$x,$y,@r) = objectify(2,@_);
580     }
581
582   return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
583
584   # inf handling
585   if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/))
586     {
587     return $x->bnan() if $x->is_zero() || $y->is_zero();
588     # result will always be +-inf:
589     # +inf * +/+inf => +inf, -inf * -/-inf => +inf
590     # +inf * -/-inf => -inf, -inf * +/+inf => -inf
591     return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
592     return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
593     return $x->binf('-');
594     }
595
596   # x== 0 # also: or y == 1 or y == -1
597   return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
598
599   # XXX TODO:
600   # According to Knuth, this can be optimized by doing gcd twice (for d and n)
601   # and reducing in one step. This would save us the bnorm() at the end.
602
603   #  1   2    1 * 2    2    1
604   #  - * - =  -----  = -  = -
605   #  4   3    4 * 3    12   6
606   
607   $x->{_n} = $MBI->_mul( $x->{_n}, $y->{_n});
608   $x->{_d} = $MBI->_mul( $x->{_d}, $y->{_d});
609
610   # compute new sign
611   $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
612
613   $x->bnorm()->round(@r);
614   }
615
616 sub bdiv
617   {
618   # (dividend: BRAT or num_str, divisor: BRAT or num_str) return
619   # (BRAT,BRAT) (quo,rem) or BRAT (only rem)
620
621   # set up parameters
622   my ($self,$x,$y,@r) = (ref($_[0]),@_);
623   # objectify is costly, so avoid it
624   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
625     {
626     ($self,$x,$y,@r) = objectify(2,@_);
627     }
628
629   return $self->_div_inf($x,$y)
630    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
631
632   # x== 0 # also: or y == 1 or y == -1
633   return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
634
635   # XXX TODO: list context, upgrade
636   # According to Knuth, this can be optimized by doing gcd twice (for d and n)
637   # and reducing in one step. This would save us the bnorm() at the end.
638
639   # 1     1    1   3
640   # -  /  - == - * -
641   # 4     3    4   1
642   
643   $x->{_n} = $MBI->_mul( $x->{_n}, $y->{_d});
644   $x->{_d} = $MBI->_mul( $x->{_d}, $y->{_n});
645
646   # compute new sign 
647   $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
648
649   $x->bnorm()->round(@r);
650   $x;
651   }
652
653 sub bmod
654   {
655   # compute "remainder" (in Perl way) of $x / $y
656
657   # set up parameters
658   my ($self,$x,$y,@r) = (ref($_[0]),@_);
659   # objectify is costly, so avoid it
660   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
661     {
662     ($self,$x,$y,@r) = objectify(2,@_);
663     }
664
665   return $self->_div_inf($x,$y)
666    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
667
668   return $x if $x->is_zero();           # 0 / 7 = 0, mod 0
669
670   # compute $x - $y * floor($x/$y), keeping the sign of $x
671
672   # copy x to u, make it positive and then do a normal division ($u/$y)
673   my $u = bless { sign => '+' }, $self;
674   $u->{_n} = $MBI->_mul( $MBI->_copy($x->{_n}), $y->{_d} );
675   $u->{_d} = $MBI->_mul( $MBI->_copy($x->{_d}), $y->{_n} );
676   
677   # compute floor(u)
678   if (! $MBI->_is_one($u->{_d}))
679     {
680     $u->{_n} = $MBI->_div($u->{_n},$u->{_d});   # 22/7 => 3/1 w/ truncate
681     # no need to set $u->{_d} to 1, since below we set it to $y->{_d} anyway
682     }
683   
684   # now compute $y * $u
685   $u->{_d} = $MBI->_copy($y->{_d});             # 1 * $y->{_d}, see floor above
686   $u->{_n} = $MBI->_mul($u->{_n},$y->{_n});
687
688   my $xsign = $x->{sign}; $x->{sign} = '+';     # remember sign and make x positive
689   # compute $x - $u
690   $x->bsub($u);
691   $x->{sign} = $xsign;                          # put sign back
692
693   $x->bnorm()->round(@r);
694   }
695
696 ##############################################################################
697 # bdec/binc
698
699 sub bdec
700   {
701   # decrement value (subtract 1)
702   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
703
704   return $x if $x->{sign} !~ /^[+-]$/;  # NaN, inf, -inf
705
706   if ($x->{sign} eq '-')
707     {
708     $x->{_n} = $MBI->_add( $x->{_n}, $x->{_d});         # -5/2 => -7/2
709     }
710   else
711     {
712     if ($MBI->_acmp($x->{_n},$x->{_d}) < 0)             # n < d?
713       {
714       # 1/3 -- => -2/3
715       $x->{_n} = $MBI->_sub( $MBI->_copy($x->{_d}), $x->{_n});
716       $x->{sign} = '-';
717       }
718     else
719       {
720       $x->{_n} = $MBI->_sub($x->{_n}, $x->{_d});        # 5/2 => 3/2
721       }
722     }
723   $x->bnorm()->round(@r);
724   }
725
726 sub binc
727   {
728   # increment value (add 1)
729   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
730   
731   return $x if $x->{sign} !~ /^[+-]$/;  # NaN, inf, -inf
732
733   if ($x->{sign} eq '-')
734     {
735     if ($MBI->_acmp($x->{_n},$x->{_d}) < 0)
736       {
737       # -1/3 ++ => 2/3 (overflow at 0)
738       $x->{_n} = $MBI->_sub( $MBI->_copy($x->{_d}), $x->{_n});
739       $x->{sign} = '+';
740       }
741     else
742       {
743       $x->{_n} = $MBI->_sub($x->{_n}, $x->{_d});        # -5/2 => -3/2
744       }
745     }
746   else
747     {
748     $x->{_n} = $MBI->_add($x->{_n},$x->{_d});           # 5/2 => 7/2
749     }
750   $x->bnorm()->round(@r);
751   }
752
753 ##############################################################################
754 # is_foo methods (the rest is inherited)
755
756 sub is_int
757   {
758   # return true if arg (BRAT or num_str) is an integer
759   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
760
761   return 1 if ($x->{sign} =~ /^[+-]$/) &&       # NaN and +-inf aren't
762     $MBI->_is_one($x->{_d});                    # x/y && y != 1 => no integer
763   0;
764   }
765
766 sub is_zero
767   {
768   # return true if arg (BRAT or num_str) is zero
769   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
770
771   return 1 if $x->{sign} eq '+' && $MBI->_is_zero($x->{_n});
772   0;
773   }
774
775 sub is_one
776   {
777   # return true if arg (BRAT or num_str) is +1 or -1 if signis given
778   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
779
780   my $sign = $_[2] || ''; $sign = '+' if $sign ne '-';
781   return 1
782    if ($x->{sign} eq $sign && $MBI->_is_one($x->{_n}) && $MBI->_is_one($x->{_d}));
783   0;
784   }
785
786 sub is_odd
787   {
788   # return true if arg (BFLOAT or num_str) is odd or false if even
789   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
790
791   return 1 if ($x->{sign} =~ /^[+-]$/) &&               # NaN & +-inf aren't
792     ($MBI->_is_one($x->{_d}) && $MBI->_is_odd($x->{_n})); # x/2 is not, but 3/1
793   0;
794   }
795
796 sub is_even
797   {
798   # return true if arg (BINT or num_str) is even or false if odd
799   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
800
801   return 0 if $x->{sign} !~ /^[+-]$/;                   # NaN & +-inf aren't
802   return 1 if ($MBI->_is_one($x->{_d})                  # x/3 is never
803      && $MBI->_is_even($x->{_n}));                      # but 4/1 is
804   0;
805   }
806
807 ##############################################################################
808 # parts() and friends
809
810 sub numerator
811   {
812   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
813
814   # NaN, inf, -inf
815   return Math::BigInt->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
816
817   my $n = Math::BigInt->new($MBI->_str($x->{_n})); $n->{sign} = $x->{sign};
818   $n;
819   }
820
821 sub denominator
822   {
823   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
824
825   # NaN
826   return Math::BigInt->new($x->{sign}) if $x->{sign} eq 'NaN';
827   # inf, -inf
828   return Math::BigInt->bone() if $x->{sign} !~ /^[+-]$/;
829   
830   Math::BigInt->new($MBI->_str($x->{_d}));
831   }
832
833 sub parts
834   {
835   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
836
837   my $c = 'Math::BigInt';
838
839   return ($c->bnan(),$c->bnan()) if $x->{sign} eq 'NaN';
840   return ($c->binf(),$c->binf()) if $x->{sign} eq '+inf';
841   return ($c->binf('-'),$c->binf()) if $x->{sign} eq '-inf';
842
843   my $n = $c->new( $MBI->_str($x->{_n}));
844   $n->{sign} = $x->{sign};
845   my $d = $c->new( $MBI->_str($x->{_d}));
846   ($n,$d);
847   }
848
849 sub length
850   {
851   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
852
853   return $nan unless $x->is_int();
854   $MBI->_len($x->{_n});                         # length(-123/1) => length(123)
855   }
856
857 sub digit
858   {
859   my ($self,$x,$n) = ref($_[0]) ? (undef,$_[0],$_[1]) : objectify(1,@_);
860
861   return $nan unless $x->is_int();
862   $MBI->_digit($x->{_n},$n || 0);               # digit(-123/1,2) => digit(123,2)
863   }
864
865 ##############################################################################
866 # special calc routines
867
868 sub bceil
869   {
870   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
871
872   return $x if $x->{sign} !~ /^[+-]$/ ||        # not for NaN, inf
873             $MBI->_is_one($x->{_d});            # 22/1 => 22, 0/1 => 0
874
875   $x->{_n} = $MBI->_div($x->{_n},$x->{_d});     # 22/7 => 3/1 w/ truncate
876   $x->{_d} = $MBI->_one();                      # d => 1
877   $x->{_n} = $MBI->_inc($x->{_n})
878     if $x->{sign} eq '+';                       # +22/7 => 4/1
879   $x->{sign} = '+' if $MBI->_is_zero($x->{_n}); # -0 => 0
880   $x;
881   }
882
883 sub bfloor
884   {
885   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
886
887   return $x if $x->{sign} !~ /^[+-]$/ ||        # not for NaN, inf
888             $MBI->_is_one($x->{_d});            # 22/1 => 22, 0/1 => 0
889
890   $x->{_n} = $MBI->_div($x->{_n},$x->{_d});     # 22/7 => 3/1 w/ truncate
891   $x->{_d} = $MBI->_one();                      # d => 1
892   $x->{_n} = $MBI->_inc($x->{_n})
893     if $x->{sign} eq '-';                       # -22/7 => -4/1
894   $x;
895   }
896
897 sub bfac
898   {
899   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
900
901   # if $x is not an integer
902   if (($x->{sign} ne '+') || (!$MBI->_is_one($x->{_d})))
903     {
904     return $x->bnan();
905     }
906
907   $x->{_n} = $MBI->_fac($x->{_n});
908   # since _d is 1, we don't need to reduce/norm the result
909   $x->round(@r);
910   }
911
912 sub bpow
913   {
914   # power ($x ** $y)
915
916   # set up parameters
917   my ($self,$x,$y,@r) = (ref($_[0]),@_);
918   # objectify is costly, so avoid it
919   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
920     {
921     ($self,$x,$y,@r) = objectify(2,@_);
922     }
923
924   return $x if $x->{sign} =~ /^[+-]inf$/;       # -inf/+inf ** x
925   return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan;
926   return $x->bone(@r) if $y->is_zero();
927   return $x->round(@r) if $x->is_one() || $y->is_one();
928
929   if ($x->{sign} eq '-' && $MBI->_is_one($x->{_n}) && $MBI->_is_one($x->{_d}))
930     {
931     # if $x == -1 and odd/even y => +1/-1
932     return $y->is_odd() ? $x->round(@r) : $x->babs()->round(@r);
933     # my Casio FX-5500L has a bug here: -1 ** 2 is -1, but -1 * -1 is 1;
934     }
935   # 1 ** -y => 1 / (1 ** |y|)
936   # so do test for negative $y after above's clause
937
938   return $x->round(@r) if $x->is_zero();  # 0**y => 0 (if not y <= 0)
939
940   # shortcut if y == 1/N (is then sqrt() respective broot())
941   if ($MBI->_is_one($y->{_n}))
942     {
943     return $x->bsqrt(@r) if $MBI->_is_two($y->{_d});    # 1/2 => sqrt
944     return $x->broot($MBI->_str($y->{_d}),@r);          # 1/N => root(N)
945     }
946
947   # shortcut y/1 (and/or x/1)
948   if ($MBI->_is_one($y->{_d}))
949     {
950     # shortcut for x/1 and y/1
951     if ($MBI->_is_one($x->{_d}))
952       {
953       $x->{_n} = $MBI->_pow($x->{_n},$y->{_n});         # x/1 ** y/1 => (x ** y)/1
954       if ($y->{sign} eq '-')
955         {
956         # 0.2 ** -3 => 1/(0.2 ** 3)
957         ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n});      # swap
958         }
959       # correct sign; + ** + => +
960       if ($x->{sign} eq '-')
961         {
962         # - * - => +, - * - * - => -
963         $x->{sign} = '+' if $MBI->_is_even($y->{_n});   
964         }
965       return $x->round(@r);
966       }
967     # x/z ** y/1
968     $x->{_n} = $MBI->_pow($x->{_n},$y->{_n});           # 5/2 ** y/1 => 5 ** y / 2 ** y
969     $x->{_d} = $MBI->_pow($x->{_d},$y->{_n});
970     if ($y->{sign} eq '-')
971       {
972       # 0.2 ** -3 => 1/(0.2 ** 3)
973       ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n});        # swap
974       }
975     # correct sign; + ** + => +
976     if ($x->{sign} eq '-')
977       {
978       # - * - => +, - * - * - => -
979       $x->{sign} = '+' if $MBI->_is_even($y->{_n});     
980       }
981     return $x->round(@r);
982     }
983
984 #  print STDERR "# $x $y\n";
985
986   # otherwise:
987
988   #      n/d     n  ______________
989   # a/b       =  -\/  (a/b) ** d
990
991   # (a/b) ** n == (a ** n) / (b ** n)
992   $MBI->_pow($x->{_n}, $y->{_n} );
993   $MBI->_pow($x->{_d}, $y->{_n} );
994
995   return $x->broot($MBI->_str($y->{_d}),@r);            # n/d => root(n)
996   }
997
998 sub blog
999   {
1000   # set up parameters
1001   my ($self,$x,$y,@r) = (ref($_[0]),@_);
1002
1003   # objectify is costly, so avoid it
1004   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1005     {
1006     ($self,$x,$y,@r) = objectify(2,$class,@_);
1007     }
1008
1009   # blog(1,Y) => 0
1010   return $x->bzero() if $x->is_one() && $y->{sign} eq '+';
1011
1012   # $x <= 0 => NaN
1013   return $x->bnan() if $x->is_zero() || $x->{sign} ne '+' || $y->{sign} ne '+';
1014
1015   if ($x->is_int() && $y->is_int())
1016     {
1017     return $self->new($x->as_number()->blog($y->as_number(),@r));
1018     }
1019
1020   # do it with floats
1021   $x->_new_from_float( $x->_as_float()->blog(Math::BigFloat->new("$y"),@r) );
1022   }
1023
1024 sub bexp
1025   {
1026   # set up parameters
1027   my ($self,$x,$y,@r) = (ref($_[0]),@_);
1028
1029   # objectify is costly, so avoid it
1030   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1031     {
1032     ($self,$x,$y,@r) = objectify(2,$class,@_);
1033     }
1034
1035   return $x->binf(@r) if $x->{sign} eq '+inf';
1036   return $x->bzero(@r) if $x->{sign} eq '-inf';
1037
1038   # we need to limit the accuracy to protect against overflow
1039   my $fallback = 0;
1040   my ($scale,@params);
1041   ($x,@params) = $x->_find_round_parameters(@r);
1042
1043   # also takes care of the "error in _find_round_parameters?" case
1044   return $x if $x->{sign} eq 'NaN';
1045
1046   # no rounding at all, so must use fallback
1047   if (scalar @params == 0)
1048     {
1049     # simulate old behaviour
1050     $params[0] = $self->div_scale();    # and round to it as accuracy
1051     $params[1] = undef;                 # P = undef
1052     $scale = $params[0]+4;              # at least four more for proper round
1053     $params[2] = $r[2];                 # round mode by caller or undef
1054     $fallback = 1;                      # to clear a/p afterwards
1055     }
1056   else
1057     {
1058     # the 4 below is empirical, and there might be cases where it's not enough...
1059     $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
1060     }
1061
1062   return $x->bone(@params) if $x->is_zero();
1063
1064   # See the comments in Math::BigFloat on how this algorithm works.
1065   # Basically we calculate A and B (where B is faculty(N)) so that A/B = e
1066
1067   my $x_org = $x->copy();
1068   if ($scale <= 75)
1069     {
1070     # set $x directly from a cached string form
1071     $x->{_n} = $MBI->_new("90933395208605785401971970164779391644753259799242");
1072     $x->{_d} = $MBI->_new("33452526613163807108170062053440751665152000000000");
1073     $x->{sign} = '+';
1074     }
1075   else
1076     {
1077     # compute A and B so that e = A / B.
1078
1079     # After some terms we end up with this, so we use it as a starting point:
1080     my $A = $MBI->_new("90933395208605785401971970164779391644753259799242");
1081     my $F = $MBI->_new(42); my $step = 42;
1082
1083     # Compute how many steps we need to take to get $A and $B sufficiently big
1084     my $steps = Math::BigFloat::_len_to_steps($scale - 4);
1085 #    print STDERR "# Doing $steps steps for ", $scale-4, " digits\n";
1086     while ($step++ <= $steps)
1087       {
1088       # calculate $a * $f + 1
1089       $A = $MBI->_mul($A, $F);
1090       $A = $MBI->_inc($A);
1091       # increment f
1092       $F = $MBI->_inc($F);
1093       }
1094     # compute $B as factorial of $steps (this is faster than doing it manually)
1095     my $B = $MBI->_fac($MBI->_new($steps));
1096
1097 #  print "A ", $MBI->_str($A), "\nB ", $MBI->_str($B), "\n";
1098
1099     $x->{_n} = $A;
1100     $x->{_d} = $B;
1101     $x->{sign} = '+';
1102     }
1103
1104   # $x contains now an estimate of e, with some surplus digits, so we can round
1105   if (!$x_org->is_one())
1106     {
1107     # raise $x to the wanted power and round it in one step:
1108     $x->bpow($x_org, @params);
1109     }
1110   else
1111     {
1112     # else just round the already computed result
1113     delete $x->{_a}; delete $x->{_p};
1114     # shortcut to not run through _find_round_parameters again
1115     if (defined $params[0])
1116       {
1117       $x->bround($params[0],$params[2]);                # then round accordingly
1118       }
1119     else
1120       {
1121       $x->bfround($params[1],$params[2]);               # then round accordingly
1122       }
1123     }
1124   if ($fallback)
1125     {
1126     # clear a/p after round, since user did not request it
1127     delete $x->{_a}; delete $x->{_p};
1128     }
1129
1130   $x;
1131   }
1132
1133 sub bnok
1134   {
1135   # set up parameters
1136   my ($self,$x,$y,@r) = (ref($_[0]),@_);
1137
1138   # objectify is costly, so avoid it
1139   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1140     {
1141     ($self,$x,$y,@r) = objectify(2,$class,@_);
1142     }
1143
1144   # do it with floats
1145   $x->_new_from_float( $x->_as_float()->bnok(Math::BigFloat->new("$y"),@r) );
1146   }
1147
1148 sub _float_from_part
1149   {
1150   my $x = shift;
1151
1152   my $f = Math::BigFloat->bzero();
1153   $f->{_m} = $MBI->_copy($x);
1154   $f->{_e} = $MBI->_zero();
1155
1156   $f;
1157   }
1158
1159 sub _as_float
1160   {
1161   my $x = shift;
1162
1163   local $Math::BigFloat::upgrade = undef;
1164   local $Math::BigFloat::accuracy = undef;
1165   local $Math::BigFloat::precision = undef;
1166   # 22/7 => 3.142857143..
1167
1168   my $a = $x->accuracy() || 0;
1169   if ($a != 0 || !$MBI->_is_one($x->{_d}))
1170     {
1171     # n/d
1172     return scalar Math::BigFloat->new($x->{sign} . $MBI->_str($x->{_n}))->bdiv( $MBI->_str($x->{_d}), $x->accuracy());
1173     }
1174   # just n
1175   Math::BigFloat->new($x->{sign} . $MBI->_str($x->{_n}));
1176   }
1177
1178 sub broot
1179   {
1180   # set up parameters
1181   my ($self,$x,$y,@r) = (ref($_[0]),@_);
1182   # objectify is costly, so avoid it
1183   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1184     {
1185     ($self,$x,$y,@r) = objectify(2,@_);
1186     }
1187
1188   if ($x->is_int() && $y->is_int())
1189     {
1190     return $self->new($x->as_number()->broot($y->as_number(),@r));
1191     }
1192
1193   # do it with floats
1194   $x->_new_from_float( $x->_as_float()->broot($y->_as_float(),@r) )->bnorm()->bround(@r);
1195   }
1196
1197 sub bmodpow
1198   {
1199   # set up parameters
1200   my ($self,$x,$y,$m,@r) = (ref($_[0]),@_);
1201   # objectify is costly, so avoid it
1202   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1203     {
1204     ($self,$x,$y,$m,@r) = objectify(3,@_);
1205     }
1206
1207   # $x or $y or $m are NaN or +-inf => NaN
1208   return $x->bnan()
1209    if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/ ||
1210    $m->{sign} !~ /^[+-]$/;
1211
1212   if ($x->is_int() && $y->is_int() && $m->is_int())
1213     {
1214     return $self->new($x->as_number()->bmodpow($y->as_number(),$m,@r));
1215     }
1216
1217   warn ("bmodpow() not fully implemented");
1218   $x->bnan();
1219   }
1220
1221 sub bmodinv
1222   {
1223   # set up parameters
1224   my ($self,$x,$y,@r) = (ref($_[0]),@_);
1225   # objectify is costly, so avoid it
1226   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1227     {
1228     ($self,$x,$y,@r) = objectify(2,@_);
1229     }
1230
1231   # $x or $y are NaN or +-inf => NaN
1232   return $x->bnan() 
1233    if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/;
1234
1235   if ($x->is_int() && $y->is_int())
1236     {
1237     return $self->new($x->as_number()->bmodinv($y->as_number(),@r));
1238     }
1239
1240   warn ("bmodinv() not fully implemented");
1241   $x->bnan();
1242   }
1243
1244 sub bsqrt
1245   {
1246   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
1247
1248   return $x->bnan() if $x->{sign} !~ /^[+]/;    # NaN, -inf or < 0
1249   return $x if $x->{sign} eq '+inf';            # sqrt(inf) == inf
1250   return $x->round(@r) if $x->is_zero() || $x->is_one();
1251
1252   local $Math::BigFloat::upgrade = undef;
1253   local $Math::BigFloat::downgrade = undef;
1254   local $Math::BigFloat::precision = undef;
1255   local $Math::BigFloat::accuracy = undef;
1256   local $Math::BigInt::upgrade = undef;
1257   local $Math::BigInt::precision = undef;
1258   local $Math::BigInt::accuracy = undef;
1259
1260   $x->{_n} = _float_from_part( $x->{_n} )->bsqrt();
1261   $x->{_d} = _float_from_part( $x->{_d} )->bsqrt();
1262
1263   # XXX TODO: we probably can optimze this:
1264
1265   # if sqrt(D) was not integer
1266   if ($x->{_d}->{_es} ne '+')
1267     {
1268     $x->{_n}->blsft($x->{_d}->exponent()->babs(),10);   # 7.1/4.51 => 7.1/45.1
1269     $x->{_d} = $MBI->_copy( $x->{_d}->{_m} );           # 7.1/45.1 => 71/45.1
1270     }
1271   # if sqrt(N) was not integer
1272   if ($x->{_n}->{_es} ne '+')
1273     {
1274     $x->{_d}->blsft($x->{_n}->exponent()->babs(),10);   # 71/45.1 => 710/45.1
1275     $x->{_n} = $MBI->_copy( $x->{_n}->{_m} );           # 710/45.1 => 710/451
1276     }
1277
1278   # convert parts to $MBI again 
1279   $x->{_n} = $MBI->_lsft( $MBI->_copy( $x->{_n}->{_m} ), $x->{_n}->{_e}, 10)
1280     if ref($x->{_n}) ne $MBI && ref($x->{_n}) ne 'ARRAY';
1281   $x->{_d} = $MBI->_lsft( $MBI->_copy( $x->{_d}->{_m} ), $x->{_d}->{_e}, 10)
1282     if ref($x->{_d}) ne $MBI && ref($x->{_d}) ne 'ARRAY';
1283
1284   $x->bnorm()->round(@r);
1285   }
1286
1287 sub blsft
1288   {
1289   my ($self,$x,$y,$b,@r) = objectify(3,@_);
1290  
1291   $b = 2 unless defined $b;
1292   $b = $self->new($b) unless ref ($b);
1293   $x->bmul( $b->copy()->bpow($y), @r);
1294   $x;
1295   }
1296
1297 sub brsft
1298   {
1299   my ($self,$x,$y,$b,@r) = objectify(3,@_);
1300
1301   $b = 2 unless defined $b;
1302   $b = $self->new($b) unless ref ($b);
1303   $x->bdiv( $b->copy()->bpow($y), @r);
1304   $x;
1305   }
1306
1307 ##############################################################################
1308 # round
1309
1310 sub round
1311   {
1312   $_[0];
1313   }
1314
1315 sub bround
1316   {
1317   $_[0];
1318   }
1319
1320 sub bfround
1321   {
1322   $_[0];
1323   }
1324
1325 ##############################################################################
1326 # comparing
1327
1328 sub bcmp
1329   {
1330   # compare two signed numbers 
1331   
1332   # set up parameters
1333   my ($self,$x,$y) = (ref($_[0]),@_);
1334   # objectify is costly, so avoid it
1335   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1336     {
1337     ($self,$x,$y) = objectify(2,@_);
1338     }
1339
1340   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
1341     {
1342     # handle +-inf and NaN
1343     return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
1344     return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
1345     return +1 if $x->{sign} eq '+inf';
1346     return -1 if $x->{sign} eq '-inf';
1347     return -1 if $y->{sign} eq '+inf';
1348     return +1;
1349     }
1350   # check sign for speed first
1351   return 1 if $x->{sign} eq '+' && $y->{sign} eq '-';   # does also 0 <=> -y
1352   return -1 if $x->{sign} eq '-' && $y->{sign} eq '+';  # does also -x <=> 0
1353
1354   # shortcut
1355   my $xz = $MBI->_is_zero($x->{_n});
1356   my $yz = $MBI->_is_zero($y->{_n});
1357   return 0 if $xz && $yz;                               # 0 <=> 0
1358   return -1 if $xz && $y->{sign} eq '+';                # 0 <=> +y
1359   return 1 if $yz && $x->{sign} eq '+';                 # +x <=> 0
1360  
1361   my $t = $MBI->_mul( $MBI->_copy($x->{_n}), $y->{_d});
1362   my $u = $MBI->_mul( $MBI->_copy($y->{_n}), $x->{_d});
1363
1364   my $cmp = $MBI->_acmp($t,$u);                         # signs are equal
1365   $cmp = -$cmp if $x->{sign} eq '-';                    # both are '-' => reverse
1366   $cmp;
1367   }
1368
1369 sub bacmp
1370   {
1371   # compare two numbers (as unsigned)
1372  
1373   # set up parameters
1374   my ($self,$x,$y) = (ref($_[0]),@_);
1375   # objectify is costly, so avoid it
1376   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1377     {
1378     ($self,$x,$y) = objectify(2,$class,@_);
1379     }
1380
1381   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
1382     {
1383     # handle +-inf and NaN
1384     return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
1385     return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
1386     return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/;
1387     return -1;
1388     }
1389
1390   my $t = $MBI->_mul( $MBI->_copy($x->{_n}), $y->{_d});
1391   my $u = $MBI->_mul( $MBI->_copy($y->{_n}), $x->{_d});
1392   $MBI->_acmp($t,$u);                                   # ignore signs
1393   }
1394
1395 ##############################################################################
1396 # output conversation
1397
1398 sub numify
1399   {
1400   # convert 17/8 => float (aka 2.125)
1401   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1402  
1403   return $x->bstr() if $x->{sign} !~ /^[+-]$/;  # inf, NaN, etc
1404
1405   # N/1 => N
1406   my $neg = ''; $neg = '-' if $x->{sign} eq '-';
1407   return $neg . $MBI->_num($x->{_n}) if $MBI->_is_one($x->{_d});
1408
1409   $x->_as_float()->numify() + 0.0;
1410   }
1411
1412 sub as_number
1413   {
1414   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1415
1416   # NaN, inf etc
1417   return Math::BigInt->new($x->{sign}) if $x->{sign} !~ /^[+-]$/;
1418  
1419   my $u = Math::BigInt->bzero();
1420   $u->{sign} = $x->{sign};
1421   $u->{value} = $MBI->_div( $MBI->_copy($x->{_n}), $x->{_d});   # 22/7 => 3
1422   $u;
1423   }
1424
1425 sub as_float
1426   {
1427   # return N/D as Math::BigFloat
1428
1429   # set up parameters
1430   my ($self,$x,@r) = (ref($_[0]),@_);
1431   # objectify is costly, so avoid it
1432   ($self,$x,@r) = objectify(1,$class,@_) unless ref $_[0];
1433
1434   # NaN, inf etc
1435   return Math::BigFloat->new($x->{sign}) if $x->{sign} !~ /^[+-]$/;
1436  
1437   my $u = Math::BigFloat->bzero();
1438   $u->{sign} = $x->{sign};
1439   # n
1440   $u->{_m} = $MBI->_copy($x->{_n});
1441   $u->{_e} = $MBI->_zero();
1442   $u->bdiv( $MBI->_str($x->{_d}), @r);
1443   # return $u
1444   $u;
1445   }
1446
1447 sub as_bin
1448   {
1449   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1450
1451   return $x unless $x->is_int();
1452
1453   my $s = $x->{sign}; $s = '' if $s eq '+';
1454   $s . $MBI->_as_bin($x->{_n});
1455   }
1456
1457 sub as_hex
1458   {
1459   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1460
1461   return $x unless $x->is_int();
1462
1463   my $s = $x->{sign}; $s = '' if $s eq '+';
1464   $s . $MBI->_as_hex($x->{_n});
1465   }
1466
1467 sub as_oct
1468   {
1469   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1470
1471   return $x unless $x->is_int();
1472
1473   my $s = $x->{sign}; $s = '' if $s eq '+';
1474   $s . $MBI->_as_oct($x->{_n});
1475   }
1476
1477 ##############################################################################
1478
1479 sub from_hex
1480   {
1481   my $class = shift;
1482
1483   $class->new(@_);
1484   }
1485
1486 sub from_bin
1487   {
1488   my $class = shift;
1489
1490   $class->new(@_);
1491   }
1492
1493 sub from_oct
1494   {
1495   my $class = shift;
1496
1497   my @parts;
1498   for my $c (@_)
1499     {
1500     push @parts, Math::BigInt->from_oct($c);
1501     }
1502   $class->new ( @parts );
1503   }
1504
1505 ##############################################################################
1506 # import
1507
1508 sub import
1509   {
1510   my $self = shift;
1511   my $l = scalar @_;
1512   my $lib = ''; my @a;
1513   my $try = 'try';
1514
1515   for ( my $i = 0; $i < $l ; $i++)
1516     {
1517     if ( $_[$i] eq ':constant' )
1518       {
1519       # this rest causes overlord er load to step in
1520       overload::constant float => sub { $self->new(shift); };
1521       }
1522 #    elsif ($_[$i] eq 'upgrade')
1523 #      {
1524 #     # this causes upgrading
1525 #      $upgrade = $_[$i+1];             # or undef to disable
1526 #      $i++;
1527 #      }
1528     elsif ($_[$i] eq 'downgrade')
1529       {
1530       # this causes downgrading
1531       $downgrade = $_[$i+1];            # or undef to disable
1532       $i++;
1533       }
1534     elsif ($_[$i] =~ /^(lib|try|only)\z/)
1535       {
1536       $lib = $_[$i+1] || '';            # default Calc
1537       $try = $1;                        # lib, try or only
1538       $i++;
1539       }
1540     elsif ($_[$i] eq 'with')
1541       {
1542       # this argument is no longer used
1543       #$MBI = $_[$i+1] || 'Math::BigInt::Calc'; # default Math::BigInt::Calc
1544       $i++;
1545       }
1546     else
1547       {
1548       push @a, $_[$i];
1549       }
1550     }
1551   require Math::BigInt;
1552
1553   # let use Math::BigInt lib => 'GMP'; use Math::BigRat; still have GMP
1554   if ($lib ne '')
1555     {
1556     my @c = split /\s*,\s*/, $lib;
1557     foreach (@c)
1558       {
1559       $_ =~ tr/a-zA-Z0-9://cd;                    # limit to sane characters
1560       }
1561     $lib = join(",", @c);
1562     }
1563   my @import = ('objectify');
1564   push @import, $try => $lib if $lib ne '';
1565
1566   # MBI already loaded, so feed it our lib arguments
1567   Math::BigInt->import( @import );
1568
1569   $MBI = Math::BigFloat->config()->{lib};
1570
1571   # register us with MBI to get notified of future lib changes
1572   Math::BigInt::_register_callback( $self, sub { $MBI = $_[0]; } );
1573   
1574   # any non :constant stuff is handled by our parent, Exporter (loaded
1575   # by Math::BigFloat, even if @_ is empty, to give it a chance
1576   $self->SUPER::import(@a);             # for subclasses
1577   $self->export_to_level(1,$self,@a);   # need this, too
1578   }
1579
1580 1;
1581
1582 __END__
1583
1584 =head1 NAME
1585
1586 Math::BigRat - Arbitrary big rational numbers
1587
1588 =head1 SYNOPSIS
1589
1590         use Math::BigRat;
1591
1592         my $x = Math::BigRat->new('3/7'); $x += '5/9';
1593
1594         print $x->bstr(),"\n";
1595         print $x ** 2,"\n";
1596
1597         my $y = Math::BigRat->new('inf');
1598         print "$y ", ($y->is_inf ? 'is' : 'is not') , " infinity\n";
1599
1600         my $z = Math::BigRat->new(144); $z->bsqrt();
1601
1602 =head1 DESCRIPTION
1603
1604 Math::BigRat complements Math::BigInt and Math::BigFloat by providing support
1605 for arbitrary big rational numbers.
1606
1607 =head2 MATH LIBRARY
1608
1609 You can change the underlying module that does the low-level
1610 math operations by using:
1611
1612         use Math::BigRat try => 'GMP';
1613
1614 Note: This needs Math::BigInt::GMP installed.
1615
1616 The following would first try to find Math::BigInt::Foo, then
1617 Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
1618
1619         use Math::BigRat try => 'Foo,Math::BigInt::Bar';
1620
1621 If you want to get warned when the fallback occurs, replace "try" with
1622 "lib":
1623
1624         use Math::BigRat lib => 'Foo,Math::BigInt::Bar';
1625
1626 If you want the code to die instead, replace "try" with
1627 "only":
1628
1629         use Math::BigRat only => 'Foo,Math::BigInt::Bar';
1630
1631 =head1 METHODS
1632
1633 Any methods not listed here are derived from Math::BigFloat (or
1634 Math::BigInt), so make sure you check these two modules for further
1635 information.
1636
1637 =head2 new()
1638
1639         $x = Math::BigRat->new('1/3');
1640
1641 Create a new Math::BigRat object. Input can come in various forms:
1642
1643         $x = Math::BigRat->new(123);                            # scalars
1644         $x = Math::BigRat->new('inf');                          # infinity
1645         $x = Math::BigRat->new('123.3');                        # float
1646         $x = Math::BigRat->new('1/3');                          # simple string
1647         $x = Math::BigRat->new('1 / 3');                        # spaced
1648         $x = Math::BigRat->new('1 / 0.1');                      # w/ floats
1649         $x = Math::BigRat->new(Math::BigInt->new(3));           # BigInt
1650         $x = Math::BigRat->new(Math::BigFloat->new('3.1'));     # BigFloat
1651         $x = Math::BigRat->new(Math::BigInt::Lite->new('2'));   # BigLite
1652
1653         # You can also give D and N as different objects:
1654         $x = Math::BigRat->new(
1655                 Math::BigInt->new(-123),
1656                 Math::BigInt->new(7),
1657                 );                      # => -123/7
1658
1659 =head2 numerator()
1660
1661         $n = $x->numerator();
1662
1663 Returns a copy of the numerator (the part above the line) as signed BigInt.
1664
1665 =head2 denominator()
1666         
1667         $d = $x->denominator();
1668
1669 Returns a copy of the denominator (the part under the line) as positive BigInt.
1670
1671 =head2 parts()
1672
1673         ($n,$d) = $x->parts();
1674
1675 Return a list consisting of (signed) numerator and (unsigned) denominator as
1676 BigInts.
1677
1678 =head2 numify()
1679
1680         my $y = $x->numify();
1681
1682 Returns the object as a scalar. This will lose some data if the object
1683 cannot be represented by a normal Perl scalar (integer or float), so
1684 use L<as_int()> or L<as_float()> instead.
1685
1686 This routine is automatically used whenever a scalar is required:
1687
1688         my $x = Math::BigRat->new('3/1');
1689         @array = (1,2,3);
1690         $y = $array[$x];                # set $y to 3
1691
1692 =head2 as_int()/as_number()
1693
1694         $x = Math::BigRat->new('13/7');
1695         print $x->as_int(),"\n";                # '1'
1696
1697 Returns a copy of the object as BigInt, truncated to an integer.
1698
1699 C<as_number()> is an alias for C<as_int()>.
1700
1701 =head2 as_float()
1702
1703         $x = Math::BigRat->new('13/7');
1704         print $x->as_float(),"\n";              # '1'
1705
1706         $x = Math::BigRat->new('2/3');
1707         print $x->as_float(5),"\n";             # '0.66667'
1708
1709 Returns a copy of the object as BigFloat, preserving the
1710 accuracy as wanted, or the default of 40 digits.
1711
1712 This method was added in v0.22 of Math::BigRat (April 2008).
1713
1714 =head2 as_hex()
1715
1716         $x = Math::BigRat->new('13');
1717         print $x->as_hex(),"\n";                # '0xd'
1718
1719 Returns the BigRat as hexadecimal string. Works only for integers. 
1720
1721 =head2 as_bin()
1722
1723         $x = Math::BigRat->new('13');
1724         print $x->as_bin(),"\n";                # '0x1101'
1725
1726 Returns the BigRat as binary string. Works only for integers. 
1727
1728 =head2 as_oct()
1729
1730         $x = Math::BigRat->new('13');
1731         print $x->as_oct(),"\n";                # '015'
1732
1733 Returns the BigRat as octal string. Works only for integers. 
1734
1735 =head2 from_hex()/from_bin()/from_oct()
1736
1737         my $h = Math::BigRat->from_hex('0x10');
1738         my $b = Math::BigRat->from_bin('0b10000000');
1739         my $o = Math::BigRat->from_oct('020');
1740
1741 Create a BigRat from an hexadecimal, binary or octal number
1742 in string form.
1743
1744 =head2 length()
1745
1746         $len = $x->length();
1747
1748 Return the length of $x in digitis for integer values.
1749
1750 =head2 digit()
1751
1752         print Math::BigRat->new('123/1')->digit(1);     # 1
1753         print Math::BigRat->new('123/1')->digit(-1);    # 3
1754
1755 Return the N'ths digit from X when X is an integer value.
1756
1757 =head2 bnorm()
1758
1759         $x->bnorm();
1760
1761 Reduce the number to the shortest form. This routine is called
1762 automatically whenever it is needed.
1763
1764 =head2 bfac()
1765
1766         $x->bfac();
1767
1768 Calculates the factorial of $x. For instance:
1769
1770         print Math::BigRat->new('3/1')->bfac(),"\n";    # 1*2*3
1771         print Math::BigRat->new('5/1')->bfac(),"\n";    # 1*2*3*4*5
1772
1773 Works currently only for integers.
1774
1775 =head2 bround()/round()/bfround()
1776
1777 Are not yet implemented.
1778
1779 =head2 bmod()
1780
1781         use Math::BigRat;
1782         my $x = Math::BigRat->new('7/4');
1783         my $y = Math::BigRat->new('4/3');
1784         print $x->bmod($y);
1785
1786 Set $x to the remainder of the division of $x by $y.
1787
1788 =head2 bneg()
1789
1790         $x->bneg();
1791
1792 Used to negate the object in-place.
1793
1794 =head2 is_one()
1795
1796         print "$x is 1\n" if $x->is_one();
1797
1798 Return true if $x is exactly one, otherwise false.
1799
1800 =head2 is_zero()
1801
1802         print "$x is 0\n" if $x->is_zero();
1803
1804 Return true if $x is exactly zero, otherwise false.
1805
1806 =head2 is_pos()/is_positive()
1807
1808         print "$x is >= 0\n" if $x->is_positive();
1809
1810 Return true if $x is positive (greater than or equal to zero), otherwise
1811 false. Please note that '+inf' is also positive, while 'NaN' and '-inf' aren't.
1812
1813 C<is_positive()> is an alias for C<is_pos()>.
1814
1815 =head2 is_neg()/is_negative()
1816
1817         print "$x is < 0\n" if $x->is_negative();
1818
1819 Return true if $x is negative (smaller than zero), otherwise false. Please
1820 note that '-inf' is also negative, while 'NaN' and '+inf' aren't.
1821
1822 C<is_negative()> is an alias for C<is_neg()>.
1823
1824 =head2 is_int()
1825
1826         print "$x is an integer\n" if $x->is_int();
1827
1828 Return true if $x has a denominator of 1 (e.g. no fraction parts), otherwise
1829 false. Please note that '-inf', 'inf' and 'NaN' aren't integer.
1830
1831 =head2 is_odd()
1832
1833         print "$x is odd\n" if $x->is_odd();
1834
1835 Return true if $x is odd, otherwise false.
1836
1837 =head2 is_even()
1838
1839         print "$x is even\n" if $x->is_even();
1840
1841 Return true if $x is even, otherwise false.
1842
1843 =head2 bceil()
1844
1845         $x->bceil();
1846
1847 Set $x to the next bigger integer value (e.g. truncate the number to integer
1848 and then increment it by one).
1849
1850 =head2 bfloor()
1851         
1852         $x->bfloor();
1853
1854 Truncate $x to an integer value.
1855
1856 =head2 bsqrt()
1857         
1858         $x->bsqrt();
1859
1860 Calculate the square root of $x.
1861
1862 =head2 broot()
1863         
1864         $x->broot($n);
1865
1866 Calculate the N'th root of $x.
1867
1868 =head2 badd()/bmul()/bsub()/bdiv()/bdec()/binc()
1869
1870 Please see the documentation in L<Math::BigInt>.
1871
1872 =head2 copy()
1873
1874         my $z = $x->copy();
1875
1876 Makes a deep copy of the object.
1877
1878 Please see the documentation in L<Math::BigInt> for further details.
1879
1880 =head2 bstr()/bsstr()
1881
1882         my $x = Math::BigInt->new('8/4');
1883         print $x->bstr(),"\n";                  # prints 1/2
1884         print $x->bsstr(),"\n";                 # prints 1/2
1885
1886 Return a string representating this object.
1887
1888 =head2 bacmp()/bcmp()
1889
1890 Used to compare numbers.
1891
1892 Please see the documentation in L<Math::BigInt> for further details.
1893
1894 =head2 blsft()/brsft()
1895
1896 Used to shift numbers left/right.
1897
1898 Please see the documentation in L<Math::BigInt> for further details.
1899
1900 =head2 bpow()
1901
1902         $x->bpow($y);
1903
1904 Compute $x ** $y.
1905
1906 Please see the documentation in L<Math::BigInt> for further details.
1907
1908 =head2 bexp()
1909
1910         $x->bexp($accuracy);            # calculate e ** X
1911
1912 Calculates two integers A and B so that A/B is equal to C<e ** $x>, where C<e> is
1913 Euler's number.
1914
1915 This method was added in v0.20 of Math::BigRat (May 2007).
1916
1917 See also L<blog()>.
1918
1919 =head2 bnok()
1920
1921         $x->bnok($y);              # x over y (binomial coefficient n over k)
1922
1923 Calculates the binomial coefficient n over k, also called the "choose"
1924 function. The result is equivalent to:
1925
1926         ( n )      n!
1927         | - |  = -------
1928         ( k )    k!(n-k)!
1929
1930 This method was added in v0.20 of Math::BigRat (May 2007).
1931
1932 =head2 config()
1933
1934         use Data::Dumper;
1935
1936         print Dumper ( Math::BigRat->config() );
1937         print Math::BigRat->config()->{lib},"\n";
1938
1939 Returns a hash containing the configuration, e.g. the version number, lib
1940 loaded etc. The following hash keys are currently filled in with the
1941 appropriate information.
1942
1943         key             RO/RW   Description
1944                                 Example
1945         ============================================================
1946         lib             RO      Name of the Math library
1947                                 Math::BigInt::Calc
1948         lib_version     RO      Version of 'lib'
1949                                 0.30
1950         class           RO      The class of config you just called
1951                                 Math::BigRat
1952         version         RO      version number of the class you used
1953                                 0.10
1954         upgrade         RW      To which class numbers are upgraded
1955                                 undef
1956         downgrade       RW      To which class numbers are downgraded
1957                                 undef
1958         precision       RW      Global precision
1959                                 undef
1960         accuracy        RW      Global accuracy
1961                                 undef
1962         round_mode      RW      Global round mode
1963                                 even
1964         div_scale       RW      Fallback accuracy for div
1965                                 40
1966         trap_nan        RW      Trap creation of NaN (undef = no)
1967                                 undef
1968         trap_inf        RW      Trap creation of +inf/-inf (undef = no)
1969                                 undef
1970
1971 By passing a reference to a hash you may set the configuration values. This
1972 works only for values that a marked with a C<RW> above, anything else is
1973 read-only.
1974
1975 =head2 objectify()
1976
1977 This is an internal routine that turns scalars into objects.
1978
1979 =head1 BUGS
1980
1981 Some things are not yet implemented, or only implemented half-way:
1982
1983 =over 2
1984
1985 =item inf handling (partial)
1986
1987 =item NaN handling (partial)
1988
1989 =item rounding (not implemented except for bceil/bfloor)
1990
1991 =item $x ** $y where $y is not an integer
1992
1993 =item bmod(), blog(), bmodinv() and bmodpow() (partial)
1994
1995 =back
1996
1997 =head1 LICENSE
1998
1999 This program is free software; you may redistribute it and/or modify it under
2000 the same terms as Perl itself.
2001
2002 =head1 SEE ALSO
2003
2004 L<Math::BigFloat> and L<Math::Big> as well as L<Math::BigInt::BitVect>,
2005 L<Math::BigInt::Pari> and  L<Math::BigInt::GMP>.
2006
2007 See L<http://search.cpan.org/search?dist=bignum> for a way to use
2008 Math::BigRat.
2009
2010 The package at L<http://search.cpan.org/search?dist=Math%3A%3ABigRat>
2011 may contain more documentation and examples as well as testcases.
2012
2013 =head1 AUTHORS
2014
2015 (C) by Tels L<http://bloodgate.com/> 2001 - 2008.
2016
2017 =cut