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