This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Fixes to compile Perl with g++ and DEBUGGING.
[perl5.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 require 5.005_03;
17 use strict;
18
19 use Math::BigFloat;
20 use vars qw($VERSION @ISA $upgrade $downgrade
21             $accuracy $precision $round_mode $div_scale $_trap_nan $_trap_inf);
22
23 @ISA = qw(Math::BigFloat);
24
25 $VERSION = '0.15';
26
27 use overload;                   # inherit overload from Math::BigFloat
28
29 BEGIN
30   { 
31   *objectify = \&Math::BigInt::objectify;       # inherit this from BigInt
32   *AUTOLOAD = \&Math::BigFloat::AUTOLOAD;       # can't inherit AUTOLOAD
33   # we inherit these from BigFloat because currently it is not possible
34   # that MBF has a different $MBI variable than we, because MBF also uses
35   # Math::BigInt::config->('lib'); (there is always only one library loaded)
36   *_e_add = \&Math::BigFloat::_e_add;
37   *_e_sub = \&Math::BigFloat::_e_sub;
38   *as_int = \&as_number;
39   *is_pos = \&is_positive;
40   *is_neg = \&is_negative;
41   }
42
43 ##############################################################################
44 # Global constants and flags. Access these only via the accessor methods!
45
46 $accuracy = $precision = undef;
47 $round_mode = 'even';
48 $div_scale = 40;
49 $upgrade = undef;
50 $downgrade = undef;
51
52 # These are internally, and not to be used from the outside at all!
53
54 $_trap_nan = 0;                         # are NaNs ok? set w/ config()
55 $_trap_inf = 0;                         # are infs ok? set w/ config()
56
57 # the package we are using for our private parts, defaults to:
58 # Math::BigInt->config()->{lib}
59 my $MBI = 'Math::BigInt::Calc';
60
61 my $nan = 'NaN';
62 my $class = 'Math::BigRat';
63
64 sub isa
65   {
66   return 0 if $_[1] =~ /^Math::Big(Int|Float)/;         # we aren't
67   UNIVERSAL::isa(@_);
68   }
69
70 ##############################################################################
71
72 sub _new_from_float
73   {
74   # turn a single float input into a rational number (like '0.1')
75   my ($self,$f) = @_;
76
77   return $self->bnan() if $f->is_nan();
78   return $self->binf($f->{sign}) if $f->{sign} =~ /^[+-]inf$/;
79
80   $self->{_n} = $MBI->_copy( $f->{_m} );        # mantissa
81   $self->{_d} = $MBI->_one();
82   $self->{sign} = $f->{sign} || '+';
83   if ($f->{_es} eq '-')
84     {
85     # something like Math::BigRat->new('0.1');
86     # 1 / 1 => 1/10
87     $MBI->_lsft ( $self->{_d}, $f->{_e} ,10);   
88     }
89   else
90     {
91     # something like Math::BigRat->new('10');
92     # 1 / 1 => 10/1
93     $MBI->_lsft ( $self->{_n}, $f->{_e} ,10) unless 
94       $MBI->_is_zero($f->{_e}); 
95     }
96   $self;
97   }
98
99 sub new
100   {
101   # create a Math::BigRat
102   my $class = shift;
103
104   my ($n,$d) = @_;
105
106   my $self = { }; bless $self,$class;
107  
108   # input like (BigInt) or (BigFloat):
109   if ((!defined $d) && (ref $n) && (!$n->isa('Math::BigRat')))
110     {
111     if ($n->isa('Math::BigFloat'))
112       {
113       $self->_new_from_float($n);
114       }
115     if ($n->isa('Math::BigInt'))
116       {
117       # TODO: trap NaN, inf
118       $self->{_n} = $MBI->_copy($n->{value});           # "mantissa" = N
119       $self->{_d} = $MBI->_one();                       # d => 1
120       $self->{sign} = $n->{sign};
121       }
122     if ($n->isa('Math::BigInt::Lite'))
123       {
124       # TODO: trap NaN, inf
125       $self->{sign} = '+'; $self->{sign} = '-' if $$n < 0;
126       $self->{_n} = $MBI->_new(abs($$n));               # "mantissa" = N
127       $self->{_d} = $MBI->_one();                       # d => 1
128       }
129     return $self->bnorm();                              # normalize (120/1 => 12/10)
130     }
131
132   # input like (BigInt,BigInt) or (BigLite,BigLite):
133   if (ref($d) && ref($n))
134     {
135     # do N first (for $self->{sign}):
136     if ($n->isa('Math::BigInt'))
137       {
138       # TODO: trap NaN, inf
139       $self->{_n} = $MBI->_copy($n->{value});           # "mantissa" = N
140       $self->{sign} = $n->{sign};
141       }
142     elsif ($n->isa('Math::BigInt::Lite'))
143       {
144       # TODO: trap NaN, inf
145       $self->{sign} = '+'; $self->{sign} = '-' if $$n < 0;
146       $self->{_n} = $MBI->_new(abs($$n));               # "mantissa" = $n
147       }
148     else
149       {
150       require Carp;
151       Carp::croak(ref($n) . " is not a recognized object format for Math::BigRat->new");
152       }
153     # now D:
154     if ($d->isa('Math::BigInt'))
155       {
156       # TODO: trap NaN, inf
157       $self->{_d} = $MBI->_copy($d->{value});           # "mantissa" = D
158       # +/+ or -/- => +, +/- or -/+ => -
159       $self->{sign} = $d->{sign} ne $self->{sign} ? '-' : '+';
160       }
161     elsif ($d->isa('Math::BigInt::Lite'))
162       {
163       # TODO: trap NaN, inf
164       $self->{_d} = $MBI->_new(abs($$d));               # "mantissa" = D
165       my $ds = '+'; $ds = '-' if $$d < 0;
166       # +/+ or -/- => +, +/- or -/+ => -
167       $self->{sign} = $ds ne $self->{sign} ? '-' : '+';
168       }
169     else
170       {
171       require Carp;
172       Carp::croak(ref($d) . " is not a recognized object format for Math::BigRat->new");
173       }
174     return $self->bnorm();                              # normalize (120/1 => 12/10)
175     }
176   return $n->copy() if ref $n;                          # already a BigRat
177
178   if (!defined $n)
179     {
180     $self->{_n} = $MBI->_zero();                        # undef => 0
181     $self->{_d} = $MBI->_one();
182     $self->{sign} = '+';
183     return $self;
184     }
185
186   # string input with / delimiter
187   if ($n =~ /\s*\/\s*/)
188     {
189     return $class->bnan() if $n =~ /\/.*\//;    # 1/2/3 isn't valid
190     return $class->bnan() if $n =~ /\/\s*$/;    # 1/ isn't valid
191     ($n,$d) = split (/\//,$n);
192     # try as BigFloats first
193     if (($n =~ /[\.eE]/) || ($d =~ /[\.eE]/))
194       {
195       local $Math::BigFloat::accuracy = undef;
196       local $Math::BigFloat::precision = undef;
197
198       # one of them looks like a float 
199       my $nf = Math::BigFloat->new($n,undef,undef);
200       $self->{sign} = '+';
201       return $self->bnan() if $nf->is_nan();
202
203       $self->{_n} = $MBI->_copy( $nf->{_m} );   # get mantissa
204
205       # now correct $self->{_n} due to $n
206       my $f = Math::BigFloat->new($d,undef,undef);
207       return $self->bnan() if $f->is_nan();
208       $self->{_d} = $MBI->_copy( $f->{_m} );
209
210       # calculate the difference between nE and dE
211       # XXX TODO: check that exponent() makes a copy to avoid copy()
212       my $diff_e = $nf->exponent()->copy()->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*(\d+)\z/)                            # first part ok?
232         {
233         $self->{sign} = $1 || '+';                              # no sign => '+'
234         $self->{_n} = $MBI->_new($2 || 0);
235         }
236
237       if ($d =~ /^([+-]?)0*(\d+)\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*(\d+)\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   my $cfg = $class->SUPER::config(@_);
342
343   # now we need only to override the ones that are different from our parent
344   $cfg->{class} = $class;
345   $cfg->{with} = $MBI;
346   $cfg;
347   }
348
349 ##############################################################################
350
351 sub bstr
352   {
353   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
354
355   if ($x->{sign} !~ /^[+-]$/)           # inf, NaN etc
356     {
357     my $s = $x->{sign}; $s =~ s/^\+//;  # +inf => inf
358     return $s;
359     }
360
361   my $s = ''; $s = $x->{sign} if $x->{sign} ne '+';     # '+3/2' => '3/2'
362
363   return $s . $MBI->_str($x->{_n}) if $MBI->_is_one($x->{_d});
364   $s . $MBI->_str($x->{_n}) . '/' . $MBI->_str($x->{_d});
365   }
366
367 sub bsstr
368   {
369   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
370
371   if ($x->{sign} !~ /^[+-]$/)           # inf, NaN etc
372     {
373     my $s = $x->{sign}; $s =~ s/^\+//;  # +inf => inf
374     return $s;
375     }
376   
377   my $s = ''; $s = $x->{sign} if $x->{sign} ne '+';     # +3 vs 3
378   $s . $MBI->_str($x->{_n}) . '/' . $MBI->_str($x->{_d});
379   }
380
381 sub bnorm
382   {
383   # reduce the number to the shortest form
384   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
385
386   # Both parts must be objects of whatever we are using today.
387   # Second check because Calc.pm has ARRAY res as unblessed objects.
388   if (ref($x->{_n}) ne $MBI && ref($x->{_n}) ne 'ARRAY')
389     {
390     require Carp; Carp::croak ("n is not $MBI but (".ref($x->{_n}).') in bnorm()');
391     }
392   if (ref($x->{_d}) ne $MBI && ref($x->{_d}) ne 'ARRAY')
393     {
394     require Carp; Carp::croak ("d is not $MBI but (".ref($x->{_d}).') in bnorm()');
395     }
396
397   # no normalize for NaN, inf etc.
398   return $x if $x->{sign} !~ /^[+-]$/;
399
400   # normalize zeros to 0/1
401   if ($MBI->_is_zero($x->{_n}))
402     {
403     $x->{sign} = '+';                                   # never leave a -0
404     $x->{_d} = $MBI->_one() unless $MBI->_is_one($x->{_d});
405     return $x;
406     }
407
408   return $x if $MBI->_is_one($x->{_d});                 # no need to reduce
409
410   # reduce other numbers
411   my $gcd = $MBI->_copy($x->{_n});
412   $gcd = $MBI->_gcd($gcd,$x->{_d});
413   
414   if (!$MBI->_is_one($gcd))
415     {
416     $x->{_n} = $MBI->_div($x->{_n},$gcd);
417     $x->{_d} = $MBI->_div($x->{_d},$gcd);
418     }
419   $x;
420   }
421
422 ##############################################################################
423 # sign manipulation
424
425 sub bneg
426   {
427   # (BRAT or num_str) return BRAT
428   # negate number or make a negated number from string
429   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
430
431   return $x if $x->modify('bneg');
432
433   # for +0 dont negate (to have always normalized +0). Does nothing for 'NaN'
434   $x->{sign} =~ tr/+-/-+/ unless ($x->{sign} eq '+' && $MBI->_is_zero($x->{_n}));
435   $x;
436   }
437
438 ##############################################################################
439 # special values
440
441 sub _bnan
442   {
443   # used by parent class bnan() to initialize number to NaN
444   my $self = shift;
445
446   if ($_trap_nan)
447     {
448     require Carp;
449     my $class = ref($self);
450     # "$self" below will stringify the object, this blows up if $self is a
451     # partial object (happens under trap_nan), so fix it beforehand
452     $self->{_d} = $MBI->_zero() unless defined $self->{_d};
453     $self->{_n} = $MBI->_zero() unless defined $self->{_n};
454     Carp::croak ("Tried to set $self to NaN in $class\::_bnan()");
455     }
456   $self->{_n} = $MBI->_zero();
457   $self->{_d} = $MBI->_zero();
458   }
459
460 sub _binf
461   {
462   # used by parent class bone() to initialize number to +inf/-inf
463   my $self = shift;
464
465   if ($_trap_inf)
466     {
467     require Carp;
468     my $class = ref($self);
469     # "$self" below will stringify the object, this blows up if $self is a
470     # partial object (happens under trap_nan), so fix it beforehand
471     $self->{_d} = $MBI->_zero() unless defined $self->{_d};
472     $self->{_n} = $MBI->_zero() unless defined $self->{_n};
473     Carp::croak ("Tried to set $self to inf in $class\::_binf()");
474     }
475   $self->{_n} = $MBI->_zero();
476   $self->{_d} = $MBI->_zero();
477   }
478
479 sub _bone
480   {
481   # used by parent class bone() to initialize number to +1/-1
482   my $self = shift;
483   $self->{_n} = $MBI->_one();
484   $self->{_d} = $MBI->_one();
485   }
486
487 sub _bzero
488   {
489   # used by parent class bzero() to initialize number to 0
490   my $self = shift;
491   $self->{_n} = $MBI->_zero();
492   $self->{_d} = $MBI->_one();
493   }
494
495 ##############################################################################
496 # mul/add/div etc
497
498 sub badd
499   {
500   # add two rational numbers
501
502   # set up parameters
503   my ($self,$x,$y,@r) = (ref($_[0]),@_);
504   # objectify is costly, so avoid it
505   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
506     {
507     ($self,$x,$y,@r) = objectify(2,@_);
508     }
509
510   # +inf + +inf => +inf,  -inf + -inf => -inf
511   return $x->binf(substr($x->{sign},0,1))
512     if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
513
514   # +inf + -inf or -inf + +inf => NaN
515   return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
516
517   #  1   1    gcd(3,4) = 1    1*3 + 1*4    7
518   #  - + -                  = --------- = --                 
519   #  4   3                      4*3       12
520
521   # we do not compute the gcd() here, but simple do:
522   #  5   7    5*3 + 7*4   43
523   #  - + -  = --------- = --                 
524   #  4   3       4*3      12
525  
526   # and bnorm() will then take care of the rest
527
528   # 5 * 3
529   $x->{_n} = $MBI->_mul( $x->{_n}, $y->{_d});
530
531   # 7 * 4
532   my $m = $MBI->_mul( $MBI->_copy( $y->{_n} ), $x->{_d} );
533
534   # 5 * 3 + 7 * 4
535   ($x->{_n}, $x->{sign}) = _e_add( $x->{_n}, $m, $x->{sign}, $y->{sign});
536
537   # 4 * 3
538   $x->{_d} = $MBI->_mul( $x->{_d}, $y->{_d});
539
540   # normalize result, and possible round
541   $x->bnorm()->round(@r);
542   }
543
544 sub bsub
545   {
546   # subtract two rational numbers
547
548   # set up parameters
549   my ($self,$x,$y,@r) = (ref($_[0]),@_);
550   # objectify is costly, so avoid it
551   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
552     {
553     ($self,$x,$y,@r) = objectify(2,@_);
554     }
555
556   # flip sign of $x, call badd(), then flip sign of result
557   $x->{sign} =~ tr/+-/-+/
558     unless $x->{sign} eq '+' && $MBI->_is_zero($x->{_n});       # not -0
559   $x->badd($y,@r);                              # does norm and round
560   $x->{sign} =~ tr/+-/-+/ 
561     unless $x->{sign} eq '+' && $MBI->_is_zero($x->{_n});       # not -0
562   $x;
563   }
564
565 sub bmul
566   {
567   # multiply two rational numbers
568   
569   # set up parameters
570   my ($self,$x,$y,@r) = (ref($_[0]),@_);
571   # objectify is costly, so avoid it
572   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
573     {
574     ($self,$x,$y,@r) = objectify(2,@_);
575     }
576
577   return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
578
579   # inf handling
580   if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/))
581     {
582     return $x->bnan() if $x->is_zero() || $y->is_zero();
583     # result will always be +-inf:
584     # +inf * +/+inf => +inf, -inf * -/-inf => +inf
585     # +inf * -/-inf => -inf, -inf * +/+inf => -inf
586     return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
587     return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
588     return $x->binf('-');
589     }
590
591   # x== 0 # also: or y == 1 or y == -1
592   return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
593
594   # XXX TODO:
595   # According to Knuth, this can be optimized by doing gcd twice (for d and n)
596   # and reducing in one step. This would save us the bnorm() at the end.
597
598   #  1   2    1 * 2    2    1
599   #  - * - =  -----  = -  = -
600   #  4   3    4 * 3    12   6
601   
602   $x->{_n} = $MBI->_mul( $x->{_n}, $y->{_n});
603   $x->{_d} = $MBI->_mul( $x->{_d}, $y->{_d});
604
605   # compute new sign
606   $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
607
608   $x->bnorm()->round(@r);
609   }
610
611 sub bdiv
612   {
613   # (dividend: BRAT or num_str, divisor: BRAT or num_str) return
614   # (BRAT,BRAT) (quo,rem) or BRAT (only rem)
615
616   # set up parameters
617   my ($self,$x,$y,@r) = (ref($_[0]),@_);
618   # objectify is costly, so avoid it
619   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
620     {
621     ($self,$x,$y,@r) = objectify(2,@_);
622     }
623
624   return $self->_div_inf($x,$y)
625    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
626
627   # x== 0 # also: or y == 1 or y == -1
628   return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
629
630   # XXX TODO: list context, upgrade
631   # According to Knuth, this can be optimized by doing gcd twice (for d and n)
632   # and reducing in one step. This would save us the bnorm() at the end.
633
634   # 1     1    1   3
635   # -  /  - == - * -
636   # 4     3    4   1
637   
638   $x->{_n} = $MBI->_mul( $x->{_n}, $y->{_d});
639   $x->{_d} = $MBI->_mul( $x->{_d}, $y->{_n});
640
641   # compute new sign 
642   $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
643
644   $x->bnorm()->round(@r);
645   $x;
646   }
647
648 sub bmod
649   {
650   # compute "remainder" (in Perl way) of $x / $y
651
652   # set up parameters
653   my ($self,$x,$y,@r) = (ref($_[0]),@_);
654   # objectify is costly, so avoid it
655   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
656     {
657     ($self,$x,$y,@r) = objectify(2,@_);
658     }
659
660   return $self->_div_inf($x,$y)
661    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
662
663   return $x if $x->is_zero();           # 0 / 7 = 0, mod 0
664
665   # compute $x - $y * floor($x/$y), keeping the sign of $x
666
667   # copy x to u, make it positive and then do a normal division ($u/$y)
668   my $u = bless { sign => '+' }, $self;
669   $u->{_n} = $MBI->_mul( $MBI->_copy($x->{_n}), $y->{_d} );
670   $u->{_d} = $MBI->_mul( $MBI->_copy($x->{_d}), $y->{_n} );
671   
672   # compute floor(u)
673   if (! $MBI->_is_one($u->{_d}))
674     {
675     $u->{_n} = $MBI->_div($u->{_n},$u->{_d});   # 22/7 => 3/1 w/ truncate
676     # no need to set $u->{_d} to 1, since below we set it to $y->{_d} anyway
677     }
678   
679   # now compute $y * $u
680   $u->{_d} = $MBI->_copy($y->{_d});             # 1 * $y->{_d}, see floor above
681   $u->{_n} = $MBI->_mul($u->{_n},$y->{_n});
682
683   my $xsign = $x->{sign}; $x->{sign} = '+';     # remember sign and make x positive
684   # compute $x - $u
685   $x->bsub($u);
686   $x->{sign} = $xsign;                          # put sign back
687
688   $x->bnorm()->round(@r);
689   }
690
691 ##############################################################################
692 # bdec/binc
693
694 sub bdec
695   {
696   # decrement value (subtract 1)
697   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
698
699   return $x if $x->{sign} !~ /^[+-]$/;  # NaN, inf, -inf
700
701   if ($x->{sign} eq '-')
702     {
703     $x->{_n} = $MBI->_add( $x->{_n}, $x->{_d});         # -5/2 => -7/2
704     }
705   else
706     {
707     if ($MBI->_acmp($x->{_n},$x->{_d}) < 0)             # n < d?
708       {
709       # 1/3 -- => -2/3
710       $x->{_n} = $MBI->_sub( $MBI->_copy($x->{_d}), $x->{_n});
711       $x->{sign} = '-';
712       }
713     else
714       {
715       $x->{_n} = $MBI->_sub($x->{_n}, $x->{_d});        # 5/2 => 3/2
716       }
717     }
718   $x->bnorm()->round(@r);
719   }
720
721 sub binc
722   {
723   # increment value (add 1)
724   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
725   
726   return $x if $x->{sign} !~ /^[+-]$/;  # NaN, inf, -inf
727
728   if ($x->{sign} eq '-')
729     {
730     if ($MBI->_acmp($x->{_n},$x->{_d}) < 0)
731       {
732       # -1/3 ++ => 2/3 (overflow at 0)
733       $x->{_n} = $MBI->_sub( $MBI->_copy($x->{_d}), $x->{_n});
734       $x->{sign} = '+';
735       }
736     else
737       {
738       $x->{_n} = $MBI->_sub($x->{_n}, $x->{_d});        # -5/2 => -3/2
739       }
740     }
741   else
742     {
743     $x->{_n} = $MBI->_add($x->{_n},$x->{_d});           # 5/2 => 7/2
744     }
745   $x->bnorm()->round(@r);
746   }
747
748 ##############################################################################
749 # is_foo methods (the rest is inherited)
750
751 sub is_int
752   {
753   # return true if arg (BRAT or num_str) is an integer
754   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
755
756   return 1 if ($x->{sign} =~ /^[+-]$/) &&       # NaN and +-inf aren't
757     $MBI->_is_one($x->{_d});                    # x/y && y != 1 => no integer
758   0;
759   }
760
761 sub is_zero
762   {
763   # return true if arg (BRAT or num_str) is zero
764   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
765
766   return 1 if $x->{sign} eq '+' && $MBI->_is_zero($x->{_n});
767   0;
768   }
769
770 sub is_one
771   {
772   # return true if arg (BRAT or num_str) is +1 or -1 if signis given
773   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
774
775   my $sign = $_[2] || ''; $sign = '+' if $sign ne '-';
776   return 1
777    if ($x->{sign} eq $sign && $MBI->_is_one($x->{_n}) && $MBI->_is_one($x->{_d}));
778   0;
779   }
780
781 sub is_odd
782   {
783   # return true if arg (BFLOAT or num_str) is odd or false if even
784   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
785
786   return 1 if ($x->{sign} =~ /^[+-]$/) &&               # NaN & +-inf aren't
787     ($MBI->_is_one($x->{_d}) && $MBI->_is_odd($x->{_n})); # x/2 is not, but 3/1
788   0;
789   }
790
791 sub is_even
792   {
793   # return true if arg (BINT or num_str) is even or false if odd
794   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
795
796   return 0 if $x->{sign} !~ /^[+-]$/;                   # NaN & +-inf aren't
797   return 1 if ($MBI->_is_one($x->{_d})                  # x/3 is never
798      && $MBI->_is_even($x->{_n}));                      # but 4/1 is
799   0;
800   }
801
802 ##############################################################################
803 # parts() and friends
804
805 sub numerator
806   {
807   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
808
809   # NaN, inf, -inf
810   return Math::BigInt->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
811
812   my $n = Math::BigInt->new($MBI->_str($x->{_n})); $n->{sign} = $x->{sign};
813   $n;
814   }
815
816 sub denominator
817   {
818   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
819
820   # NaN
821   return Math::BigInt->new($x->{sign}) if $x->{sign} eq 'NaN';
822   # inf, -inf
823   return Math::BigInt->bone() if $x->{sign} !~ /^[+-]$/;
824   
825   Math::BigInt->new($MBI->_str($x->{_d}));
826   }
827
828 sub parts
829   {
830   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
831
832   my $c = 'Math::BigInt';
833
834   return ($c->bnan(),$c->bnan()) if $x->{sign} eq 'NaN';
835   return ($c->binf(),$c->binf()) if $x->{sign} eq '+inf';
836   return ($c->binf('-'),$c->binf()) if $x->{sign} eq '-inf';
837
838   my $n = $c->new( $MBI->_str($x->{_n}));
839   $n->{sign} = $x->{sign};
840   my $d = $c->new( $MBI->_str($x->{_d}));
841   ($n,$d);
842   }
843
844 sub length
845   {
846   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
847
848   return $nan unless $x->is_int();
849   $MBI->_len($x->{_n});                         # length(-123/1) => length(123)
850   }
851
852 sub digit
853   {
854   my ($self,$x,$n) = ref($_[0]) ? (undef,$_[0],$_[1]) : objectify(1,@_);
855
856   return $nan unless $x->is_int();
857   $MBI->_digit($x->{_n},$n || 0);               # digit(-123/1,2) => digit(123,2)
858   }
859
860 ##############################################################################
861 # special calc routines
862
863 sub bceil
864   {
865   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
866
867   return $x if $x->{sign} !~ /^[+-]$/ ||        # not for NaN, inf
868             $MBI->_is_one($x->{_d});            # 22/1 => 22, 0/1 => 0
869
870   $x->{_n} = $MBI->_div($x->{_n},$x->{_d});     # 22/7 => 3/1 w/ truncate
871   $x->{_d} = $MBI->_one();                      # d => 1
872   $x->{_n} = $MBI->_inc($x->{_n})
873     if $x->{sign} eq '+';                       # +22/7 => 4/1
874   $x->{sign} = '+' if $MBI->_is_zero($x->{_n}); # -0 => 0
875   $x;
876   }
877
878 sub bfloor
879   {
880   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
881
882   return $x if $x->{sign} !~ /^[+-]$/ ||        # not for NaN, inf
883             $MBI->_is_one($x->{_d});            # 22/1 => 22, 0/1 => 0
884
885   $x->{_n} = $MBI->_div($x->{_n},$x->{_d});     # 22/7 => 3/1 w/ truncate
886   $x->{_d} = $MBI->_one();                      # d => 1
887   $x->{_n} = $MBI->_inc($x->{_n})
888     if $x->{sign} eq '-';                       # -22/7 => -4/1
889   $x;
890   }
891
892 sub bfac
893   {
894   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
895
896   # if $x is not an integer
897   if (($x->{sign} ne '+') || (!$MBI->_is_one($x->{_d})))
898     {
899     return $x->bnan();
900     }
901
902   $x->{_n} = $MBI->_fac($x->{_n});
903   # since _d is 1, we don't need to reduce/norm the result
904   $x->round(@r);
905   }
906
907 sub bpow
908   {
909   # power ($x ** $y)
910
911   # set up parameters
912   my ($self,$x,$y,@r) = (ref($_[0]),@_);
913   # objectify is costly, so avoid it
914   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
915     {
916     ($self,$x,$y,@r) = objectify(2,@_);
917     }
918
919   return $x if $x->{sign} =~ /^[+-]inf$/;       # -inf/+inf ** x
920   return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan;
921   return $x->bone(@r) if $y->is_zero();
922   return $x->round(@r) if $x->is_one() || $y->is_one();
923
924   if ($x->{sign} eq '-' && $MBI->_is_one($x->{_n}) && $MBI->_is_one($x->{_d}))
925     {
926     # if $x == -1 and odd/even y => +1/-1
927     return $y->is_odd() ? $x->round(@r) : $x->babs()->round(@r);
928     # my Casio FX-5500L has a bug here: -1 ** 2 is -1, but -1 * -1 is 1;
929     }
930   # 1 ** -y => 1 / (1 ** |y|)
931   # so do test for negative $y after above's clause
932
933   return $x->round(@r) if $x->is_zero();  # 0**y => 0 (if not y <= 0)
934
935   # shortcut y/1 (and/or x/1)
936   if ($MBI->_is_one($y->{_d}))
937     {
938     # shortcut for x/1 and y/1
939     if ($MBI->_is_one($x->{_d}))
940       {
941       $x->{_n} = $MBI->_pow($x->{_n},$y->{_n});         # x/1 ** y/1 => (x ** y)/1
942       if ($y->{sign} eq '-')
943         {
944         # 0.2 ** -3 => 1/(0.2 ** 3)
945         ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n});      # swap
946         }
947       # correct sign; + ** + => +
948       if ($x->{sign} eq '-')
949         {
950         # - * - => +, - * - * - => -
951         $x->{sign} = '+' if $MBI->_is_even($y->{_n});   
952         }
953       return $x->round(@r);
954       }
955     # x/z ** y/1
956     $x->{_n} = $MBI->_pow($x->{_n},$y->{_n});           # 5/2 ** y/1 => 5 ** y / 2 ** y
957     $x->{_d} = $MBI->_pow($x->{_d},$y->{_n});
958     if ($y->{sign} eq '-')
959       {
960       # 0.2 ** -3 => 1/(0.2 ** 3)
961       ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n});        # swap
962       }
963     # correct sign; + ** + => +
964     if ($x->{sign} eq '-')
965       {
966       # - * - => +, - * - * - => -
967       $x->{sign} = '+' if $MBI->_is_even($y->{_n});     
968       }
969     return $x->round(@r);
970     }
971
972   # regular calculation (this is wrong for d/e ** f/g)
973   my $pow2 = $self->bone();
974   my $y1 = $MBI->_div ( $MBI->_copy($y->{_n}), $y->{_d});
975   my $two = $MBI->_two();
976
977   while (!$MBI->_is_one($y1))
978     {
979     $pow2->bmul($x) if $MBI->_is_odd($y1);
980     $MBI->_div($y1, $two);
981     $x->bmul($x);
982     }
983   $x->bmul($pow2) unless $pow2->is_one();
984   # n ** -x => 1/n ** x
985   ($x->{_d},$x->{_n}) = ($x->{_n},$x->{_d}) if $y->{sign} eq '-'; 
986   $x->bnorm()->round(@r);
987   }
988
989 sub blog
990   {
991   # set up parameters
992   my ($self,$x,$y,@r) = (ref($_[0]),@_);
993
994   # objectify is costly, so avoid it
995   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
996     {
997     ($self,$x,$y,@r) = objectify(2,$class,@_);
998     }
999
1000   # blog(1,Y) => 0
1001   return $x->bzero() if $x->is_one() && $y->{sign} eq '+';
1002
1003   # $x <= 0 => NaN
1004   return $x->bnan() if $x->is_zero() || $x->{sign} ne '+' || $y->{sign} ne '+';
1005
1006   if ($x->is_int() && $y->is_int())
1007     {
1008     return $self->new($x->as_number()->blog($y->as_number(),@r));
1009     }
1010
1011   # do it with floats
1012   $x->_new_from_float( $x->_as_float()->blog(Math::BigFloat->new("$y"),@r) );
1013   }
1014
1015 sub _float_from_part
1016   {
1017   my $x = shift;
1018
1019   my $f = Math::BigFloat->bzero();
1020   $f->{_m} = $MBI->_copy($x);
1021   $f->{_e} = $MBI->_zero();
1022
1023   $f;
1024   }
1025
1026 sub _as_float
1027   {
1028   my $x = shift;
1029
1030   local $Math::BigFloat::upgrade = undef;
1031   local $Math::BigFloat::accuracy = undef;
1032   local $Math::BigFloat::precision = undef;
1033   # 22/7 => 3.142857143..
1034
1035   my $a = $x->accuracy() || 0;
1036   if ($a != 0 || !$MBI->_is_one($x->{_d}))
1037     {
1038     # n/d
1039     return Math::BigFloat->new($x->{sign} . $MBI->_str($x->{_n}))->bdiv( $MBI->_str($x->{_d}), $x->accuracy());
1040     }
1041   # just n
1042   Math::BigFloat->new($x->{sign} . $MBI->_str($x->{_n}));
1043   }
1044
1045 sub broot
1046   {
1047   # set up parameters
1048   my ($self,$x,$y,@r) = (ref($_[0]),@_);
1049   # objectify is costly, so avoid it
1050   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1051     {
1052     ($self,$x,$y,@r) = objectify(2,@_);
1053     }
1054
1055   if ($x->is_int() && $y->is_int())
1056     {
1057     return $self->new($x->as_number()->broot($y->as_number(),@r));
1058     }
1059
1060   # do it with floats
1061   $x->_new_from_float( $x->_as_float()->broot($y,@r) );
1062   }
1063
1064 sub bmodpow
1065   {
1066   # set up parameters
1067   my ($self,$x,$y,$m,@r) = (ref($_[0]),@_);
1068   # objectify is costly, so avoid it
1069   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1070     {
1071     ($self,$x,$y,$m,@r) = objectify(3,@_);
1072     }
1073
1074   # $x or $y or $m are NaN or +-inf => NaN
1075   return $x->bnan()
1076    if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/ ||
1077    $m->{sign} !~ /^[+-]$/;
1078
1079   if ($x->is_int() && $y->is_int() && $m->is_int())
1080     {
1081     return $self->new($x->as_number()->bmodpow($y->as_number(),$m,@r));
1082     }
1083
1084   warn ("bmodpow() not fully implemented");
1085   $x->bnan();
1086   }
1087
1088 sub bmodinv
1089   {
1090   # set up parameters
1091   my ($self,$x,$y,@r) = (ref($_[0]),@_);
1092   # objectify is costly, so avoid it
1093   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1094     {
1095     ($self,$x,$y,@r) = objectify(2,@_);
1096     }
1097
1098   # $x or $y are NaN or +-inf => NaN
1099   return $x->bnan() 
1100    if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/;
1101
1102   if ($x->is_int() && $y->is_int())
1103     {
1104     return $self->new($x->as_number()->bmodinv($y->as_number(),@r));
1105     }
1106
1107   warn ("bmodinv() not fully implemented");
1108   $x->bnan();
1109   }
1110
1111 sub bsqrt
1112   {
1113   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
1114
1115   return $x->bnan() if $x->{sign} !~ /^[+]/;    # NaN, -inf or < 0
1116   return $x if $x->{sign} eq '+inf';            # sqrt(inf) == inf
1117   return $x->round(@r) if $x->is_zero() || $x->is_one();
1118
1119   local $Math::BigFloat::upgrade = undef;
1120   local $Math::BigFloat::downgrade = undef;
1121   local $Math::BigFloat::precision = undef;
1122   local $Math::BigFloat::accuracy = undef;
1123   local $Math::BigInt::upgrade = undef;
1124   local $Math::BigInt::precision = undef;
1125   local $Math::BigInt::accuracy = undef;
1126
1127   $x->{_n} = _float_from_part( $x->{_n} )->bsqrt();
1128   $x->{_d} = _float_from_part( $x->{_d} )->bsqrt();
1129
1130   # XXX TODO: we probably can optimze this:
1131
1132   # if sqrt(D) was not integer
1133   if ($x->{_d}->{_es} ne '+')
1134     {
1135     $x->{_n}->blsft($x->{_d}->exponent()->babs(),10);   # 7.1/4.51 => 7.1/45.1
1136     $x->{_d} = $MBI->_copy( $x->{_d}->{_m} );           # 7.1/45.1 => 71/45.1
1137     }
1138   # if sqrt(N) was not integer
1139   if ($x->{_n}->{_es} ne '+')
1140     {
1141     $x->{_d}->blsft($x->{_n}->exponent()->babs(),10);   # 71/45.1 => 710/45.1
1142     $x->{_n} = $MBI->_copy( $x->{_n}->{_m} );           # 710/45.1 => 710/451
1143     }
1144
1145   # convert parts to $MBI again 
1146   $x->{_n} = $MBI->_lsft( $MBI->_copy( $x->{_n}->{_m} ), $x->{_n}->{_e}, 10)
1147     if ref($x->{_n}) ne $MBI && ref($x->{_n}) ne 'ARRAY';
1148   $x->{_d} = $MBI->_lsft( $MBI->_copy( $x->{_d}->{_m} ), $x->{_d}->{_e}, 10)
1149     if ref($x->{_d}) ne $MBI && ref($x->{_d}) ne 'ARRAY';
1150
1151   $x->bnorm()->round(@r);
1152   }
1153
1154 sub blsft
1155   {
1156   my ($self,$x,$y,$b,@r) = objectify(3,@_);
1157  
1158   $b = 2 unless defined $b;
1159   $b = $self->new($b) unless ref ($b);
1160   $x->bmul( $b->copy()->bpow($y), @r);
1161   $x;
1162   }
1163
1164 sub brsft
1165   {
1166   my ($self,$x,$y,$b,@r) = objectify(3,@_);
1167
1168   $b = 2 unless defined $b;
1169   $b = $self->new($b) unless ref ($b);
1170   $x->bdiv( $b->copy()->bpow($y), @r);
1171   $x;
1172   }
1173
1174 ##############################################################################
1175 # round
1176
1177 sub round
1178   {
1179   $_[0];
1180   }
1181
1182 sub bround
1183   {
1184   $_[0];
1185   }
1186
1187 sub bfround
1188   {
1189   $_[0];
1190   }
1191
1192 ##############################################################################
1193 # comparing
1194
1195 sub bcmp
1196   {
1197   # compare two signed numbers 
1198   
1199   # set up parameters
1200   my ($self,$x,$y) = (ref($_[0]),@_);
1201   # objectify is costly, so avoid it
1202   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1203     {
1204     ($self,$x,$y) = objectify(2,@_);
1205     }
1206
1207   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
1208     {
1209     # handle +-inf and NaN
1210     return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
1211     return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
1212     return +1 if $x->{sign} eq '+inf';
1213     return -1 if $x->{sign} eq '-inf';
1214     return -1 if $y->{sign} eq '+inf';
1215     return +1;
1216     }
1217   # check sign for speed first
1218   return 1 if $x->{sign} eq '+' && $y->{sign} eq '-';   # does also 0 <=> -y
1219   return -1 if $x->{sign} eq '-' && $y->{sign} eq '+';  # does also -x <=> 0
1220
1221   # shortcut
1222   my $xz = $MBI->_is_zero($x->{_n});
1223   my $yz = $MBI->_is_zero($y->{_n});
1224   return 0 if $xz && $yz;                               # 0 <=> 0
1225   return -1 if $xz && $y->{sign} eq '+';                # 0 <=> +y
1226   return 1 if $yz && $x->{sign} eq '+';                 # +x <=> 0
1227  
1228   my $t = $MBI->_mul( $MBI->_copy($x->{_n}), $y->{_d});
1229   my $u = $MBI->_mul( $MBI->_copy($y->{_n}), $x->{_d});
1230
1231   my $cmp = $MBI->_acmp($t,$u);                         # signs are equal
1232   $cmp = -$cmp if $x->{sign} eq '-';                    # both are '-' => reverse
1233   $cmp;
1234   }
1235
1236 sub bacmp
1237   {
1238   # compare two numbers (as unsigned)
1239  
1240   # set up parameters
1241   my ($self,$x,$y) = (ref($_[0]),@_);
1242   # objectify is costly, so avoid it
1243   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
1244     {
1245     ($self,$x,$y) = objectify(2,$class,@_);
1246     }
1247
1248   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
1249     {
1250     # handle +-inf and NaN
1251     return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
1252     return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
1253     return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/;
1254     return -1;
1255     }
1256
1257   my $t = $MBI->_mul( $MBI->_copy($x->{_n}), $y->{_d});
1258   my $u = $MBI->_mul( $MBI->_copy($y->{_n}), $x->{_d});
1259   $MBI->_acmp($t,$u);                                   # ignore signs
1260   }
1261
1262 ##############################################################################
1263 # output conversation
1264
1265 sub numify
1266   {
1267   # convert 17/8 => float (aka 2.125)
1268   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1269  
1270   return $x->bstr() if $x->{sign} !~ /^[+-]$/;  # inf, NaN, etc
1271
1272   # N/1 => N
1273   my $neg = ''; $neg = '-' if $x->{sign} eq '-';
1274   return $neg . $MBI->_num($x->{_n}) if $MBI->_is_one($x->{_d});
1275
1276   $x->_as_float()->numify() + 0.0;
1277   }
1278
1279 sub as_number
1280   {
1281   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1282
1283   return Math::BigInt->new($x) if $x->{sign} !~ /^[+-]$/;       # NaN, inf etc
1284  
1285   my $u = Math::BigInt->bzero();
1286   $u->{sign} = $x->{sign};
1287   $u->{value} = $MBI->_div( $MBI->_copy($x->{_n}), $x->{_d});   # 22/7 => 3
1288   $u;
1289   }
1290
1291 sub as_bin
1292   {
1293   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1294
1295   return $x unless $x->is_int();
1296
1297   my $s = $x->{sign}; $s = '' if $s eq '+';
1298   $s . $MBI->_as_bin($x->{_n});
1299   }
1300
1301 sub as_hex
1302   {
1303   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
1304
1305   return $x unless $x->is_int();
1306
1307   my $s = $x->{sign}; $s = '' if $s eq '+';
1308   $s . $MBI->_as_hex($x->{_n});
1309   }
1310
1311 ##############################################################################
1312 # import
1313
1314 sub import
1315   {
1316   my $self = shift;
1317   my $l = scalar @_;
1318   my $lib = ''; my @a;
1319
1320   for ( my $i = 0; $i < $l ; $i++)
1321     {
1322     if ( $_[$i] eq ':constant' )
1323       {
1324       # this rest causes overlord er load to step in
1325       overload::constant float => sub { $self->new(shift); };
1326       }
1327 #    elsif ($_[$i] eq 'upgrade')
1328 #      {
1329 #     # this causes upgrading
1330 #      $upgrade = $_[$i+1];             # or undef to disable
1331 #      $i++;
1332 #      }
1333     elsif ($_[$i] eq 'downgrade')
1334       {
1335       # this causes downgrading
1336       $downgrade = $_[$i+1];            # or undef to disable
1337       $i++;
1338       }
1339     elsif ($_[$i] eq 'lib')
1340       {
1341       $lib = $_[$i+1] || '';            # default Calc
1342       $i++;
1343       }
1344     elsif ($_[$i] eq 'with')
1345       {
1346       # this argument is no longer used
1347       #$MBI = $_[$i+1] || 'Math::BigInt::Calc'; # default Math::BigInt::Calc
1348       $i++;
1349       }
1350     else
1351       {
1352       push @a, $_[$i];
1353       }
1354     }
1355   require Math::BigInt;
1356
1357   # let use Math::BigInt lib => 'GMP'; use Math::BigRat; still have GMP
1358   if ($lib ne '')
1359     {
1360     my @c = split /\s*,\s*/, $lib;
1361     foreach (@c)
1362       {
1363       $_ =~ tr/a-zA-Z0-9://cd;                    # limit to sane characters
1364       }
1365     $lib = join(",", @c);
1366     }
1367   my @import = ('objectify');
1368   push @import, lib => $lib if $lib ne '';
1369
1370   # MBI already loaded, so feed it our lib arguments
1371   Math::BigInt->import( @import );
1372
1373   $MBI = Math::BigFloat->config()->{lib};
1374
1375   # register us with MBI to get notified of future lib changes
1376   Math::BigInt::_register_callback( $self, sub { $MBI = $_[0]; } );
1377   
1378   # any non :constant stuff is handled by our parent, Exporter (loaded
1379   # by Math::BigFloat, even if @_ is empty, to give it a chance
1380   $self->SUPER::import(@a);             # for subclasses
1381   $self->export_to_level(1,$self,@a);   # need this, too
1382   }
1383
1384 1;
1385
1386 __END__
1387
1388 =head1 NAME
1389
1390 Math::BigRat - Arbitrary big rational numbers
1391
1392 =head1 SYNOPSIS
1393
1394         use Math::BigRat;
1395
1396         my $x = Math::BigRat->new('3/7'); $x += '5/9';
1397
1398         print $x->bstr(),"\n";
1399         print $x ** 2,"\n";
1400
1401         my $y = Math::BigRat->new('inf');
1402         print "$y ", ($y->is_inf ? 'is' : 'is not') , " infinity\n";
1403
1404         my $z = Math::BigRat->new(144); $z->bsqrt();
1405
1406 =head1 DESCRIPTION
1407
1408 Math::BigRat complements Math::BigInt and Math::BigFloat by providing support
1409 for arbitrary big rational numbers.
1410
1411 =head2 MATH LIBRARY
1412
1413 Math with the numbers is done (by default) by a module called
1414 Math::BigInt::Calc. This is equivalent to saying:
1415
1416         use Math::BigRat lib => 'Calc';
1417
1418 You can change this by using:
1419
1420         use Math::BigRat lib => 'BitVect';
1421
1422 The following would first try to find Math::BigInt::Foo, then
1423 Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
1424
1425         use Math::BigRat lib => 'Foo,Math::BigInt::Bar';
1426
1427 Calc.pm uses as internal format an array of elements of some decimal base
1428 (usually 1e7, but this might be different for some systems) with the least
1429 significant digit first, while BitVect.pm uses a bit vector of base 2, most
1430 significant bit first. Other modules might use even different means of
1431 representing the numbers. See the respective module documentation for further
1432 details.
1433
1434 Currently the following replacement libraries exist, search for them at CPAN:
1435
1436         Math::BigInt::BitVect
1437         Math::BigInt::GMP
1438         Math::BigInt::Pari
1439         Math::BigInt::FastCalc
1440
1441 =head1 METHODS
1442
1443 Any methods not listed here are derived from Math::BigFloat (or
1444 Math::BigInt), so make sure you check these two modules for further
1445 information.
1446
1447 =head2 new()
1448
1449         $x = Math::BigRat->new('1/3');
1450
1451 Create a new Math::BigRat object. Input can come in various forms:
1452
1453         $x = Math::BigRat->new(123);                            # scalars
1454         $x = Math::BigRat->new('inf');                          # infinity
1455         $x = Math::BigRat->new('123.3');                        # float
1456         $x = Math::BigRat->new('1/3');                          # simple string
1457         $x = Math::BigRat->new('1 / 3');                        # spaced
1458         $x = Math::BigRat->new('1 / 0.1');                      # w/ floats
1459         $x = Math::BigRat->new(Math::BigInt->new(3));           # BigInt
1460         $x = Math::BigRat->new(Math::BigFloat->new('3.1'));     # BigFloat
1461         $x = Math::BigRat->new(Math::BigInt::Lite->new('2'));   # BigLite
1462
1463         # You can also give D and N as different objects:
1464         $x = Math::BigRat->new(
1465                 Math::BigInt->new(-123),
1466                 Math::BigInt->new(7),
1467                 );                      # => -123/7
1468
1469 =head2 numerator()
1470
1471         $n = $x->numerator();
1472
1473 Returns a copy of the numerator (the part above the line) as signed BigInt.
1474
1475 =head2 denominator()
1476         
1477         $d = $x->denominator();
1478
1479 Returns a copy of the denominator (the part under the line) as positive BigInt.
1480
1481 =head2 parts()
1482
1483         ($n,$d) = $x->parts();
1484
1485 Return a list consisting of (signed) numerator and (unsigned) denominator as
1486 BigInts.
1487
1488 =head2 as_int()
1489
1490         $x = Math::BigRat->new('13/7');
1491         print $x->as_int(),"\n";                # '1'
1492
1493 Returns a copy of the object as BigInt, truncated to an integer.
1494
1495 C<as_number()> is an alias for C<as_int()>.
1496
1497 =head2 as_hex()
1498
1499         $x = Math::BigRat->new('13');
1500         print $x->as_hex(),"\n";                # '0xd'
1501
1502 Returns the BigRat as hexadecimal string. Works only for integers. 
1503
1504 =head2 as_bin()
1505
1506         $x = Math::BigRat->new('13');
1507         print $x->as_bin(),"\n";                # '0x1101'
1508
1509 Returns the BigRat as binary string. Works only for integers. 
1510
1511 =head2 bfac()
1512
1513         $x->bfac();
1514
1515 Calculates the factorial of $x. For instance:
1516
1517         print Math::BigRat->new('3/1')->bfac(),"\n";    # 1*2*3
1518         print Math::BigRat->new('5/1')->bfac(),"\n";    # 1*2*3*4*5
1519
1520 Works currently only for integers.
1521
1522 =head2 blog()
1523
1524 Is not yet implemented.
1525
1526 =head2 bround()/round()/bfround()
1527
1528 Are not yet implemented.
1529
1530 =head2 bmod()
1531
1532         use Math::BigRat;
1533         my $x = Math::BigRat->new('7/4');
1534         my $y = Math::BigRat->new('4/3');
1535         print $x->bmod($y);
1536
1537 Set $x to the remainder of the division of $x by $y.
1538
1539 =head2 is_one()
1540
1541         print "$x is 1\n" if $x->is_one();
1542
1543 Return true if $x is exactly one, otherwise false.
1544
1545 =head2 is_zero()
1546
1547         print "$x is 0\n" if $x->is_zero();
1548
1549 Return true if $x is exactly zero, otherwise false.
1550
1551 =head2 is_pos()
1552
1553         print "$x is >= 0\n" if $x->is_positive();
1554
1555 Return true if $x is positive (greater than or equal to zero), otherwise
1556 false. Please note that '+inf' is also positive, while 'NaN' and '-inf' aren't.
1557
1558 C<is_positive()> is an alias for C<is_pos()>.
1559
1560 =head2 is_neg()
1561
1562         print "$x is < 0\n" if $x->is_negative();
1563
1564 Return true if $x is negative (smaller than zero), otherwise false. Please
1565 note that '-inf' is also negative, while 'NaN' and '+inf' aren't.
1566
1567 C<is_negative()> is an alias for C<is_neg()>.
1568
1569 =head2 is_int()
1570
1571         print "$x is an integer\n" if $x->is_int();
1572
1573 Return true if $x has a denominator of 1 (e.g. no fraction parts), otherwise
1574 false. Please note that '-inf', 'inf' and 'NaN' aren't integer.
1575
1576 =head2 is_odd()
1577
1578         print "$x is odd\n" if $x->is_odd();
1579
1580 Return true if $x is odd, otherwise false.
1581
1582 =head2 is_even()
1583
1584         print "$x is even\n" if $x->is_even();
1585
1586 Return true if $x is even, otherwise false.
1587
1588 =head2 bceil()
1589
1590         $x->bceil();
1591
1592 Set $x to the next bigger integer value (e.g. truncate the number to integer
1593 and then increment it by one).
1594
1595 =head2 bfloor()
1596         
1597         $x->bfloor();
1598
1599 Truncate $x to an integer value.
1600
1601 =head2 bsqrt()
1602         
1603         $x->bsqrt();
1604
1605 Calculate the square root of $x.
1606
1607 =head2 config
1608
1609         use Data::Dumper;
1610
1611         print Dumper ( Math::BigRat->config() );
1612         print Math::BigRat->config()->{lib},"\n";
1613
1614 Returns a hash containing the configuration, e.g. the version number, lib
1615 loaded etc. The following hash keys are currently filled in with the
1616 appropriate information.
1617
1618         key             RO/RW   Description
1619                                 Example
1620         ============================================================
1621         lib             RO      Name of the Math library
1622                                 Math::BigInt::Calc
1623         lib_version     RO      Version of 'lib'
1624                                 0.30
1625         class           RO      The class of config you just called
1626                                 Math::BigRat
1627         version         RO      version number of the class you used
1628                                 0.10
1629         upgrade         RW      To which class numbers are upgraded
1630                                 undef
1631         downgrade       RW      To which class numbers are downgraded
1632                                 undef
1633         precision       RW      Global precision
1634                                 undef
1635         accuracy        RW      Global accuracy
1636                                 undef
1637         round_mode      RW      Global round mode
1638                                 even
1639         div_scale       RW      Fallback accuracy for div
1640                                 40
1641         trap_nan        RW      Trap creation of NaN (undef = no)
1642                                 undef
1643         trap_inf        RW      Trap creation of +inf/-inf (undef = no)
1644                                 undef
1645
1646 By passing a reference to a hash you may set the configuration values. This
1647 works only for values that a marked with a C<RW> above, anything else is
1648 read-only.
1649
1650 =head1 BUGS
1651
1652 Some things are not yet implemented, or only implemented half-way:
1653
1654 =over 2
1655
1656 =item inf handling (partial)
1657
1658 =item NaN handling (partial)
1659
1660 =item rounding (not implemented except for bceil/bfloor)
1661
1662 =item $x ** $y where $y is not an integer
1663
1664 =item bmod(), blog(), bmodinv() and bmodpow() (partial)
1665
1666 =back
1667
1668 =head1 LICENSE
1669
1670 This program is free software; you may redistribute it and/or modify it under
1671 the same terms as Perl itself.
1672
1673 =head1 SEE ALSO
1674
1675 L<Math::BigFloat> and L<Math::Big> as well as L<Math::BigInt::BitVect>,
1676 L<Math::BigInt::Pari> and  L<Math::BigInt::GMP>.
1677
1678 See L<http://search.cpan.org/search?dist=bignum> for a way to use
1679 Math::BigRat.
1680
1681 The package at L<http://search.cpan.org/search?dist=Math%3A%3ABigRat>
1682 may contain more documentation and examples as well as testcases.
1683
1684 =head1 AUTHORS
1685
1686 (C) by Tels L<http://bloodgate.com/> 2001 - 2005.
1687
1688 =cut