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