Update Term::UI to 0.16
[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.21';
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 y/1 (and/or x/1)
941   if ($MBI->_is_one($y->{_d}))
942     {
943     # shortcut for x/1 and y/1
944     if ($MBI->_is_one($x->{_d}))
945       {
946       $x->{_n} = $MBI->_pow($x->{_n},$y->{_n});         # x/1 ** y/1 => (x ** y)/1
947       if ($y->{sign} eq '-')
948         {
949         # 0.2 ** -3 => 1/(0.2 ** 3)
950         ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n});      # swap
951         }
952       # correct sign; + ** + => +
953       if ($x->{sign} eq '-')
954         {
955         # - * - => +, - * - * - => -
956         $x->{sign} = '+' if $MBI->_is_even($y->{_n});   
957         }
958       return $x->round(@r);
959       }
960     # x/z ** y/1
961     $x->{_n} = $MBI->_pow($x->{_n},$y->{_n});           # 5/2 ** y/1 => 5 ** y / 2 ** y
962     $x->{_d} = $MBI->_pow($x->{_d},$y->{_n});
963     if ($y->{sign} eq '-')
964       {
965       # 0.2 ** -3 => 1/(0.2 ** 3)
966       ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n});        # swap
967       }
968     # correct sign; + ** + => +
969     if ($x->{sign} eq '-')
970       {
971       # - * - => +, - * - * - => -
972       $x->{sign} = '+' if $MBI->_is_even($y->{_n});     
973       }
974     return $x->round(@r);
975     }
976
977   # regular calculation (this is wrong for d/e ** f/g)
978   my $pow2 = $self->bone();
979   my $y1 = $MBI->_div ( $MBI->_copy($y->{_n}), $y->{_d});
980   my $two = $MBI->_two();
981
982   while (!$MBI->_is_one($y1))
983     {
984     $pow2->bmul($x) if $MBI->_is_odd($y1);
985     $MBI->_div($y1, $two);
986     $x->bmul($x);
987     }
988   $x->bmul($pow2) unless $pow2->is_one();
989   # n ** -x => 1/n ** x
990   ($x->{_d},$x->{_n}) = ($x->{_n},$x->{_d}) if $y->{sign} eq '-'; 
991   $x->bnorm()->round(@r);
992   }
993
994 sub blog
995   {
996   # set up parameters
997   my ($self,$x,$y,@r) = (ref($_[0]),@_);
998
999   # objectify is costly, so avoid it
1000   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1001     {
1002     ($self,$x,$y,@r) = objectify(2,$class,@_);
1003     }
1004
1005   # blog(1,Y) => 0
1006   return $x->bzero() if $x->is_one() && $y->{sign} eq '+';
1007
1008   # $x <= 0 => NaN
1009   return $x->bnan() if $x->is_zero() || $x->{sign} ne '+' || $y->{sign} ne '+';
1010
1011   if ($x->is_int() && $y->is_int())
1012     {
1013     return $self->new($x->as_number()->blog($y->as_number(),@r));
1014     }
1015
1016   # do it with floats
1017   $x->_new_from_float( $x->_as_float()->blog(Math::BigFloat->new("$y"),@r) );
1018   }
1019
1020 sub bexp
1021   {
1022   # set up parameters
1023   my ($self,$x,$y,$a,$p,$r) = (ref($_[0]),@_);
1024
1025   # objectify is costly, so avoid it
1026   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1027     {
1028     ($self,$x,$y,$a,$p,$r) = objectify(2,$class,@_);
1029     }
1030
1031   return $x->binf() if $x->{sign} eq '+inf';
1032   return $x->bzero() if $x->{sign} eq '-inf';
1033
1034   # we need to limit the accuracy to protect against overflow
1035   my $fallback = 0;
1036   my ($scale,@params);
1037   ($x,@params) = $x->_find_round_parameters($a,$p,$r);
1038
1039   # also takes care of the "error in _find_round_parameters?" case
1040   return $x if $x->{sign} eq 'NaN';
1041
1042   # no rounding at all, so must use fallback
1043   if (scalar @params == 0)
1044     {
1045     # simulate old behaviour
1046     $params[0] = $self->div_scale();    # and round to it as accuracy
1047     $params[1] = undef;                 # P = undef
1048     $scale = $params[0]+4;              # at least four more for proper round
1049     $params[2] = $r;                    # round mode by caller or undef
1050     $fallback = 1;                      # to clear a/p afterwards
1051     }
1052   else
1053     {
1054     # the 4 below is empirical, and there might be cases where it's not enough...
1055     $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
1056     }
1057
1058   return $x->bone(@params) if $x->is_zero();
1059
1060   # See the comments in Math::BigFloat on how this algorithm works.
1061   # Basically we calculate A and B (where B is faculty(N)) so that A/B = e
1062
1063   my $x_org = $x->copy();
1064   if ($scale <= 75)
1065     {
1066     # set $x directly from a cached string form
1067     $x->{_n} = $MBI->_new("90933395208605785401971970164779391644753259799242");
1068     $x->{_d} = $MBI->_new("33452526613163807108170062053440751665152000000000");
1069     $x->{sign} = '+';
1070     }
1071   else
1072     {
1073     # compute A and B so that e = A / B.
1074
1075     # After some terms we end up with this, so we use it as a starting point:
1076     my $A = $MBI->_new("90933395208605785401971970164779391644753259799242");
1077     my $F = $MBI->_new(42); my $step = 42;
1078
1079     # Compute how many steps we need to take to get $A and $B sufficiently big
1080     my $steps = Math::BigFloat::_len_to_steps($scale - 4);
1081 #    print STDERR "# Doing $steps steps for ", $scale-4, " digits\n";
1082     while ($step++ <= $steps)
1083       {
1084       # calculate $a * $f + 1
1085       $A = $MBI->_mul($A, $F);
1086       $A = $MBI->_inc($A);
1087       # increment f
1088       $F = $MBI->_inc($F);
1089       }
1090     # compute $B as factorial of $steps (this is faster than doing it manually)
1091     my $B = $MBI->_fac($MBI->_new($steps));
1092
1093 #  print "A ", $MBI->_str($A), "\nB ", $MBI->_str($B), "\n";
1094
1095     $x->{_n} = $A;
1096     $x->{_d} = $B;
1097     $x->{sign} = '+';
1098     }
1099
1100   # $x contains now an estimate of e, with some surplus digits, so we can round
1101   if (!$x_org->is_one())
1102     {
1103     # raise $x to the wanted power and round it in one step:
1104     $x->bpow($x_org, @params);
1105     }
1106   else
1107     {
1108     # else just round the already computed result
1109     delete $x->{_a}; delete $x->{_p};
1110     # shortcut to not run through _find_round_parameters again
1111     if (defined $params[0])
1112       {
1113       $x->bround($params[0],$params[2]);                # then round accordingly
1114       }
1115     else
1116       {
1117       $x->bfround($params[1],$params[2]);               # then round accordingly
1118       }
1119     }
1120   if ($fallback)
1121     {
1122     # clear a/p after round, since user did not request it
1123     delete $x->{_a}; delete $x->{_p};
1124     }
1125
1126   $x;
1127   }
1128
1129 sub bnok
1130   {
1131   # set up parameters
1132   my ($self,$x,$y,@r) = (ref($_[0]),@_);
1133
1134   # objectify is costly, so avoid it
1135   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1136     {
1137     ($self,$x,$y,@r) = objectify(2,$class,@_);
1138     }
1139
1140   # do it with floats
1141   $x->_new_from_float( $x->_as_float()->bnok(Math::BigFloat->new("$y"),@r) );
1142   }
1143
1144 sub _float_from_part
1145   {
1146   my $x = shift;
1147
1148   my $f = Math::BigFloat->bzero();
1149   $f->{_m} = $MBI->_copy($x);
1150   $f->{_e} = $MBI->_zero();
1151
1152   $f;
1153   }
1154
1155 sub _as_float
1156   {
1157   my $x = shift;
1158
1159   local $Math::BigFloat::upgrade = undef;
1160   local $Math::BigFloat::accuracy = undef;
1161   local $Math::BigFloat::precision = undef;
1162   # 22/7 => 3.142857143..
1163
1164   my $a = $x->accuracy() || 0;
1165   if ($a != 0 || !$MBI->_is_one($x->{_d}))
1166     {
1167     # n/d
1168     return Math::BigFloat->new($x->{sign} . $MBI->_str($x->{_n}))->bdiv( $MBI->_str($x->{_d}), $x->accuracy());
1169     }
1170   # just n
1171   Math::BigFloat->new($x->{sign} . $MBI->_str($x->{_n}));
1172   }
1173
1174 sub broot
1175   {
1176   # set up parameters
1177   my ($self,$x,$y,@r) = (ref($_[0]),@_);
1178   # objectify is costly, so avoid it
1179   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1180     {
1181     ($self,$x,$y,@r) = objectify(2,@_);
1182     }
1183
1184   if ($x->is_int() && $y->is_int())
1185     {
1186     return $self->new($x->as_number()->broot($y->as_number(),@r));
1187     }
1188
1189   # do it with floats
1190   $x->_new_from_float( $x->_as_float()->broot($y,@r) );
1191   }
1192
1193 sub bmodpow
1194   {
1195   # set up parameters
1196   my ($self,$x,$y,$m,@r) = (ref($_[0]),@_);
1197   # objectify is costly, so avoid it
1198   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1199     {
1200     ($self,$x,$y,$m,@r) = objectify(3,@_);
1201     }
1202
1203   # $x or $y or $m are NaN or +-inf => NaN
1204   return $x->bnan()
1205    if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/ ||
1206    $m->{sign} !~ /^[+-]$/;
1207
1208   if ($x->is_int() && $y->is_int() && $m->is_int())
1209     {
1210     return $self->new($x->as_number()->bmodpow($y->as_number(),$m,@r));
1211     }
1212
1213   warn ("bmodpow() not fully implemented");
1214   $x->bnan();
1215   }
1216
1217 sub bmodinv
1218   {
1219   # set up parameters
1220   my ($self,$x,$y,@r) = (ref($_[0]),@_);
1221   # objectify is costly, so avoid it
1222   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1223     {
1224     ($self,$x,$y,@r) = objectify(2,@_);
1225     }
1226
1227   # $x or $y are NaN or +-inf => NaN
1228   return $x->bnan() 
1229    if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/;
1230
1231   if ($x->is_int() && $y->is_int())
1232     {
1233     return $self->new($x->as_number()->bmodinv($y->as_number(),@r));
1234     }
1235
1236   warn ("bmodinv() not fully implemented");
1237   $x->bnan();
1238   }
1239
1240 sub bsqrt
1241   {
1242   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
1243
1244   return $x->bnan() if $x->{sign} !~ /^[+]/;    # NaN, -inf or < 0
1245   return $x if $x->{sign} eq '+inf';            # sqrt(inf) == inf
1246   return $x->round(@r) if $x->is_zero() || $x->is_one();
1247
1248   local $Math::BigFloat::upgrade = undef;
1249   local $Math::BigFloat::downgrade = undef;
1250   local $Math::BigFloat::precision = undef;
1251   local $Math::BigFloat::accuracy = undef;
1252   local $Math::BigInt::upgrade = undef;
1253   local $Math::BigInt::precision = undef;
1254   local $Math::BigInt::accuracy = undef;
1255
1256   $x->{_n} = _float_from_part( $x->{_n} )->bsqrt();
1257   $x->{_d} = _float_from_part( $x->{_d} )->bsqrt();
1258
1259   # XXX TODO: we probably can optimze this:
1260
1261   # if sqrt(D) was not integer
1262   if ($x->{_d}->{_es} ne '+')
1263     {
1264     $x->{_n}->blsft($x->{_d}->exponent()->babs(),10);   # 7.1/4.51 => 7.1/45.1
1265     $x->{_d} = $MBI->_copy( $x->{_d}->{_m} );           # 7.1/45.1 => 71/45.1
1266     }
1267   # if sqrt(N) was not integer
1268   if ($x->{_n}->{_es} ne '+')
1269     {
1270     $x->{_d}->blsft($x->{_n}->exponent()->babs(),10);   # 71/45.1 => 710/45.1
1271     $x->{_n} = $MBI->_copy( $x->{_n}->{_m} );           # 710/45.1 => 710/451
1272     }
1273
1274   # convert parts to $MBI again 
1275   $x->{_n} = $MBI->_lsft( $MBI->_copy( $x->{_n}->{_m} ), $x->{_n}->{_e}, 10)
1276     if ref($x->{_n}) ne $MBI && ref($x->{_n}) ne 'ARRAY';
1277   $x->{_d} = $MBI->_lsft( $MBI->_copy( $x->{_d}->{_m} ), $x->{_d}->{_e}, 10)
1278     if ref($x->{_d}) ne $MBI && ref($x->{_d}) ne 'ARRAY';
1279
1280   $x->bnorm()->round(@r);
1281   }
1282
1283 sub blsft
1284   {
1285   my ($self,$x,$y,$b,@r) = objectify(3,@_);
1286  
1287   $b = 2 unless defined $b;
1288   $b = $self->new($b) unless ref ($b);
1289   $x->bmul( $b->copy()->bpow($y), @r);
1290   $x;
1291   }
1292
1293 sub brsft
1294   {
1295   my ($self,$x,$y,$b,@r) = objectify(3,@_);
1296
1297   $b = 2 unless defined $b;
1298   $b = $self->new($b) unless ref ($b);
1299   $x->bdiv( $b->copy()->bpow($y), @r);
1300   $x;
1301   }
1302
1303 ##############################################################################
1304 # round
1305
1306 sub round
1307   {
1308   $_[0];
1309   }
1310
1311 sub bround
1312   {
1313   $_[0];
1314   }
1315
1316 sub bfround
1317   {
1318   $_[0];
1319   }
1320
1321 ##############################################################################
1322 # comparing
1323
1324 sub bcmp
1325   {
1326   # compare two signed numbers 
1327   
1328   # set up parameters
1329   my ($self,$x,$y) = (ref($_[0]),@_);
1330   # objectify is costly, so avoid it
1331   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1332     {
1333     ($self,$x,$y) = objectify(2,@_);
1334     }
1335
1336   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
1337     {
1338     # handle +-inf and NaN
1339     return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
1340     return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
1341     return +1 if $x->{sign} eq '+inf';
1342     return -1 if $x->{sign} eq '-inf';
1343     return -1 if $y->{sign} eq '+inf';
1344     return +1;
1345     }
1346   # check sign for speed first
1347   return 1 if $x->{sign} eq '+' && $y->{sign} eq '-';   # does also 0 <=> -y
1348   return -1 if $x->{sign} eq '-' && $y->{sign} eq '+';  # does also -x <=> 0
1349
1350   # shortcut
1351   my $xz = $MBI->_is_zero($x->{_n});
1352   my $yz = $MBI->_is_zero($y->{_n});
1353   return 0 if $xz && $yz;                               # 0 <=> 0
1354   return -1 if $xz && $y->{sign} eq '+';                # 0 <=> +y
1355   return 1 if $yz && $x->{sign} eq '+';                 # +x <=> 0
1356  
1357   my $t = $MBI->_mul( $MBI->_copy($x->{_n}), $y->{_d});
1358   my $u = $MBI->_mul( $MBI->_copy($y->{_n}), $x->{_d});
1359
1360   my $cmp = $MBI->_acmp($t,$u);                         # signs are equal
1361   $cmp = -$cmp if $x->{sign} eq '-';                    # both are '-' => reverse
1362   $cmp;
1363   }
1364
1365 sub bacmp
1366   {
1367   # compare two numbers (as unsigned)
1368  
1369   # set up parameters
1370   my ($self,$x,$y) = (ref($_[0]),@_);
1371   # objectify is costly, so avoid it
1372   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1373     {
1374     ($self,$x,$y) = objectify(2,$class,@_);
1375     }
1376
1377   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
1378     {
1379     # handle +-inf and NaN
1380     return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
1381     return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
1382     return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/;
1383     return -1;
1384     }
1385
1386   my $t = $MBI->_mul( $MBI->_copy($x->{_n}), $y->{_d});
1387   my $u = $MBI->_mul( $MBI->_copy($y->{_n}), $x->{_d});
1388   $MBI->_acmp($t,$u);                                   # ignore signs
1389   }
1390
1391 ##############################################################################
1392 # output conversation
1393
1394 sub numify
1395   {
1396   # convert 17/8 => float (aka 2.125)
1397   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1398  
1399   return $x->bstr() if $x->{sign} !~ /^[+-]$/;  # inf, NaN, etc
1400
1401   # N/1 => N
1402   my $neg = ''; $neg = '-' if $x->{sign} eq '-';
1403   return $neg . $MBI->_num($x->{_n}) if $MBI->_is_one($x->{_d});
1404
1405   $x->_as_float()->numify() + 0.0;
1406   }
1407
1408 sub as_number
1409   {
1410   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1411
1412   # NaN, inf etc
1413   return Math::BigInt->new($x->{sign}) if $x->{sign} !~ /^[+-]$/;
1414  
1415   my $u = Math::BigInt->bzero();
1416   $u->{sign} = $x->{sign};
1417   $u->{value} = $MBI->_div( $MBI->_copy($x->{_n}), $x->{_d});   # 22/7 => 3
1418   $u;
1419   }
1420
1421 sub as_bin
1422   {
1423   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1424
1425   return $x unless $x->is_int();
1426
1427   my $s = $x->{sign}; $s = '' if $s eq '+';
1428   $s . $MBI->_as_bin($x->{_n});
1429   }
1430
1431 sub as_hex
1432   {
1433   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1434
1435   return $x unless $x->is_int();
1436
1437   my $s = $x->{sign}; $s = '' if $s eq '+';
1438   $s . $MBI->_as_hex($x->{_n});
1439   }
1440
1441 sub as_oct
1442   {
1443   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1444
1445   return $x unless $x->is_int();
1446
1447   my $s = $x->{sign}; $s = '' if $s eq '+';
1448   $s . $MBI->_as_oct($x->{_n});
1449   }
1450
1451 ##############################################################################
1452
1453 sub from_hex
1454   {
1455   my $class = shift;
1456
1457   $class->new(@_);
1458   }
1459
1460 sub from_bin
1461   {
1462   my $class = shift;
1463
1464   $class->new(@_);
1465   }
1466
1467 sub from_oct
1468   {
1469   my $class = shift;
1470
1471   my @parts;
1472   for my $c (@_)
1473     {
1474     push @parts, Math::BigInt->from_oct($c);
1475     }
1476   $class->new ( @parts );
1477   }
1478
1479 ##############################################################################
1480 # import
1481
1482 sub import
1483   {
1484   my $self = shift;
1485   my $l = scalar @_;
1486   my $lib = ''; my @a;
1487   my $try = 'try';
1488
1489   for ( my $i = 0; $i < $l ; $i++)
1490     {
1491     if ( $_[$i] eq ':constant' )
1492       {
1493       # this rest causes overlord er load to step in
1494       overload::constant float => sub { $self->new(shift); };
1495       }
1496 #    elsif ($_[$i] eq 'upgrade')
1497 #      {
1498 #     # this causes upgrading
1499 #      $upgrade = $_[$i+1];             # or undef to disable
1500 #      $i++;
1501 #      }
1502     elsif ($_[$i] eq 'downgrade')
1503       {
1504       # this causes downgrading
1505       $downgrade = $_[$i+1];            # or undef to disable
1506       $i++;
1507       }
1508     elsif ($_[$i] =~ /^(lib|try|only)\z/)
1509       {
1510       $lib = $_[$i+1] || '';            # default Calc
1511       $try = $1;                        # lib, try or only
1512       $i++;
1513       }
1514     elsif ($_[$i] eq 'with')
1515       {
1516       # this argument is no longer used
1517       #$MBI = $_[$i+1] || 'Math::BigInt::Calc'; # default Math::BigInt::Calc
1518       $i++;
1519       }
1520     else
1521       {
1522       push @a, $_[$i];
1523       }
1524     }
1525   require Math::BigInt;
1526
1527   # let use Math::BigInt lib => 'GMP'; use Math::BigRat; still have GMP
1528   if ($lib ne '')
1529     {
1530     my @c = split /\s*,\s*/, $lib;
1531     foreach (@c)
1532       {
1533       $_ =~ tr/a-zA-Z0-9://cd;                    # limit to sane characters
1534       }
1535     $lib = join(",", @c);
1536     }
1537   my @import = ('objectify');
1538   push @import, $try => $lib if $lib ne '';
1539
1540   # MBI already loaded, so feed it our lib arguments
1541   Math::BigInt->import( @import );
1542
1543   $MBI = Math::BigFloat->config()->{lib};
1544
1545   # register us with MBI to get notified of future lib changes
1546   Math::BigInt::_register_callback( $self, sub { $MBI = $_[0]; } );
1547   
1548   # any non :constant stuff is handled by our parent, Exporter (loaded
1549   # by Math::BigFloat, even if @_ is empty, to give it a chance
1550   $self->SUPER::import(@a);             # for subclasses
1551   $self->export_to_level(1,$self,@a);   # need this, too
1552   }
1553
1554 1;
1555
1556 __END__
1557
1558 =head1 NAME
1559
1560 Math::BigRat - Arbitrary big rational numbers
1561
1562 =head1 SYNOPSIS
1563
1564         use Math::BigRat;
1565
1566         my $x = Math::BigRat->new('3/7'); $x += '5/9';
1567
1568         print $x->bstr(),"\n";
1569         print $x ** 2,"\n";
1570
1571         my $y = Math::BigRat->new('inf');
1572         print "$y ", ($y->is_inf ? 'is' : 'is not') , " infinity\n";
1573
1574         my $z = Math::BigRat->new(144); $z->bsqrt();
1575
1576 =head1 DESCRIPTION
1577
1578 Math::BigRat complements Math::BigInt and Math::BigFloat by providing support
1579 for arbitrary big rational numbers.
1580
1581 =head2 MATH LIBRARY
1582
1583 You can change the underlying module that does the low-level
1584 math operations by using:
1585
1586         use Math::BigRat try => 'GMP';
1587
1588 Note: This needs Math::BigInt::GMP installed.
1589
1590 The following would first try to find Math::BigInt::Foo, then
1591 Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
1592
1593         use Math::BigRat try => 'Foo,Math::BigInt::Bar';
1594
1595 If you want to get warned when the fallback occurs, replace "try" with
1596 "lib":
1597
1598         use Math::BigRat lib => 'Foo,Math::BigInt::Bar';
1599
1600 If you want the code to die instead, replace "try" with
1601 "only":
1602
1603         use Math::BigRat only => 'Foo,Math::BigInt::Bar';
1604
1605 =head1 METHODS
1606
1607 Any methods not listed here are derived from Math::BigFloat (or
1608 Math::BigInt), so make sure you check these two modules for further
1609 information.
1610
1611 =head2 new()
1612
1613         $x = Math::BigRat->new('1/3');
1614
1615 Create a new Math::BigRat object. Input can come in various forms:
1616
1617         $x = Math::BigRat->new(123);                            # scalars
1618         $x = Math::BigRat->new('inf');                          # infinity
1619         $x = Math::BigRat->new('123.3');                        # float
1620         $x = Math::BigRat->new('1/3');                          # simple string
1621         $x = Math::BigRat->new('1 / 3');                        # spaced
1622         $x = Math::BigRat->new('1 / 0.1');                      # w/ floats
1623         $x = Math::BigRat->new(Math::BigInt->new(3));           # BigInt
1624         $x = Math::BigRat->new(Math::BigFloat->new('3.1'));     # BigFloat
1625         $x = Math::BigRat->new(Math::BigInt::Lite->new('2'));   # BigLite
1626
1627         # You can also give D and N as different objects:
1628         $x = Math::BigRat->new(
1629                 Math::BigInt->new(-123),
1630                 Math::BigInt->new(7),
1631                 );                      # => -123/7
1632
1633 =head2 numerator()
1634
1635         $n = $x->numerator();
1636
1637 Returns a copy of the numerator (the part above the line) as signed BigInt.
1638
1639 =head2 denominator()
1640         
1641         $d = $x->denominator();
1642
1643 Returns a copy of the denominator (the part under the line) as positive BigInt.
1644
1645 =head2 parts()
1646
1647         ($n,$d) = $x->parts();
1648
1649 Return a list consisting of (signed) numerator and (unsigned) denominator as
1650 BigInts.
1651
1652 =head2 numify()
1653
1654         my $y = $x->numify();
1655
1656 Returns the object as a scalar. This will lose some data if the object
1657 cannot be represented by a normal Perl scalar (integer or float), so
1658 use as_int() instead.
1659
1660 This routine is automatically used whenever a scalar is required:
1661
1662         my $x = Math::BigRat->new('3/1');
1663         @array = (1,2,3);
1664         $y = $array[$x];                # set $y to 3
1665
1666 =head2 as_int()/as_number()
1667
1668         $x = Math::BigRat->new('13/7');
1669         print $x->as_int(),"\n";                # '1'
1670
1671 Returns a copy of the object as BigInt, truncated to an integer.
1672
1673 C<as_number()> is an alias for C<as_int()>.
1674
1675 =head2 as_hex()
1676
1677         $x = Math::BigRat->new('13');
1678         print $x->as_hex(),"\n";                # '0xd'
1679
1680 Returns the BigRat as hexadecimal string. Works only for integers. 
1681
1682 =head2 as_bin()
1683
1684         $x = Math::BigRat->new('13');
1685         print $x->as_bin(),"\n";                # '0x1101'
1686
1687 Returns the BigRat as binary string. Works only for integers. 
1688
1689 =head2 as_oct()
1690
1691         $x = Math::BigRat->new('13');
1692         print $x->as_oct(),"\n";                # '015'
1693
1694 Returns the BigRat as octal string. Works only for integers. 
1695
1696 =head2 from_hex()/from_bin()/from_oct()
1697
1698         my $h = Math::BigRat->from_hex('0x10');
1699         my $b = Math::BigRat->from_bin('0b10000000');
1700         my $o = Math::BigRat->from_oct('020');
1701
1702 Create a BigRat from an hexadecimal, binary or octal number
1703 in string form.
1704
1705 =head2 length()
1706
1707         $len = $x->length();
1708
1709 Return the length of $x in digitis for integer values.
1710
1711 =head2 digit()
1712
1713         print Math::BigRat->new('123/1')->digit(1);     # 1
1714         print Math::BigRat->new('123/1')->digit(-1);    # 3
1715
1716 Return the N'ths digit from X when X is an integer value.
1717
1718 =head2 bnorm()
1719
1720         $x->bnorm();
1721
1722 Reduce the number to the shortest form. This routine is called
1723 automatically whenever it is needed.
1724
1725 =head2 bfac()
1726
1727         $x->bfac();
1728
1729 Calculates the factorial of $x. For instance:
1730
1731         print Math::BigRat->new('3/1')->bfac(),"\n";    # 1*2*3
1732         print Math::BigRat->new('5/1')->bfac(),"\n";    # 1*2*3*4*5
1733
1734 Works currently only for integers.
1735
1736 =head2 bround()/round()/bfround()
1737
1738 Are not yet implemented.
1739
1740 =head2 bmod()
1741
1742         use Math::BigRat;
1743         my $x = Math::BigRat->new('7/4');
1744         my $y = Math::BigRat->new('4/3');
1745         print $x->bmod($y);
1746
1747 Set $x to the remainder of the division of $x by $y.
1748
1749 =head2 bneg()
1750
1751         $x->bneg();
1752
1753 Used to negate the object in-place.
1754
1755 =head2 is_one()
1756
1757         print "$x is 1\n" if $x->is_one();
1758
1759 Return true if $x is exactly one, otherwise false.
1760
1761 =head2 is_zero()
1762
1763         print "$x is 0\n" if $x->is_zero();
1764
1765 Return true if $x is exactly zero, otherwise false.
1766
1767 =head2 is_pos()/is_positive()
1768
1769         print "$x is >= 0\n" if $x->is_positive();
1770
1771 Return true if $x is positive (greater than or equal to zero), otherwise
1772 false. Please note that '+inf' is also positive, while 'NaN' and '-inf' aren't.
1773
1774 C<is_positive()> is an alias for C<is_pos()>.
1775
1776 =head2 is_neg()/is_negative()
1777
1778         print "$x is < 0\n" if $x->is_negative();
1779
1780 Return true if $x is negative (smaller than zero), otherwise false. Please
1781 note that '-inf' is also negative, while 'NaN' and '+inf' aren't.
1782
1783 C<is_negative()> is an alias for C<is_neg()>.
1784
1785 =head2 is_int()
1786
1787         print "$x is an integer\n" if $x->is_int();
1788
1789 Return true if $x has a denominator of 1 (e.g. no fraction parts), otherwise
1790 false. Please note that '-inf', 'inf' and 'NaN' aren't integer.
1791
1792 =head2 is_odd()
1793
1794         print "$x is odd\n" if $x->is_odd();
1795
1796 Return true if $x is odd, otherwise false.
1797
1798 =head2 is_even()
1799
1800         print "$x is even\n" if $x->is_even();
1801
1802 Return true if $x is even, otherwise false.
1803
1804 =head2 bceil()
1805
1806         $x->bceil();
1807
1808 Set $x to the next bigger integer value (e.g. truncate the number to integer
1809 and then increment it by one).
1810
1811 =head2 bfloor()
1812         
1813         $x->bfloor();
1814
1815 Truncate $x to an integer value.
1816
1817 =head2 bsqrt()
1818         
1819         $x->bsqrt();
1820
1821 Calculate the square root of $x.
1822
1823 =head2 broot()
1824         
1825         $x->broot($n);
1826
1827 Calculate the N'th root of $x.
1828
1829 =head2 badd()/bmul()/bsub()/bdiv()/bdec()/binc()
1830
1831 Please see the documentation in L<Math::BigInt>.
1832
1833 =head2 copy()
1834
1835         my $z = $x->copy();
1836
1837 Makes a deep copy of the object.
1838
1839 Please see the documentation in L<Math::BigInt> for further details.
1840
1841 =head2 bstr()/bsstr()
1842
1843         my $x = Math::BigInt->new('8/4');
1844         print $x->bstr(),"\n";                  # prints 1/2
1845         print $x->bsstr(),"\n";                 # prints 1/2
1846
1847 Return a string representating this object.
1848
1849 =head2 bacmp()/bcmp()
1850
1851 Used to compare numbers.
1852
1853 Please see the documentation in L<Math::BigInt> for further details.
1854
1855 =head2 blsft()/brsft()
1856
1857 Used to shift numbers left/right.
1858
1859 Please see the documentation in L<Math::BigInt> for further details.
1860
1861 =head2 bpow()
1862
1863         $x->bpow($y);
1864
1865 Compute $x ** $y.
1866
1867 Please see the documentation in L<Math::BigInt> for further details.
1868
1869 =head2 bexp()
1870
1871         $x->bexp($accuracy);            # calculate e ** X
1872
1873 Calculates two integers A and B so that A/B is equal to C<e ** $x>, where C<e> is
1874 Euler's number.
1875
1876 This method was added in v0.20 of Math::BigRat (May 2007).
1877
1878 See also L<blog()>.
1879
1880 =head2 bnok()
1881
1882         $x->bnok($y);              # x over y (binomial coefficient n over k)
1883
1884 Calculates the binomial coefficient n over k, also called the "choose"
1885 function. The result is equivalent to:
1886
1887         ( n )      n!
1888         | - |  = -------
1889         ( k )    k!(n-k)!
1890
1891 This method was added in v0.20 of Math::BigRat (May 2007).
1892
1893 =head2 config()
1894
1895         use Data::Dumper;
1896
1897         print Dumper ( Math::BigRat->config() );
1898         print Math::BigRat->config()->{lib},"\n";
1899
1900 Returns a hash containing the configuration, e.g. the version number, lib
1901 loaded etc. The following hash keys are currently filled in with the
1902 appropriate information.
1903
1904         key             RO/RW   Description
1905                                 Example
1906         ============================================================
1907         lib             RO      Name of the Math library
1908                                 Math::BigInt::Calc
1909         lib_version     RO      Version of 'lib'
1910                                 0.30
1911         class           RO      The class of config you just called
1912                                 Math::BigRat
1913         version         RO      version number of the class you used
1914                                 0.10
1915         upgrade         RW      To which class numbers are upgraded
1916                                 undef
1917         downgrade       RW      To which class numbers are downgraded
1918                                 undef
1919         precision       RW      Global precision
1920                                 undef
1921         accuracy        RW      Global accuracy
1922                                 undef
1923         round_mode      RW      Global round mode
1924                                 even
1925         div_scale       RW      Fallback accuracy for div
1926                                 40
1927         trap_nan        RW      Trap creation of NaN (undef = no)
1928                                 undef
1929         trap_inf        RW      Trap creation of +inf/-inf (undef = no)
1930                                 undef
1931
1932 By passing a reference to a hash you may set the configuration values. This
1933 works only for values that a marked with a C<RW> above, anything else is
1934 read-only.
1935
1936 =head1 BUGS
1937
1938 Some things are not yet implemented, or only implemented half-way:
1939
1940 =over 2
1941
1942 =item inf handling (partial)
1943
1944 =item NaN handling (partial)
1945
1946 =item rounding (not implemented except for bceil/bfloor)
1947
1948 =item $x ** $y where $y is not an integer
1949
1950 =item bmod(), blog(), bmodinv() and bmodpow() (partial)
1951
1952 =back
1953
1954 =head1 LICENSE
1955
1956 This program is free software; you may redistribute it and/or modify it under
1957 the same terms as Perl itself.
1958
1959 =head1 SEE ALSO
1960
1961 L<Math::BigFloat> and L<Math::Big> as well as L<Math::BigInt::BitVect>,
1962 L<Math::BigInt::Pari> and  L<Math::BigInt::GMP>.
1963
1964 See L<http://search.cpan.org/search?dist=bignum> for a way to use
1965 Math::BigRat.
1966
1967 The package at L<http://search.cpan.org/search?dist=Math%3A%3ABigRat>
1968 may contain more documentation and examples as well as testcases.
1969
1970 =head1 AUTHORS
1971
1972 (C) by Tels L<http://bloodgate.com/> 2001 - 2007.
1973
1974 =cut