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