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