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